Creating A Deck.gl Layer Using A REST API

This project uses a deck.gl layer with MapLibre and a Clockwork Micro base map in order to display the sights in Île-de-France. We will also colour the points according to the districts of these sights.


Initialising the Project

We will use a Clockwork mMicro map as our basemap. Don't forget to use your own API key.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>

    <link
      rel="stylesheet"
      href="https://unpkg.com/maplibre-gl@3.5.2/dist/maplibre-gl.css"
    />
    <script src="https://unpkg.com/maplibre-gl@3.5.2/dist/maplibre-gl.js"></script>
    <title>Deck.gl Data Visualisation | CWM</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        position: relative;
      }
      #map {
        height: 100vh;
        width: 100vw;
      }
      .maplibregl-popup {
        z-index: 2;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const url = "https://maps.clockworkmicro.com/streets/v1/style?x-api-key=";
      const apiKey = "cwm_api_key";

      const map = new maplibregl.Map({
        container: "map",
        style: url + apiKey,
        center: [2.343957, 48.862011],
        zoom: 10.5,
      });
      map.addControl(new maplibregl.NavigationControl(), "top-right");

    </script>
  </body>
</html>

Dataset and Initialising the Deck.gl Layer

We will use a REST API as our data source. We will receive geoJSON points for the sites. The quantity of points received can be limited by using the limit param. We will use the code for the districts for coloring our points on our ScatterPlot Layer instead of changing the point radius, which is more common and works the same way.


The color palette chosen for this example consists of 21 colors that are chosen at random. Deck.gl expects an array of three numbers as RGB values. Following is the color palette chosen for this example.

const colorPalette = [
  [255, 102, 51],
  [255, 179, 153],
  [255, 51, 255],
  [255, 255, 153],
  [0, 179, 230],
  [230, 179, 51],
  [51, 102, 230],
  [153, 153, 102],
  [153, 255, 153],
  [179, 77, 77],
  [128, 179, 0],
  [128, 153, 0],
  [230, 179, 179],
  [102, 128, 179],
  [102, 153, 26],
  [255, 153, 230],
  [204, 255, 26],
  [255, 26, 102],
  [230, 51, 26],
  [51, 255, 204],
  [102, 153, 77],
];

We now load the data from a publicly available API endpoint and create the ScatterPlotLayer as a MapboxOverlay. We will also add a MapLibre popup on click events that contains the name of the sight. Since we are going to add the layer as an overlay the layer will appear over the popup. In order to prevent that we can simply change the z-index value of the popup.

.maplibregl-popup {
  z-index: 2;
}

// Add the overlay as a control
map.on("load", () => {
  (async () => {
    // Pull the data
    const responseJSON = await fetch(parisSights).then((res) =>
      res.json()
    );

    const layer = new deck.ScatterplotLayer({
      id: "scatterplot-layer",
      data: responseJSON.results,
      pickable: true,
      opacity: 0.7,
      stroked: true,
      filled: true,
      radiusMinPixels: 14,
      radiusMaxPixels: 100,
      lineWidthMinPixels: 5,
      // Using appropiriate fields for coordinates from the dataset
      getPosition: (d) => [d.geo_point_2d.lon, d.geo_point_2d.lat],
      getFillColor: (d) => {
        if ("insee" in d && d.insee.startsWith("75")) {
          // All the districts in Paris
          return colorPalette[parseInt(d.insee.substring(3))];
        } else {
          // Out of Paris
          return colorPalette[20];
        }
      },
      getLineColor: (d) => [14, 16, 255],
      onClick: (info) => {
        const { coordinate, object } = info;
        const description = `<p>${object.nom_carto || "Unknown"}</p>`;

        new maplibregl.Popup()
          .setLngLat(coordinate)
          .setHTML(description)
          .addTo(map);
      },
    });

    // create the overlay
    const overlay = new deck.MapboxOverlay({
      layers: [layer],
    });
    map.addControl(overlay);
  })();
});

Just in case you missed any of the steps following is the code for this example.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>

    <link
      rel="stylesheet"
      href="https://unpkg.com/maplibre-gl@3.5.2/dist/maplibre-gl.css"
    />
    <script src="https://unpkg.com/maplibre-gl@3.5.2/dist/maplibre-gl.js"></script>
    <title>Deck.gl Data Visualisation Using REST API</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        position: relative;
      }
      #map {
        height: 100vh;
        width: 100vw;
      }
      .maplibregl-popup {
        z-index: 2;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const url = "https://maps.clockworkmicro.com/streets/v1/style?x-api-key=";
      const apiKey = "cwm_api_key";

      const map = new maplibregl.Map({
        container: "map",
        style: url + apiKey,
        center: [2.343957, 48.862011],
        zoom: 10.5,
      });
      map.addControl(new maplibregl.NavigationControl(), "top-right");

      // 20 + 1 colors all the districts of Paris and outside of the discrits
      const colorPalette = [
        [255, 102, 51],
        [255, 179, 153],
        [255, 51, 255],
        [255, 255, 153],
        [0, 179, 230],
        [230, 179, 51],
        [51, 102, 230],
        [153, 153, 102],
        [153, 255, 153],
        [179, 77, 77],
        [128, 179, 0],
        [128, 153, 0],
        [230, 179, 179],
        [102, 128, 179],
        [102, 153, 26],
        [255, 153, 230],
        [204, 255, 26],
        [255, 26, 102],
        [230, 51, 26],
        [51, 255, 204],
        [102, 153, 77],
      ];

      const limit = 100;
      // Source for the sample data = https://data.iledefrance.fr
      const parisSights = `https://data.iledefrance.fr/api/explore/v2.1/catalog/datasets/principaux-sites-touristiques-en-ile-de-france0/records?limit=${limit}`;

      let layerControl;

      // Add the overlay as a control
      map.on("load", () => {
        (async () => {
          // Pull the data
          const responseJSON = await fetch(parisSights).then((res) =>
            res.json()
          );

          const layer = new deck.ScatterplotLayer({
            id: "scatterplot-layer",
            data: responseJSON.results,
            pickable: true,
            opacity: 0.7,
            stroked: true,
            filled: true,
            radiusMinPixels: 14,
            radiusMaxPixels: 100,
            lineWidthMinPixels: 5,
            // Using appropiriate fields for coordinates from the dataset
            getPosition: (d) => [d.geo_point_2d.lon, d.geo_point_2d.lat],
            getFillColor: (d) => {
              if ("insee" in d && d.insee.startsWith("75")) {
                // All the districts in Paris
                return colorPalette[parseInt(d.insee.substring(3))];
              } else {
                // Out of Paris
                return colorPalette[20];
              }
            },
            getLineColor: (d) => [14, 16, 255],
            onClick: (info) => {
              const { coordinate, object } = info;
              const description = `<p>${object.nom_carto || "Unknown"}</p>`;

              new maplibregl.Popup()
                .setLngLat(coordinate)
                .setHTML(description)
                .addTo(map);
            },
          });

          // create the overlay
          const overlay = new deck.MapboxOverlay({
            layers: [layer],
          });
          map.addControl(overlay);
        })();
      });
    </script>
  </body>
</html>

About

Clockwork Micro is based in Seattle and Paris.

Services

Contact

Email:

info@clockworkmicro.com
Copyright2024Clockwork Micro. All rights reserved.

Clockwork Micro