1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
      <!DOCTYPE html>
<html>
  <head>
    <title>Single layer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Montserrat:600" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Add a layer</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Add one CARTO layer to your map.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
      <!DOCTYPE html>
<html>
  <head>
    <title>Single layer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Add a layer</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Add one CARTO layer to your map.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
      <!DOCTYPE html>
<html>
  <head>
    <title>Multilayer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Add more layers</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Add multiple CARTO layers to your map.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([40, 0], 5);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const spainCitiesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
          WHERE adm0name = \'Spain\'
      `);
      const spainCitiesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const spainCitiesLayer = new carto.layer.Layer(spainCitiesSource, spainCitiesStyle);

      const europeCountriesSource = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeCountriesStyle = new carto.style.CartoCSS(`
        #layer {
          polygon-fill: #826DBA;
          polygon-opacity: 0.8;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.8;
          }
        }
      `);
      const europeCountriesLayer = new carto.layer.Layer(europeCountriesSource, europeCountriesStyle);

      client.addLayers([europeCountriesLayer, spainCitiesLayer]);
      client.getLeafletLayer().addTo(map);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
      <!DOCTYPE html>
<html>
  <head>
    <title>Multilayer | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Add more layers</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Add multiple CARTO layers to your map.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 40, lng: 0},
        zoom: 5,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const spainCitiesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
          WHERE adm0name = \'Spain\'
      `);
      const spainCitiesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const spainCitiesLayer = new carto.layer.Layer(spainCitiesSource, spainCitiesStyle);

      const europeCountriesSource = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeCountriesStyle = new carto.style.CartoCSS(`
        #layer {
          polygon-fill: #826DBA;
          polygon-opacity: 0.8;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.8;
          }
        }
      `);
      const europeCountriesLayer = new carto.layer.Layer(europeCountriesSource, europeCountriesStyle);

      client.addLayers([europeCountriesLayer, spainCitiesLayer]);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
      <!DOCTYPE html>
