CARTO for deck.gl

CARTO for deck.gl

Clustering

This example shows how to create clusters of points.

  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
<html>
  <head>
    <script src="https://unpkg.com/deck.gl@^8.5.0/dist.min.js"></script>
    <script src="https://unpkg.com/@deck.gl/carto@^8.5.0/dist.min.js"></script>

    <script src="https://unpkg.com/supercluster@6.0.2/dist/supercluster.min.js"></script>
    
    <script src="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.js"></script>
    <link href="https://libs.cartocdn.com/mapbox-gl/v1.13.0/mapbox-gl.css" rel="stylesheet" />
  </head>

  <body style="margin: 0; padding: 0">
    <div id="map" style="width: 100vw; height: 100vh;"></div>
  </body>

  <script type="text/javascript">
    deck.carto.setDefaultCredentials({
      apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
      apiVersion: deck.carto.API_VERSIONS.V3,
      accessToken: 'eyJhbGciOiJIUzI1NiJ9.eyJhIjoiYWNfbHFlM3p3Z3UiLCJqdGkiOiI1YjI0OWE2ZCJ9.Y7zB30NJFzq5fPv8W5nkoH5lPXFWQP0uywDtqUg8y8c'
    });

    (async ()=>{
      const {DeckGL, CompositeLayer, IconLayer} = deck;
      const {CartoSQLLayer, setDefaultCredentials} = deck.carto;

      // Define your custom IconClusterLayer
      function getIconName(size) {
        if (size === 0) {
          return '';
        }
        if (size < 10) {
          return `marker-${size}`;
        }
        if (size < 100) {
          return `marker-${Math.floor(size / 10)}0`;
        }
        return 'marker-100';
      }

      function getIconSize(size) {
        return Math.min(100, size) / 100 + 1;
      }

      class IconClusterLayer extends CompositeLayer {
        shouldUpdateState({changeFlags}) {
          return changeFlags.somethingChanged;
        }

        updateState({props, oldProps, changeFlags}) {
          const rebuildIndex = changeFlags.dataChanged || props.sizeScale !== oldProps.sizeScale;

          if (rebuildIndex) {
            const index = new Supercluster({maxZoom: 16, radius: props.sizeScale});
            index.load(
              props.data.map(d => ({
                geometry: {coordinates: props.getPosition(d)},
                properties: d
              }))
            );
            this.setState({index});
          }

          const z = Math.floor(this.context.viewport.zoom);
          if (rebuildIndex || z !== this.state.z) {
            this.setState({
              data: this.state.index.getClusters([-180, -85, 180, 85], z),
              z
            });
          }
        }

        renderLayers() {
          const {data} = this.state;
          const {iconAtlas, iconMapping, sizeScale} = this.props;

          return new IconLayer(
            this.getSubLayerProps({
              id: 'icon',
              data,
              iconAtlas,
              iconMapping,
              sizeScale,
              getPosition: d => d.geometry.coordinates,
              getIcon: d => getIconName(d.properties.cluster ? d.properties.point_count : 1),
              getSize: d => getIconSize(d.properties.cluster ? d.properties.point_count : 1)
            })
          );
        }
      }

      // Fetch Data from CARTO
      const data =  await deck.carto.getData({
        type: deck.carto.MAP_TYPES.QUERY,
        source: `SELECT cartodb_id, geom FROM cartobq.public_account.meteorites`,
        connection: 'bqconn',
        format: deck.carto.FORMATS.GEOJSON
      });

      // Create a deck.gl map and use your IconClusterLayer with your CARTO dataset
      const deckgl = new DeckGL({
        container: 'map',
        mapStyle: deck.carto.BASEMAP.VOYAGER,

        initialViewState: {
          latitude: 0,
          longitude: 0,
          zoom: 1
        },
        controller: true,

        layers: [
          new IconClusterLayer({
            id: 'icon-cluster',
            data: data.features,
            getPosition: d => d.geometry.coordinates,
            iconAtlas: 'https://raw.githubusercontent.com/visgl/deck.gl/8.4-release/examples/website/icon/data/location-icon-atlas.png',
            iconMapping: 'https://raw.githubusercontent.com/visgl/deck.gl/8.4-release/examples/website/icon/data/location-icon-mapping.json',
            sizeScale: 60
          })
        ]
      });
    })();
  </script>
</html>