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>