<html>
  <head>
    <title>Change source | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the source</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the source of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select different sources</p>
          </section>

          <div id="controls">
            <ul>
              <li onclick="setAllCities()">
                <input type="radio" name="source" checked id="all">
                <label for="all">All cities</label>
              </li>
              <li onclick="setEuropeanCities()">
                <input type="radio" name="source" id="europe">
                <label for="europe">European cities</label>
              </li>
              <li onclick="setSpanishCities()">
                <input type="radio" name="source" id="spain">
                <label for="spain">Spanish cities</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      function setAllCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
      }

      function setEuropeanCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `);
      }

      function setSpanishCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name = \'Spain\'
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      <!DOCTYPE html>
<html>
  <head>
    <title>Change source | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the source</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the source of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select different sources</p>
          </section>

          <div id="controls">
            <ul>
              <li onclick="setAllCities()">
                <input type="radio" name="source" checked id="all">
                <label for="all">All cities</label>
              </li>
              <li onclick="setEuropeanCities()">
                <input type="radio" name="source" id="europe">
                <label for="europe">European cities</label>
              </li>
              <li onclick="setSpanishCities()">
                <input type="radio" name="source" id="spain">
                <label for="spain">Spanish cities</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      function setAllCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
      }

      function setEuropeanCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `);
      }

      function setSpanishCities() {
        source.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name = \'Spain\'
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
      <!DOCTYPE html>
<html>
  <head>
    <title>Change style | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the style</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the style of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select different styles</p>
          </section>
          <div id="controls">
            <ul>
              <li onclick="setRed()">
                <input type="radio" name="style" checked id="red">
                <label for="red">Size 7px - Red</label>
              </li>
              <li onclick="setGreen()">
                <input type="radio" name="style" id="green">
                <label for="green">Size 9px - Green</label>
              </li>
              <li onclick="setBlue()">
                <input type="radio" name="style" id="blue">
                <label for="blue">Size 11px - Blue</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>
    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      function setRed() {
        style.setContent(`
          #layer {
            marker-width: 7;
            marker-fill: #EE4D5A;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setGreen() {
        style.setContent(`
          #layer {
            marker-width: 9;
            marker-fill: #9BC63B;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setBlue() {
        style.setContent(`
          #layer {
            marker-width: 11;
            marker-fill: #1785FB;
            marker-line-color: #FFFFFF;
          }
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
      <!DOCTYPE html>
<html>
  <head>
    <title>Change style | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the style</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the style of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select different styles</p>
          </section>
          <div id="controls">
            <ul>
              <li onclick="setRed()">
                <input type="radio" name="style" checked id="red">
                <label for="red">Size 7px - Red</label>
              </li>
              <li onclick="setGreen()">
                <input type="radio" name="style" id="green">
                <label for="green">Size 9px - Green</label>
              </li>
              <li onclick="setBlue()">
                <input type="radio" name="style" id="blue">
                <label for="blue">Size 11px - Blue</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>
    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      function setRed() {
        style.setContent(`
          #layer {
            marker-width: 7;
            marker-fill: #EE4D5A;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setGreen() {
        style.setContent(`
          #layer {
            marker-width: 7;
            marker-fill: #9BC63B;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setBlue() {
        style.setContent(`
          #layer {
            marker-width: 9;
            marker-fill: #1785FB;
            marker-line-color: #FFFFFF;
          }
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
      <!DOCTYPE html>
<html>
  <head>
    <title>Change order | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Move the layers</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the order of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click to move countries layer to&nbsp;front/back</p>
          </section>
          <div id="controls">
            <ul>
              <li onclick="bringToBack()">
                <input type="radio" name="style" id="bringToBack">
                <label for="bringToBack">Bring to back</label>
              </li>
              <li onclick="bringToFront()">
                <input type="radio" name="style" checked id="bringToFront">
                <label for="bringToFront">Bring to front</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>
    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const spainCitiesSource = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const spainCitiesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const spainCitiesLayer = new carto.layer.Layer(spainCitiesSource, spainCitiesStyle);

      const europeCountriesSource = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeCountriesStyle = new carto.style.CartoCSS(`
        #layer {
          polygon-fill: #826DBA;
          polygon-opacity: 0.8;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.8;
          }
        }
      `);
      const europeCountriesLayer = new carto.layer.Layer(europeCountriesSource, europeCountriesStyle);

      client.addLayers([europeCountriesLayer, spainCitiesLayer]);
      client.getLeafletLayer().addTo(map);

      function bringToBack() {
        spainCitiesLayer.bringToBack();
        // or
        // spainCitiesLayer.setOrder(0);
        // or
        // client.moveLayer(spainCitiesLayer, 0);
      }

      function bringToFront() {
        spainCitiesLayer.bringToFront();
        // or
        // spainCitiesLayer.setOrder(1);
        // // or
        // client.moveLayer(spainCitiesLayer, 1);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
      <!DOCTYPE html>
<html>
  <head>
    <title>Change order | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Move the layers</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Update the order of your layers.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click to move countries layer to&nbsp;front/back</p>
          </section>
          <div id="controls">
            <ul>
              <li onclick="bringToBack()">
                <input type="radio" name="style" id="bringToBack">
                <label for="bringToBack">Bring to back</label>
              </li>
              <li onclick="bringToFront()">
                <input type="radio" name="style" checked id="bringToFront">
                <label for="bringToFront">Bring to front</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>
    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const spainCitiesSource = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const spainCitiesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const spainCitiesLayer = new carto.layer.Layer(spainCitiesSource, spainCitiesStyle);

      const europeCountriesSource = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeCountriesStyle = new carto.style.CartoCSS(`
        #layer {
          polygon-fill: #826DBA;
          polygon-opacity: 0.8;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.8;
          }
        }
      `);
      const europeCountriesLayer = new carto.layer.Layer(europeCountriesSource, europeCountriesStyle);

      client.addLayers([europeCountriesLayer, spainCitiesLayer]);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      function bringToBack() {
        spainCitiesLayer.bringToBack();
        // or
        // spainCitiesLayer.setOrder(0);
        // or
        // client.moveLayer(spainCitiesLayer, 0);
      }

      function bringToFront() {
        spainCitiesLayer.bringToFront();
        // or
        // spainCitiesLayer.setOrder(1);
        // // or
        // client.moveLayer(spainCitiesLayer, 1);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
      <!DOCTYPE html>
<html>
  <head>
    <title>Layer with aggregation | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Server tile aggregation</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">This map has smart backend aggregation applied. See source code for details.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: ramp([population], (#ecda9a, #f7945d, #ee4d5a), jenks());
          marker-line-color: #FFFFFF;
        }
      `);

      // Aggregation option
      const aggregation = new carto.layer.Aggregation({
        threshold: 1,
        resolution: 4,
        placement: carto.layer.Aggregation.placement.SAMPLE,
        columns: {
          population: {
            aggregateFunction: carto.layer.Aggregation.operation.SUM,
            aggregatedColumn: 'pop_max'
          }
        }
      });

      const layer = new carto.layer.Layer(source, style, { aggregation });

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
      <!DOCTYPE html>
<html>
  <head>
    <title>Layer with aggregation | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Server tile aggregation</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">This map has smart backend aggregation applied. See source code for details.</p>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>
    
    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: ramp([population], (#ecda9a, #f7945d, #ee4d5a), jenks());
          marker-line-color: #FFFFFF;
        }
      `);

      // Aggregation option
      const aggregation = new carto.layer.Aggregation({
        threshold: 1,
        resolution: 4,
        placement: carto.layer.Aggregation.placement.SAMPLE,
        columns: {
          population: {
            aggregateFunction: carto.layer.Aggregation.operation.SUM,
            aggregatedColumn: 'pop_max'
          }
        }
      });

      const layer = new carto.layer.Layer(source, style, { aggregation });

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
      <!DOCTYPE html>
<html>
  <head>
    <title>Feature click | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Detect feature click</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Interact with the features on the click event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click on the markers</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureClickColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      layer.on('featureClicked', featureEvent => {
        let content = '';
        content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        content += `<p class="open-sans">${featureEvent.data.pop_max} <small>max inhabitants</small></p>`;
        document.getElementById('info').innerHTML = content;
      });
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
      <!DOCTYPE html>
<html>
  <head>
    <title>Feature click | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Detect feature click</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Interact with the features on the click event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click on the markers</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureClickColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      layer.on('featureClicked', featureEvent => {
        let content = '';
        content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        content += `<p class="open-sans">${featureEvent.data.pop_max} <small>max inhabitants</small></p>`;
        document.getElementById('info').innerHTML = content;
      });
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
      <!DOCTYPE html>
<html>
  <head>
    <title>Feature over/out | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Detect feature over/out</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Interact with the features on the over/out event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Move the mouse over the markers</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 10;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureOverColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      layer.on('featureOver', featureEvent => {
        let content = '';
        content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        content += `<p class="open-sans">${featureEvent.data.pop_max} <small>max inhabitants</small></p>`;
        content += `</div>`;
        document.getElementById('info').innerHTML = content;
        featureVisible = true;
      });

      layer.on('featureOut', featureEvent => {
        hideInfo();
      });

      function debounce(func, wait, immediate) {
        var timeout;
        return function() {
          var context = this, args = arguments;
          var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
          };
          var callNow = immediate && !timeout;
          clearTimeout(timeout);
          timeout = setTimeout(later, wait);
          if (callNow) func.apply(context, args);
        };
      };

      const hideInfo = debounce(function () {
        document.getElementById('info').innerHTML = '';
      }, 500);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
      <!DOCTYPE html>
<html>
  <head>
    <title>Feature over/out | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Detect feature over/out</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Interact with the features on the over/out event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Move the mouse over the markers</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 10;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureOverColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      layer.on('featureOver', featureEvent => {
        let content = '';
        content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        content += `<p class="open-sans">${featureEvent.data.pop_max} <small>max inhabitants</small></p>`;
        content += `</div>`;
        document.getElementById('info').innerHTML = content;
        featureVisible = true;
      });

      layer.on('featureOut', featureEvent => {
        hideInfo();
      });

      function debounce(func, wait, immediate) {
        var timeout;
        return function() {
          var context = this, args = arguments;
          var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
          };
          var callNow = immediate && !timeout;
          clearTimeout(timeout);
          timeout = setTimeout(later, wait);
          if (callNow) func.apply(context, args);
        };
      };

      const hideInfo = debounce(function () {
        document.getElementById('info').innerHTML = '';
      }, 500);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
      <!DOCTYPE html>
<html>
  <head>
    <title>Change feature columns | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the feature columns</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Change the columns returned in the feature event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click on the markers</p>
          </section>
          <div id="controls">
            <ul class="actions">
              <li>
                <input id="red" type="radio" name="style" onclick="setMoreData()">
                <label for="red">More data</label>
              </li>
              <li>
                <input id="green" type="radio" name="style" onclick="setLessData()" checked>
                <label for="green">Less data</label>
              </li>
            </ul>
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureClickColumns: ['name']
      });

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      layer.on('featureClicked', featureEvent => {
        let content = '';
        if (featureEvent.data.name) {
          content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        }
        if (featureEvent.data.pop_max) {
          content += `<p class="open-sans"><span>${featureEvent.data.pop_max}</span> max inhabitants</p>`;
        }
        if (featureEvent.data.pop_min) {
          content += `<p class="open-sans"><span>${featureEvent.data.pop_min}</span> min inhabitants</p>`;
        }
        document.getElementById('info').innerHTML = content;
      });

      function setMoreData() {
        layer.setFeatureClickColumns(['name', 'pop_max', 'pop_min']);
      }

      function setLessData() {
        layer.setFeatureClickColumns(['name']);
        document.getElementById('content').innerHTML = '';
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      <!DOCTYPE html>
<html>
  <head>
    <title>Change feature columns | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map">
    </div>
    <!-- Description -->
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Change the feature columns</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Change the columns returned in the feature event.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Click on the markers</p>
          </section>
          <div id="controls">
            <ul class="actions">
              <li>
                <input id="red" type="radio" name="style" onclick="setMoreData()">
                <label for="red">More data</label>
              </li>
              <li>
                <input id="green" type="radio" name="style" onclick="setLessData()" checked>
                <label for="green">Less data</label>
              </li>
            </ul>
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureClickColumns: ['name']
      });

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      layer.on('featureClicked', featureEvent => {
        let content = '';
        if (featureEvent.data.name) {
          content += `<h3>${featureEvent.data.name.toUpperCase()}</h3>`;
        }
        if (featureEvent.data.pop_max) {
          content += `<p class="open-sans">${featureEvent.data.pop_max} <span>max inhabitants</span></p>`;
        }
        if (featureEvent.data.pop_min) {
          content += `<p class="open-sans">${featureEvent.data.pop_min} <span>min inhabitants</span></p>`;
        }
        document.getElementById('info').innerHTML = content;
      });

      function setMoreData() {
        layer.setFeatureClickColumns(['name', 'pop_max', 'pop_min']);
        document.getElementById('content').innerHTML = '';
      }

      function setLessData() {
        layer.setFeatureClickColumns(['name']);
        document.getElementById('content').innerHTML = '';
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
      <!DOCTYPE html>
<html>
  <head>
    <title>Formula widget | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body class="bg-gray">
    <div class="dataview">
      <ul>
        <li>
          <h2 class="h2">Column</h2>
          <input id="column" type="text" value="pop_max" class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class="h2">Operation</h2>
          <select id="operation" class="select open-sans">
            <option value="count">COUNT</option>
            <option value="sum">SUM</option>
            <option value="avg">AVG</option>
            <option value="max">MAX</option>
            <option value="min">MIN</option>
          </select>
        </li>
      </ul>
      <button onclick="applyDataviewChanges()" class="button open-sans">Apply</button>
      <pre class="code" id="data"></pre>
    </div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Formula widget</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create a widget with the formula dataview.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Change column or operation on the form.</p>
            <p class="open-sans">Example columns: rank_max, pop_max, pop_min.</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const formulaDataview = new carto.dataview.Formula(source, 'pop_max', {
        operation: carto.operation.COUNT
      });

      formulaDataview.on('dataChanged', data => {
        document.getElementById('data').innerHTML = JSON.stringify(data, null, 4);
      });

      formulaDataview.on('error', error => {
        alert(error.message);
      });

      client.addDataview(formulaDataview);

      function applyDataviewChanges() {
        const column = document.getElementById('column').value;
        const operation = document.getElementById('operation').value;
        formulaDataview.setColumn(column);
        formulaDataview.setOperation(operation);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
      <!DOCTYPE html>
<html>
  <head>
    <title>Category widget | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body class="bg-gray">
    <div class="dataview">
      <ul>
        <li>
          <h2 class="h2">Column</h2>
          <input id="column" type="text" value="adm0name" class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class="h2">Limit</h2>
          <input id="limit" type="number" value="10" class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class="h2">Operation</h2>
          <select id="operation" class="select open-sans">
            <option value="sum">SUM</option>
            <option value="count">COUNT</option>
            <option value="avg">AVG</option>
            <option value="max">MAX</option>
            <option value="min">MIN</option>
          </select>
        </li>
        <li>
          <h2 class="h2">Operation column</h2>
          <input id="operationColumn" type="text" value="pop_max" class="input_text open-sans"></input>
        </li>
      </ul>
      <button onclick="applyDataviewChanges()" class="button open-sans">Apply</button>
      <pre class="code" id="data"></pre>
    </div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Category widget</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create a widget with the category dataview.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Change form values.</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const categoryDataview = new carto.dataview.Category(source, 'adm0name', {
        limit: 10,
        operation: carto.operation.SUM,
        operationColumn: 'pop_max'
      });

      categoryDataview.on('dataChanged', data => {
        document.getElementById('data').innerHTML = JSON.stringify(data, null, 4);
      });

      categoryDataview.on('error', error => {
        alert(error.message);
      });

      client.addDataview(categoryDataview);

      function applyDataviewChanges() {
        const column = document.getElementById('column').value;
        const limit = document.getElementById('limit').value;
        const operation = document.getElementById('operation').value;
        const operationColumn = document.getElementById('operationColumn').value;
        categoryDataview.setColumn(column);
        categoryDataview.setLimit(parseInt(limit));
        categoryDataview.setOperation(operation);
        categoryDataview.setOperationColumn(operationColumn);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
      <!DOCTYPE html>
<html>
  <head>
    <title>Histogram widget | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body class="bg-gray">
    <div class="dataview">
      <ul>
        <li>
          <h2 class="h2">Column</h2>
          <input id="column" type="text" value="price" class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class="h2">Bins</h2>
          <input id="bins" type="number" value="5" class="input_text open-sans"></input>
        </li>
      </ul>
      <button onclick="applyDataviewChanges()" class="button open-sans">Apply</button>
      <pre class="code" id="data"></pre>
    </div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Histogram widget</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create a widget with the histogram dataview.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Change column or bins on the form.</p>
            <p class="open-sans">Example columns: price, minimum_nights, availability_365.</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.SQL(`
        SELECT * FROM airbnb_listings WHERE price < 150
      `);
      const histogramDataview = new carto.dataview.Histogram(source, 'price', {
        bins: 5
      });

      histogramDataview.on('dataChanged', data => {
        document.getElementById('data').innerHTML = JSON.stringify(data, null, 4);
      });

      histogramDataview.on('error', error => {
        alert(error.message);
      });

      client.addDataview(histogramDataview);

      function applyDataviewChanges() {
        const column = document.getElementById('column').value;
        const bins = document.getElementById('bins').value;
        histogramDataview.setColumn(column);
        histogramDataview.setBins(parseInt(bins));
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
      <!DOCTYPE html>
<html>
  <head>
    <title>Time Series widget | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body class="bg-gray">
    <div class="dataview">
      <ul>
        <li>
          <h2 class="h2">Column</h2>
          <input id="column" type="text" value="date"  class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class="h2">Aggregation</h2>
          <select id="aggregation"  class="select">
            <option value="auto">Auto</option>
            <option value="year">Year</option>
            <option value="quarter">Quarter</option>
            <option value="month">Month</option>
            <option value="week">Week</option>
            <option value="day">Day</option>
            <option value="hour">Hour</option>
            <option value="minute">Minute</option>
          </select>
        </li>
        <li>
          <h2 class="h2">Offset</h2>
          <input id="offset" type="number" value="1"  class="input_text open-sans"></input>
        </li>
      </ul>
      <button  class="button open-sans" onclick="applyDataviewChanges()">Apply</button>
      <pre class="code" id="data"></pre>
    </div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Time Series widget</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create a widget with the time series dataview.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select different aggregations on the form.</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        railroad_data
      `);
      const timeseriesDataview = new carto.dataview.TimeSeries(source, 'date', {
        aggregation: carto.dataview.timeAggregation.AUTO,
        offset: 1
      });

      timeseriesDataview.on('dataChanged', data => {
        document.getElementById('data').innerHTML = JSON.stringify(data, null, 4);
      });

      timeseriesDataview.on('error', error => {
        alert(error.message);
      });

      client.addDataview(timeseriesDataview);

      function applyDataviewChanges() {
        const column = document.getElementById('column').value;
        const aggregation = document.getElementById('aggregation').value;
        const offset = document.getElementById('offset').value;
        timeseriesDataview.setColumn(column);
        timeseriesDataview.setAggregation(aggregation);
        timeseriesDataview.setOffset(parseInt(offset));
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
      <!DOCTYPE html>
<html>
  <head>
    <title>Bounding Box filter | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Bounding Box filter</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Apply a map bounding box filter to dataviews.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Move the map</p>
          </section>
          <div class="widget category"></div>
          <div class="widget formula"></div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureOverColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      const categoryDataview = new carto.dataview.Category(source, 'adm0name', {
        limit: 4,
        operation: carto.operation.SUM,
        operationColumn: 'pop_max'
      });
      categoryDataview.on('dataChanged', renderWidgetCategory);

      client.addDataview(categoryDataview);

      const formulaDataview = new carto.dataview.Formula(source, 'pop_max', {
        operation: carto.operation.COUNT,
      });
      formulaDataview.on('dataChanged', renderWidgetFormula);

      client.addDataview(formulaDataview);

      const bboxFilter = new carto.filter.BoundingBoxLeaflet(map);

      categoryDataview.addFilter(bboxFilter);
      formulaDataview.addFilter(bboxFilter);

      function renderWidgetCategory(data) {
        let content = '';
        content += `<ul>`
        for (let category of data.categories) {
          content += `<li>`
          content += `<p class="category">${category.name}</p>
          <p class="open-sans">${parseInt(category.value)} <small>inhabitants</small></p>`;
          content += `<li>`
        }
        content += `</ul>`
        document.querySelector('.widget.category').innerHTML = content;
      }

      function renderWidgetFormula(data) {
        const content = `<h2 class="h2">${data.result} <small>cities</small></h2>`;
        document.querySelector('.widget.formula').innerHTML = content;
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      <!DOCTYPE html>
<html>
  <head>
    <title>Bounding Box filter | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Bounding Box filter</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Apply a map bounding box filter to dataviews.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Move the map</p>
          </section>
          <div class="widget category"></div>
          <div class="widget formula"></div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        zoomControl: true,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const style = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const layer = new carto.layer.Layer(source, style, {
        featureOverColumns: ['name', 'pop_max']
      });

      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      const categoryDataview = new carto.dataview.Category(source, 'adm0name', {
        limit: 4,
        operation: carto.operation.SUM,
        operationColumn: 'pop_max'
      });
      categoryDataview.on('dataChanged', renderWidgetCategory);

      client.addDataview(categoryDataview);

      const formulaDataview = new carto.dataview.Formula(source, 'pop_max', {
        operation: carto.operation.COUNT,
      });
      formulaDataview.on('dataChanged', renderWidgetFormula);

      client.addDataview(formulaDataview);

      const bboxFilter = new carto.filter.BoundingBoxGoogleMaps(map);

      categoryDataview.addFilter(bboxFilter);
      formulaDataview.addFilter(bboxFilter);

      function renderWidgetCategory(data) {
        let content = '';
        content += `<ul>`
        for (let category of data.categories) {
          content += `<li>`
          content += `<h3>${category.name}</h3>
          <p class="open-sans">${parseInt(category.value)} <small>inhabitants</small></p>`;
          content += `<li>`
        }
        content += `</ul>`
        document.querySelector('.widget.category').innerHTML = content;
      }

      function renderWidgetFormula(data) {
        const content = `<h2 class="h2">${data.result} <small>cities</small></h2>`;
        document.querySelector('.widget.formula').innerHTML = content;
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
      <!DOCTYPE html>
<html>
  <head>
    <title>Widgets error handling | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body class="bg-gray">
    <div class="dataview">
      <ul>
        <li>
          <h2 class"h2">Column</h2>
          <input id="column" type="text" value="pop_max" class="input_text open-sans"></input>
        </li>
        <li>
          <h2 class"h2">Operation</h2>
          <select id="operation" class="select">
            <option value="count">COUNT</option>
            <option value="sum">SUM</option>
            <option value="avg">AVG</option>
            <option value="max">MAX</option>
            <option value="min">MIN</option>
          </select>
        </li>
      </ul>
      <button onclick="applyDataviewChanges()" class="button open-sans text-blue"><b>Apply</b></button>
      <button onclick="provokeError()" class="button button-error open-sans text-red"><b>Provoke error</b></button>
      <pre class="code" id="data"></pre>
    </div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Status and error handling</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Manage the status and erros in dataviews.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Apply submits the form. Provoke error sends a wrong column.</p>
          </section>
          <div id="controls">
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const source = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const formulaDataview = new carto.dataview.Formula(source, 'pop_max', {
        operation: carto.operation.COUNT
      });

      let data;

      formulaDataview.on('dataChanged', newData => {
        data = JSON.stringify(newData, null, 4);
        setText(data);
      });

      formulaDataview.on('error', error => {
        setText(error.message);
      });

      formulaDataview.on('statusChanged', status => {
        if (status === carto.dataview.status.LOADING) {
          setText('Loading...');
        } else if (status === carto.dataview.status.LOADED && data) {
          setText(data);
        }
      });

      client.addDataview(formulaDataview);

      function applyDataviewChanges() {
        const column = document.getElementById('column').value;
        const operation = document.getElementById('operation').value;
        formulaDataview.setColumn(column);
        formulaDataview.setOperation(operation);
      }

      function provokeError () {
        formulaDataview.setColumn('wrongcolumn');
      }

      function setText (text) {
        document.getElementById('data').innerHTML = text;
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
      <!DOCTYPE html>
<html>
  <head>
    <title>Guide | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Guide</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Full reference guide example.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select a country</p>
          </section>
          <div id="controls">
            <h2 class="h2">European countries</h2>
            <select class="js-countries">
              <option value="">All</option>
            </select>
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">Average population</h2>
        <p class="result open-sans"><span class="js-average-population">xxx</span> <small>inhabitants</small></p>
      </div>
    </aside>

    <script>
      // 1. Setting up the Leaflet Map
      // 1.1 Creating the Leaflet Map
      const map = L.map('map').setView([50, 15], 4);
      map.scrollWheelZoom.disable();

      // 1.2 Adding basemap and labels layers
      // Adding Voyager Basemap
      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      // Adding Voyager Labels
      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}.png', {
        maxZoom: 18,
        zIndex: 10
      }).addTo(map);

      // 2 Defining a carto.Client
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      // 3. Displaying countries and cities on the map
      // 3.1 Defining the layers
      // European Countries layer
      const europeanCountriesDataset = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeanCountriesStyle = new carto.style.CartoCSS(`
        #layer {
        polygon-fill: #826DBA;
          polygon-opacity: 0.5;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.5;
          }
        }
      `);
      const europeanCountries = new carto.layer.Layer(europeanCountriesDataset, europeanCountriesStyle);

      // Europe cities layer
      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
          WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-fill-opacity: 0.9;
          marker-line-width: 0.5;
          marker-line-color: #FFFFFF;
          marker-line-opacity: 1;
          marker-type: ellipse;
          marker-allow-overlap: false;
        }
      `);
      const populatedPlaces = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
        featureOverColumns: ['name']
      });

      // 3.2 Adding the layers to the client
      client.addLayers([europeanCountries, populatedPlaces]);

      // 3.3. Adding the layers to the map
      client.getLeafletLayer().addTo(map);

      // 4. Setting up tooltips
      // 4.1 Showing the tooltip when user mouses over a city
      const popup = L.popup({ closeButton: false });
      populatedPlaces.on('featureOver', featureEvent => {
        popup.setLatLng(featureEvent.latLng);
        if (!popup.isOpen()) {
          popup.setContent(featureEvent.data.name);
          popup.openOn(map);
        }
      });

      // 4.2 Hiding the tooltip
      populatedPlaces.on('featureOut', featureEvent => {
        popup.removeFrom(map);
      });

      // 5 Creating a formula widget
      // 5.1 Defining a formula dataview
      const averagePopulation = new carto.dataview.Formula(populatedPlacesSource, 'pop_max', {
        operation: carto.operation.AVG
      });

      // 5.2 Listening to data changes on the dataview
      averagePopulation.on('dataChanged', data => {
        refreshAveragePopulationWidget(data.result);
      });

      function refreshAveragePopulationWidget(avgPopulation) {
        const widgetDom = document.querySelector('.box.widget');
        const averagePopulationDom = widgetDom.querySelector('.js-average-population');
        averagePopulationDom.innerText = Math.floor(avgPopulation);
      }

      // 5.3 Adding the dataview to the client
      client.addDataview(averagePopulation);

      // 6 Creating a country selector widget
      // 6.1 Defining a category dataview
      const countriesDataview = new carto.dataview.Category(europeanCountriesDataset, 'admin', {
        limit: 100
      });

      // 6.2 Listening to data changes on the dataview
      countriesDataview.on('dataChanged', data => {
        const countryNames = data.categories.map(category => category.name).sort();
        refreshCountriesWidget(countryNames);
      });

      function refreshCountriesWidget(adminNames) {
        const asideElement = document.querySelector('aside.toolbox');
        const countriesDom = asideElement.querySelector('.js-countries');
        countriesDom.onchange = event => {
          const admin = event.target.value;
          highlightCountry(admin);
          filterPopulatedPlacesByCountry(admin);
        };

        // Fill in the list of countries
        adminNames.forEach(admin => {
          const option = document.createElement('option');
          option.innerHTML = admin;
          option.value = admin;
          countriesDom.appendChild(option);
        });
      }

      function highlightCountry(admin) {
        let cartoCSS = `
          #layer {
            polygon-fill: #826DBA;
            polygon-opacity: 0.5;
            ::outline {
              line-width: 1;
              line-color: #FFFFFF;
              line-opacity: 0.5;
            }
          }
        `;
        if (admin) {
          cartoCSS = `
            ${cartoCSS}
            #layer[admin!='${admin}'] {
              polygon-fill: #e5e5e5;
            }
          `;
        }
        europeanCountriesStyle.setContent(cartoCSS);
      }

      function filterPopulatedPlacesByCountry(admin) {
        let query = `
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `;
        if (admin) {
          query = `
            SELECT *
              FROM ne_10m_populated_places_simple
              WHERE adm0name='${admin}'
          `;
        }
        populatedPlacesSource.setQuery(query);
      }

      // 6.3 Adding the dataview to the client
      client.addDataview(countriesDataview);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
      <!DOCTYPE html>
<html>
  <head>
    <title>Guide | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Guide</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Full reference guide example.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select a country</p>
          </section>
          <div id="controls">
            <h2 class="h2">European countries</h2>
            <select class="js-countries">
              <option value="">All</option>
            </select>
            <div id="info"></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">Average population</h2>
        <p class="result open-sans"><span class="js-average-population">xxx</span> <small>inhabitants</small></p>
      </div>
    </aside>

    <script>
      // 1. Setting up a Google Maps Map
      // 1.1 Creating the Google Maps Map
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 50, lng: 15},
        zoom: 4,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });

      // 1.2 Hide countries borders
      map.set('styles', [{
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      // 2 Defining a carto.Client
      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      // 3. Displaying countries and cities on the map
      // 3.1 Defining the layers
      // European Countries layer
      const europeanCountriesDataset = new carto.source.Dataset(`
        ne_adm0_europe
      `);
      const europeanCountriesStyle = new carto.style.CartoCSS(`
        #layer {
        polygon-fill: #826DBA;
          polygon-opacity: 0.5;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.5;
          }
        }
      `);
      const europeanCountries = new carto.layer.Layer(europeanCountriesDataset, europeanCountriesStyle);

      // Europe cities layer
      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
          WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-fill-opacity: 0.9;
          marker-line-width: 0.5;
          marker-line-color: #FFFFFF;
          marker-line-opacity: 1;
          marker-type: ellipse;
          marker-allow-overlap: false;
        }
      `);
      const populatedPlaces = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
        featureOverColumns: ['name']
      });

      // 3.2 Adding the layers to the client
      client.addLayers([europeanCountries, populatedPlaces]);

      // 3.3. Adding the layers to the map
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      // 4. Setting up tooltips
      // 4.1 Showing the tooltip when user mouses over a city
      const infowindow = new google.maps.InfoWindow();
      populatedPlaces.on('featureOver', featureEvent => {
        infowindow.setPosition(featureEvent.latLng);
        if (!infowindow.map) {
          infowindow.setContent(featureEvent.data.name);
          infowindow.open(map);
        }
      });

      // 4.2 Hiding the tooltip
      populatedPlaces.on('featureOut', featureEvent => {
        infowindow.close();
      });

      // 5 Creating a formula widget
      // 5.1 Defining a formula dataview
      const averagePopulation = new carto.dataview.Formula(populatedPlacesSource, 'pop_max', {
        operation: carto.operation.AVG
      });

      // 5.2 Listening to data changes on the dataview
      averagePopulation.on('dataChanged', data => {
        refreshAveragePopulationWidget(data.result);
      });

      function refreshAveragePopulationWidget(avgPopulation) {
        const widgetDom = document.querySelector('.box.widget');
        const averagePopulationDom = widgetDom.querySelector('.js-average-population');
        averagePopulationDom.innerText = Math.floor(avgPopulation);
      }

      // 5.3 Adding the dataview to the client
      client.addDataview(averagePopulation);

      // 6 Creating a country selector widget
      // 6.1 Defining a category dataview
      const countriesDataview = new carto.dataview.Category(europeanCountriesDataset, 'admin', {
        limit: 100
      });

      // 6.2 Listening to data changes on the dataview
      countriesDataview.on('dataChanged', data => {
        const countryNames = data.categories.map(category => category.name).sort();
        refreshCountriesWidget(countryNames);
      });

      function refreshCountriesWidget(adminNames) {
        const asideElement = document.querySelector('aside.toolbox');
        const countriesDom = asideElement.querySelector('.js-countries');
        countriesDom.onchange = event => {
          const admin = event.target.value;
          highlightCountry(admin);
          filterPopulatedPlacesByCountry(admin);
        };

        // Fill in the list of countries
        adminNames.forEach(admin => {
          const option = document.createElement('option');
          option.innerHTML = admin;
          option.value = admin;
          countriesDom.appendChild(option);
        });
      }

      function highlightCountry(admin) {
        let cartoCSS = `
          #layer {
            polygon-fill: #826DBA;
            polygon-opacity: 0.5;
            ::outline {
              line-color: #FFFFFF;
              line-width: 1;
              line-opacity: 0.5;
            }
          }
        `;
        if (admin) {
          cartoCSS = `
            ${cartoCSS}
            #layer[admin!='${admin}'] {
              polygon-fill: #e5e5e5;
            }
          `;
        }
        europeanCountriesStyle.setContent(cartoCSS);
      }

      function filterPopulatedPlacesByCountry(admin) {
        let query = `
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `;
        if (admin) {
          query = `
            SELECT *
              FROM ne_10m_populated_places_simple
              WHERE adm0name='${admin}'
          `;
        }
        populatedPlacesSource.setQuery(query);
      }

      // 6.3 Adding the dataview to the client
      client.addDataview(countriesDataview);
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
      <!DOCTYPE html>
<html>
  <head>
    <title>Pop-ups | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Pop-Ups</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create pop-up information windows and interact with your map.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select your preferred kind of pop-ups</p>
          </section>

          <div id="controls">
            <ul class="actions">
              <li onclick="setPopupsClick()">
                <input type="radio" name="style" value="01" id="popup">
                <label for="popup">Pop-ups on click</label>
              </li>
              <li onclick="setPopupsHover()">
                <input type="radio" name="style" value="01" id="hover">
                <label for="hover">Pop-ups on hover</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
        featureOverColumns: ['name', 'pop_max', 'pop_min']
      });

      client.addLayer(populatedPlacesLayer);
      client.getLeafletLayer().addTo(map);

      const popup = L.popup({ closeButton: false });

      function openPopup(featureEvent) {
        let content = '';
        content += `<div class="widget">`;
        if (featureEvent.data.name) {
          content += `<h2 class="h2">${featureEvent.data.name}</h2>`;
        }
        if (featureEvent.data.pop_max || featureEvent.data.pop_min) {
          content += `<ul>`;
          if (featureEvent.data.pop_max) {
            content += `<li><h3>Max:</h3><p class="open-sans">${featureEvent.data.pop_max}</p></li>`;
          }
          if (featureEvent.data.pop_min) {
            content += `<li><h3>Min:</h3><p class="open-sans">${featureEvent.data.pop_min}</p></li>`;
          }
          content += `</ul>`;
        }
        content += `</div>`;
        popup.setContent(content);
        popup.setLatLng(featureEvent.latLng);
        if (!popup.isOpen()) {
          popup.openOn(map);
        }
      }

      function closePopup(featureEvent) {
        popup.removeFrom(map);
      }

      function setPopupsClick() {
        populatedPlacesLayer.off('featureOver');
        populatedPlacesLayer.off('featureOut');
        populatedPlacesLayer.on('featureClicked', openPopup);
      }

      function setPopupsHover() {
        populatedPlacesLayer.off('featureClicked');
        populatedPlacesLayer.on('featureOver', openPopup);
        populatedPlacesLayer.on('featureOut', closePopup);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
      <!DOCTYPE html>
<html>
  <head>
    <title>Pop-ups | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Pop-Ups</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create pop-up information windows and interact with your map.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">Select your preferred kind of pop-ups</p>
          </section>

          <div id="controls">
            <ul class="actions">
              <li onclick="setPopupsClick()">
                <input type="radio" name="style" value="01" id="popup">
                <label for="popup">Pop-ups on click</label>
              </li>
              <li onclick="setPopupsHover()">
                <input type="radio" name="style" value="01" id="hover">
                <label for="hover">Pop-ups on hover</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.Dataset(`
        ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle, {
        featureOverColumns: ['name', 'pop_max', 'pop_min']
      });

      client.addLayer(populatedPlacesLayer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      const infowindow = new google.maps.InfoWindow();

      function openPopup(featureEvent) {
        let content = '';
        content += `<div class="widget">`;
        if (featureEvent.data.name) {
          content += `<h2 class="h2">${featureEvent.data.name}</h2>`;
        }
        if (featureEvent.data.pop_max || featureEvent.data.pop_min) {
          content += `<ul>`;
          if (featureEvent.data.pop_max) {
            content += `<li><h3>Max:</h3><p class="open-sans">${featureEvent.data.pop_max}</p></li>`;
          }
          if (featureEvent.data.pop_min) {
            content += `<li><h3>Min:</h3><p class="open-sans">${featureEvent.data.pop_min}</p></li>`;
          }
          content += `</ul>`;
        }
        content += `</div>`;
        infowindow.setContent(content);
        infowindow.setPosition(featureEvent.latLng);
        if (!infowindow.map) {
          infowindow.open(map);
        }
      }

      function closePopup(featureEvent) {
        infowindow.close();
      }

      function setPopupsClick() {
        populatedPlacesLayer.off('featureOver');
        populatedPlacesLayer.off('featureOut');
        populatedPlacesLayer.on('featureClicked', openPopup);
      }

      function setPopupsHover() {
        populatedPlacesLayer.off('featureClicked');
        populatedPlacesLayer.on('featureOver', openPopup);
        populatedPlacesLayer.on('featureOut', closePopup);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
      <!DOCTYPE html>
<html>
  <head>
    <title>Legends | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Legends</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create dynamic legends.</p>
          <div class="separator"></div>
          <div id="controls">
            <ul>
              <li onclick="setAllCities()">
                <input type="radio" name="data" checked  id="all">
                <label for="all">ALL cities</label>
              </li>
              <li onclick="setEuropeanCities()">
                <input type="radio" name="data" id="europe">
                <label for="europe">European cities</label>
              </li>
              <li onclick="setSpanishCities()">
                <input type="radio" name="data" id="spain">
                <label for="spain">Spanish cities</label>
              </li>
            </ul>
            <div class="separator"></div>
            <ul>
              <li onchange="invertColors()">
                <input type="checkbox" name="data" id="invertColors">
                <label for="invertColors">Invert colors</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box legend">
        <h2 class="h2">World cities</h2>
        <ul class="category open-sans">
          <li id="capital"></li>
          <li id="normal"></li>
        </ul>
        <h2 class="h2">Inhabitants</h2>
        <ul id="legend-population">
          <li class="size open-sans">
            <div id="min"></div>
            <div id="max"></div>
          </li>
          <li class="avg open-sans"></li>
        </ul>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: ramp([pop_max], range(2, 12), quantiles(5));
          marker-fill: ramp([adm0cap], (#EE4D5A, #68B69E), (0, 1), "=", category);
          marker-fill-opacity: 0.6;
          marker-allow-overlap: true;
          marker-line-width: 1;
          marker-line-color: #000;
          marker-line-opacity: 0.2;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      client.getLeafletLayer().addTo(map);

      populatedPlacesLayer.on('metadataChanged', function(event) {
        event.styles.forEach(function (styleMetadata) {
          switch(styleMetadata.getProperty()) {
            case 'marker-width':
              renderLegendSize(styleMetadata);
              break;
            case 'marker-fill':
              renderLegendCapital(styleMetadata);
              break;
          }
        });
      });

      function renderLegendSize(metadata) {
        document.getElementById('min').innerHTML = `
          <div class="circle circle-outline" style="width:8px; height:8px;"></div> <p>${metadata.getMin()}</p>
        `;
        document.getElementById('max').innerHTML = `
          <div class="circle circle-outline" style="width:24px; height:24px;"></div> <p>${metadata.getMax()}</p>
        `;
        document.querySelector('.legend .avg').innerHTML = `
          <p><b>Average: </b> ${metadata.getAverage().toFixed(2)}</p>
        `;
      }

      function renderLegendCapital(metadata) {
        const categories = metadata.getCategories();

        for (category of categories) {
          switch (category.name) {
            case 0:
              document.getElementById('normal').innerHTML = `
                <div class="circle" style="background:${category.value}"></div> Normal
              `;
              break;
            case 1:
              document.getElementById('capital').innerHTML = `
                <div class="circle" style="background:${category.value}"></div> Capital
              `;
              break;
          }
        }
      }

      function setAllCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
      }

      function setEuropeanCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `);
      }

      function setSpanishCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name = \'Spain\'
        `);
      }

      function invertColors() {
        const invert = document.getElementById('invertColors').checked;
        const colors = invert ? '(#68B69E, #EE4D5A)' : '(#EE4D5A, #68B69E)';
        const content = `
          #layer {
            marker-width: ramp([pop_max], range(2, 12), quantiles(5));
            marker-fill: ramp([adm0cap], ${colors}, (0, 1), "=", category);
            marker-fill-opacity: 0.6;
            marker-allow-overlap: true;
            marker-line-width: 1;
            marker-line-color: #000;
            marker-line-opacity: 0.2;
          }
        `;
        populatedPlacesStyle.setContent(content);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
      <!DOCTYPE html>
<html>
  <head>
    <title>Legends | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Legends</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Create dynamic legends.</p>
          <div class="separator"></div>
          <div id="controls">
            <ul>
              <li onclick="setAllCities()">
                <input type="radio" name="data" checked  id="all">
                <label for="all">ALL cities</label>
              </li>
              <li onclick="setEuropeanCities()">
                <input type="radio" name="data" id="europe">
                <label for="europe">European cities</label>
              </li>
              <li onclick="setSpanishCities()">
                <input type="radio" name="data" id="spain">
                <label for="spain">Spanish cities</label>
              </li>
            </ul>
            <div class="separator"></div>
            <ul>
              <li onchange="invertColors()">
                <input type="checkbox" name="data" id="invertColors">
                <label for="invertColors">Invert colors</label>
              </li>
            </ul>
          </div>

        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box legend">
        <h2 class="h2">World cities</h2>
        <ul class="category open-sans">
          <li id="capital"></li>
          <li id="normal"></li>
        </ul>
        <h2 class="h2">Inhabitants</h2>
        <ul id="legend-population">
          <li class="size open-sans">
            <div id="min"></div>
            <div id="max"></div>
          </li>
          <li class="avg open-sans"></li>
        </ul>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: ramp([pop_max], range(2, 12), quantiles(5));
          marker-fill: ramp([adm0cap], (#EE4D5A, #68B69E), (0, 1), "=", category);
          marker-fill-opacity: 0.6;
          marker-allow-overlap: true;
          marker-line-width: 1;
          marker-line-color: #000;
          marker-line-opacity: 0.2;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      populatedPlacesLayer.on('metadataChanged', function(event) {
        event.styles.forEach(function (styleMetadata) {
          switch(styleMetadata.getProperty()) {
            case 'marker-width':
              renderLegendSize(styleMetadata);
              break;
            case 'marker-fill':
              renderLegendCapital(styleMetadata);
              break;
          }
        });
      });

      function renderLegendSize(metadata) {
        document.getElementById('min').innerHTML = `
          <div class="circle circle-outline" style="width:8px; height:8px;"></div> <p>${metadata.getMin()}</p>
        `;
        document.getElementById('max').innerHTML = `
          <div class="circle circle-outline" style="width:24px; height:24px;"></div> <p>${metadata.getMax()}</p>
        `;
        document.querySelector('.legend .avg').innerHTML = `
          <p><b>Average: </b> ${metadata.getAverage().toFixed(2)}</p>
        `;
      }

      function renderLegendCapital(metadata) {
        const categories = metadata.getCategories();

        for (category of categories) {
          switch (category.name) {
            case 0:
              document.getElementById('normal').innerHTML = `
                <div class="circle" style="background:${category.value}"></div> Normal
              `;
              break;
            case 1:
              document.getElementById('capital').innerHTML = `
                <div class="circle" style="background:${category.value}"></div> Capital
              `;
              break;
          }
        }
      }

      function setAllCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
      }

      function setEuropeanCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name IN (SELECT admin FROM ne_adm0_europe)
        `);
      }

      function setSpanishCities() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            WHERE adm0name = \'Spain\'
        `);
      }

      function invertColors() {
        const invert = document.getElementById('invertColors').checked;
        const colors = invert ? '(#68B69E, #EE4D5A)' : '(#EE4D5A, #68B69E)';
        const content = `
          #layer {
            marker-width: ramp([pop_max], range(2, 12), quantiles(5));
            marker-fill: ramp([adm0cap], ${colors}, (0, 1), "=", category);
            marker-fill-opacity: 0.6;
            marker-allow-overlap: true;
            marker-line-width: 1;
            marker-line-color: #000;
            marker-line-opacity: 0.2;
          }
        `;
        populatedPlacesStyle.setContent(content);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
      <!DOCTYPE html>
<html>
  <head>
    <title>Populated places | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Most/less populated places</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Filter the 20 most/less populated places in the world.</p>
          <div class="separator"></div>
          <div id="controls">
            <ul class="actions">
              <li onclick="setAll()">
                <input type="radio" name="style" value="01" id="all" checked="">
                <label for="all">ALL Places<label>
              </li>
              <li onclick="setMostPopulated(20)">
                <input type="radio" name="style" value="02" id="most">
                <label for="most">Most populated places</label>
              </li>
              <li onclick="setLessPopulated(20)">
                <input type="radio" name="style" value="03" id="less">
                <label for="less">Less populated places</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #EE4D5A;
          marker-width: 7;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      client.getLeafletLayer().addTo(map);

      function setAll() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #EE4D5A;
            marker-width: 7;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setMostPopulated(limit) {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            ORDER BY pop_max DESC LIMIT ${limit}
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #68B69E;
            marker-width: 12;
            marker-line-color: #FFFFFF;
            text-name: [name];
            text-face-name: 'Open Sans Regular';
            text-size: 12;
            text-dy: -10;
          }
        `);
      }

      function setLessPopulated(limit) {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            ORDER BY pop_max ASC LIMIT ${limit}
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #F15743;
            marker-width: 12;
            marker-line-color: #FFFFFF;
            text-name: [name];
            text-face-name: 'Open Sans Regular';
            text-size: 12;
            text-dy: -10;
          }
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
      <!DOCTYPE html>
<html>
  <head>
    <title>Populated places | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Most/less populated places</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Filter the 20 most/less populated places in the world.</p>
          <div class="separator"></div>
          <div id="controls">
            <ul class="actions">
              <li onclick="setAll()">
                <input type="radio" name="style" value="01" id="all" checked="">
                <label for="all">ALL Places<label>
              </li>
              <li onclick="setMostPopulated(20)">
                <input type="radio" name="style" value="02" id="most">
                <label for="most">Most populated places</label>
              </li>
              <li onclick="setLessPopulated(20)">
                <input type="radio" name="style" value="03" id="less">
                <label for="less">Less populated places</label>
              </li>
            </ul>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(`
        SELECT *
          FROM ne_10m_populated_places_simple
      `);
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-fill: #EE4D5A;
          marker-width: 7;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      function setAll() {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #EE4D5A;
            marker-width: 7;
            marker-line-color: #FFFFFF;
          }
        `);
      }

      function setMostPopulated(limit) {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            ORDER BY pop_max DESC LIMIT ${limit}
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #68B69E;
            marker-width: 12;
            marker-line-color: #FFFFFF;
            text-name: [name];
            text-face-name: 'Open Sans Regular';
            text-size: 12;
            text-dy: -10;
          }
        `);
      }

      function setLessPopulated(limit) {
        populatedPlacesSource.setQuery(`
          SELECT *
            FROM ne_10m_populated_places_simple
            ORDER BY pop_max ASC LIMIT ${limit}
        `);
        populatedPlacesStyle.setContent(`
          #layer {
            marker-fill: #F15743;
            marker-width: 12;
            marker-line-color: #FFFFFF;
            text-name: [name];
            text-face-name: 'Open Sans Regular';
            text-size: 12;
            text-dy: -10;
          }
        `);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
      <!DOCTYPE html>
<html>
  <head>
    <title>Edit SQL CARTOCSS | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Edit SQL & CartoCSS</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Edit manually the SQL query and the CartoCSS style.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">This example only uses one style and one layer whose content is changed.</p>
            <p class="open-sans">Since the style and source objects are the same they won't trigger events. You need to use the promise to handle errors.</p>
          </section>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">SQL</h2>
        <textarea id="sql" rows="3">SELECT * FROM ne_10m_populated_places_simple</textarea>
        <button class="button" onclick="updateSource()">UPDATE SQL</button>
      </div>

      <div class="box widget">
        <h2 class="h2">CartoCSS</h2>
        <textarea id="cartocss" rows="3">
#layer {
  marker-fill: red;
}
        </textarea>
        <button class="button-update button" onclick="updateStyle()">UPDATE STYLE</button>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(getValue('#sql'));
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-fill-opacity: 0.9;
          marker-line-width: 0.5;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      client.getLeafletLayer().addTo(map);

      function updateSource() {
        reset('#sql');
        populatedPlacesSource.setQuery(getValue('#sql'))
          .catch(cartoError => {
            error('#sql', cartoError);
          });
      }

      function updateStyle() {
        reset('#cartocss')
        populatedPlacesStyle.setContent(getValue('#cartocss'))
          .catch(cartoError => {
            error('#cartocss', cartoError);
          });
      }

      function getValue(id) {
        return document.querySelector(id).value
      }

      function reset(id) {
        document.querySelector(id).style.border = 'default';
      }

      function error(id, cartoError) {
        document.querySelector(id).style.border = '1px solid #E57373';
        alert(cartoError.message);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
      <!DOCTYPE html>
<html>
  <head>
    <title>Edit SQL & CartoCSS | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Edit SQL & CartoCSS</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Edit manually the SQL query and the CartoCSS style.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">This example only uses one style and one layer whose content is changed.</p>
            <p class="open-sans">Since the style and source objects are the same they won't trigger events. You need to use the promise to handle errors.</p>
          </section>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">SQL</h2>
        <textarea id="sql" rows="3">SELECT * FROM ne_10m_populated_places_simple</textarea>
        <button class="button" onclick="updateSource()">UPDATE SQL</button>
      </div>

      <div class="box widget">
        <h2 class="h2">CartoCSS</h2>
        <textarea id="cartocss" rows="3">
#layer {
  marker-fill: red;
}
        </textarea>
        <button class="button-update button" onclick="updateStyle()">UPDATE STYLE</button>
      </div>
    </aside>

    <script>
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 30, lng: 0},
        zoom: 3,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });
      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      const populatedPlacesSource = new carto.source.SQL(getValue('#sql'));
      const populatedPlacesStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-fill-opacity: 0.9;
          marker-line-width: 0.5;
          marker-line-color: #FFFFFF;
        }
      `);
      const populatedPlacesLayer = new carto.layer.Layer(populatedPlacesSource, populatedPlacesStyle);

      client.addLayer(populatedPlacesLayer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      function updateSource() {
        reset('#sql');
        populatedPlacesSource.setQuery(getValue('#sql'))
          .catch(cartoError => {
            error('#sql', cartoError);
          });
      }

      function updateStyle() {
        reset('#cartocss')
        populatedPlacesStyle.setContent(getValue('#cartocss'))
          .catch(cartoError => {
            error('#cartocss', cartoError);
          });
      }

      function getValue(id) {
        return document.querySelector(id).value
      }

      function reset(id) {
        document.querySelector(id).style.background = 'white';
      }

      function error(id, cartoError) {
        document.querySelector(id).style.border = '1px solid #E57373';
        alert(cartoError.message);
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
      <!DOCTYPE html>
<html>
  <head>
    <title>Error handling | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
    <link href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">

  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Error handling</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Handle common errors in maps.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">In this example we handle the client error while calling the `addLayer` funciton.</p>
            <p class="open-sans">See `refreshLayer` function in the source code for an example on how to handle Promise errors.</p>
          </section>
          <div id="controls">
            <div id="info"><p class="mt-16 open-sans"></p></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">DATASET</h2>
        <textarea id="dataset-value" rows=2></textarea>
        <button id="dataset-button" class="button" onclick="updateDataset()">SET WRONG DATASET</button>
      </div>

      <div class="box widget">
        <h2 class="h2">STYLE</h2>
        <textarea id="style-value" rows="3"></textarea>
        <button id="style-button" class="button" onclick="updateStyle()">UPDATE STYLE</button>
      </div>
    </aside>

    <script>
      const map = L.map('map').setView([30, 0], 3);
      map.scrollWheelZoom.disable();

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18
      }).addTo(map);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      // State
      const state = {
        isDatasetValid: true,
        isStyleValid: true,
        errorMessage: '',
        updating: false
      };

      // Datasets
      const validDataset = 'ne_10m_populated_places_simple';
      const wrongDataset = 'wrong_dataset';

      // Style
      const validStyle = '#layer { marker-fill: red; }';
      const wrongStyle = '#layer { marker-fill: wrong-color; }';

      let source = new carto.source.Dataset(validDataset);
      let style = new carto.style.CartoCSS(validStyle);
      let layer = new carto.layer.Layer(source, style);

      client.addLayer(layer);
      client.getLeafletLayer().addTo(map);

      updateUI();

      function refreshLayer (layer) {
        client.addLayer(layer)
          .then(function () {
            state.errorMessage = '';
            state.updating = false;
            updateUI();
          })
          .catch(function (error) {
            state.errorMessage = error.message;
            state.updating = false;
            updateUI();
          });
      }

      function updateDataset() {
        client.removeLayer(layer);

        state.isDatasetValid = !state.isDatasetValid;
        state.updating = true;

        const dataset = state.isDatasetValid
          ? validDataset
          : wrongDataset;

        updateUI();

        source = new carto.source.Dataset(dataset);
        layer = new carto.layer.Layer(source, style);
        refreshLayer(layer);
      }

      function updateStyle() {
        client.removeLayer(layer);

        state.isStyleValid = !state.isStyleValid;
        state.updating = true;

        const styleContent = state.isStyleValid
          ? validStyle
          : wrongStyle;

        updateUI();

        style = new carto.style.CartoCSS(styleContent);
        layer = new carto.layer.Layer(source, style);
        refreshLayer(layer);
      }

      function updateUI () {
        const datasetValueEl = document.getElementById('dataset-value');
        const styleValueEl = document.getElementById('style-value');
        const datasetButtonEl = document.getElementById('dataset-button');
        const styleButtonEl = document.getElementById('style-button');
        const panelEl = document.querySelector('#info p');

        datasetValueEl.value = state.isDatasetValid
          ? validDataset
          : wrongDataset;

        styleValueEl.value = state.isStyleValid
          ? validStyle
          : wrongStyle;

        datasetButtonEl.textContent = state.isDatasetValid
          ? 'Set wrong dataset'
          : 'Revert to a valid dataset';

        styleButtonEl.textContent = state.isStyleValid
          ? 'Set wrong style'
          : 'Revert to a valid style';

        panelEl.textContent = state.updating
          ? 'Updating...'
          : state.errorMessage
            ? state.errorMessage
            : 'Everything OK';

        if (state.updating) {
          panelEl.classList.remove('bg-red');
          panelEl.classList.remove('bg-white');
          panelEl.classList.add('bg-orange');
          panelEl.classList.add('p-8');
          panelEl.classList.add('text-white');
        } else if (state.errorMessage) {
          panelEl.classList.add('bg-red');
          panelEl.classList.remove('bg-white');
          panelEl.classList.remove('bg-orange');
          panelEl.classList.add('p-8');
          panelEl.classList.add('text-white');
        } else {
          panelEl.classList.add('bg-white');
          panelEl.classList.remove('bg-red');
          panelEl.classList.remove('bg-orange');
          panelEl.classList.remove('p-8');
          panelEl.classList.remove('text-white');
        }
      }
    </script>
  </body>
</html>

      
CLICK TO COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
      <!DOCTYPE html>
<html>
  <head>
    <title>Error handling | CARTO</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700' rel='stylesheet' type='text/css'>
    <!-- Include Google Maps -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAORE5iCjgLb4sMcWfmyRJgtP9VwfOrbJM&v=3.31"></script>
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.2/carto.min.js"></script>
    <link href="https://carto.com/developers/carto-js/examples/maps/public/style.css" rel="stylesheet">
  </head>
  <body>
    <div id="map"></div>
    <aside class="toolbox">
      <div class="box">
        <header>
          <h1>Error handling</h1>
          <button class="github-logo js-source-link"></button>
        </header>
        <section>
          <p class="description open-sans">Handle common errors in maps.</p>
          <div class="separator"></div>
          <section class="usage">
            <header>USAGE</header>
            <p class="open-sans">In this example we handle the client error while calling the `addLayer` funciton.</p>
            <p class="open-sans">See `refreshLayer` function in the source code for an example on how to handle Promise errors.</p>
          </section>
          <div id="controls">
            <div id="info"><p class="mt-16 open-sans"></p></div>
          </div>
        </section>
        <footer class="js-footer"></footer>
      </div>

      <div class="box widget">
        <h2 class="h2">DATASET</h2>
        <textarea id="dataset-value" rows=2></textarea>
        <button id="dataset-button" class="button" onclick="updateDataset()">SET WRONG DATASET</button>
      </div>

      <div class="box widget">
        <h2 class="h2">STYLE</h2>
        <textarea id="style-value" rows="3"></textarea>
        <button id="style-button" class="button" onclick="updateStyle()">UPDATE STYLE</button>
      </div>
    </aside>

    <script>
      // Setting up a Google Maps Map
      const map = new google.maps.Map(document.getElementById('map'), {
        center: {lat: 50, lng: 15},
        zoom: 4,
        fullscreenControl: false,
        gestureHandling: 'cooperative'
      });

      // Hide the map labels and geometry strokes
      map.set('styles', [{
        elementType: 'labels',
        stylers: [{ visibility: 'off' }]
      }, {
        elementType: 'geometry.stroke',
        stylers: [{ visibility: 'off' }]
      }]);

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'cartojs-test'
      });

      // State
      const state = {
        isDatasetValid: true,
        isStyleValid: true,
        errorMessage: '',
        updating: false
      };

      // Datasets
      const validDataset = 'ne_10m_populated_places_simple';
      const wrongDataset = 'wrong_dataset';

      // Style
      const validStyle = '#layer { marker-fill: red; }';
      const wrongStyle = '#layer { marker-fill: wrong-color; }';

      let source = new carto.source.Dataset(validDataset);
      let style = new carto.style.CartoCSS(validStyle);
      let layer = new carto.layer.Layer(source, style);

      // Adding the layers to the map
      client.addLayer(layer);
      map.overlayMapTypes.push(client.getGoogleMapsMapType(map));

      updateUI();

      function refreshLayer (layer) {
        client.addLayer(layer)
          .then(function () {
            state.errorMessage = '';
            state.updating = false;
            updateUI();
          })
          .catch(function (error) {
            state.errorMessage = error.message;
            state.updating = false;
            updateUI();
          });
      }

      function updateDataset() {
        client.removeLayer(layer);

        state.isDatasetValid = !state.isDatasetValid;
        state.updating = true;

        const dataset = state.isDatasetValid
          ? validDataset
          : wrongDataset;

        updateUI();

        source = new carto.source.Dataset(dataset);
        layer = new carto.layer.Layer(source, style);
        refreshLayer(layer);
      }

      function updateStyle() {
        client.removeLayer(layer);

        state.isStyleValid = !state.isStyleValid;
        state.updating = true;

        const styleContent = state.isStyleValid
          ? validStyle
          : wrongStyle;

        updateUI();

        style = new carto.style.CartoCSS(styleContent);
        layer = new carto.layer.Layer(source, style);
        refreshLayer(layer);
      }

      function updateUI () {
        const datasetValueEl = document.getElementById('dataset-value');
        const styleValueEl = document.getElementById('style-value');
        const datasetButtonEl = document.getElementById('dataset-button');
        const styleButtonEl = document.getElementById('style-button');
        const panelEl = document.querySelector('#info p');

        datasetValueEl.value = state.isDatasetValid
          ? validDataset
          : wrongDataset;

        styleValueEl.value = state.isStyleValid
          ? validStyle
          : wrongStyle;

        datasetButtonEl.textContent = state.isDatasetValid
          ? 'Set wrong dataset'
          : 'Revert to a valid dataset';

        styleButtonEl.textContent = state.isStyleValid
          ? 'Set wrong style'
          : 'Revert to a valid style';

        panelEl.textContent = state.updating
          ? 'Updating...'
          : state.errorMessage
            ? state.errorMessage
            : 'Everything OK';

        if (state.updating) {
          panelEl.classList.remove('bg-red');
          panelEl.classList.remove('bg-white');
          panelEl.classList.add('bg-orange');
          panelEl.classList.add('p-8');
          panelEl.classList.add('text-white');
        } else if (state.errorMessage) {
          panelEl.classList.add('bg-red');
          panelEl.classList.remove('bg-white');
          panelEl.classList.remove('bg-orange');
          panelEl.classList.add('p-8');
          panelEl.classList.add('text-white');
        } else {
          panelEl.classList.add('bg-white');
          panelEl.classList.remove('bg-red');
          panelEl.classList.remove('bg-orange');
          panelEl.classList.remove('p-8');
          panelEl.classList.remove('text-white');
        }
      }
    </script>
  </body>
</html>

      
CLICK TO COPY