Mapbox Tutorial: Heatmap using GL JS

Madison Draper
5 min readApr 11, 2018

--

Heatmaps, or isorhythmic maps, display dense amounts of points as a painted cluster. It’s visually stimulating and shows gradients of concentrations. One of the most common heat maps is a meteorological map. Here is Mapbox’s original tutorial for another point of reference.

What You’ll Need

  1. Mapbox account and access token.
  2. Mapbox GL JS, a Javascript Library.
  3. Text Editor, either Sublime or Atom works great.
  4. GeoJSON data of the street trees in Pittsburgh from the Western Pennsylvania Regional Data Center.
  5. This extensively commented code. I won’t give you all the answers throughout the tutorial, but reference this if you get stuck!

Step 1: Create a Web Map

Let’s start by setting up a web page with an empty blank map. This will be our canvas.

  1. Open a new document in your text editor and save it as index.html.
  2. Create a skeleton HTML document.
<!DOCtype html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<style> /* CSS here */ </style>
</head>
<body>
<script> /* JavaScript here */ </script>
<body>
</html>

3. Add Mapbox GL JS between the <head> tags.

<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.js'></script><link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css' rel='stylesheet' />

4. Between the <head> tags, add CSS styling for your map.

 <style>    
body {
margin: 0;
padding: 0;
}

#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>

5. Add your map container between the <body> tags.

<div id='map'></div>

6. Between the <script> tags, add your access token and initiate the map. In your map variable, you can set the container, style, center and zoom.

mapboxgl.accessToken = '<your-access-token>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v9',
center: [-79.999732, 40.4374],
zoom: 11
});

Open your map in the browser. If you don’t see it come up, that’s okay. Go through the steps again and try to troubleshoot yourself before looking at the provided code.

Step 2: Add Data and Layers

  1. Make sure you downloaded the data
  2. Use the .on function to initiate an event listener for load, then give it a function to fire.
  3. Add the data source with .addSource(). Declare an id, type and path.
map.on('load', function() {

map.addSource('trees', {
type: 'geojson',
data: './trees.geojson'
});
/* add heatmap layer here */
/* add circle layer here */
});

4. Add the source to the map as a layer using .addLayer(). Declare the id, type, source, zoom and details.

5. Add a JSON to paint to adjust heat map properties. Add stops for zoom adjustments. This describes the heat-map properties thoroughly.

map.addLayer({
id: 'trees-heat',
type: 'heatmap',
source: 'trees',
maxzoom: 15,
paint: {
// increase weight as diameter breast height increases
'heatmap-weight': {
property: 'dbh',
type: 'exponential',
stops: [
[1, 0],
[62, 1]
]
},
// increase intensity as zoom level increases
'heatmap-intensity': {
stops: [
[11, 1],
[15, 3]
]
},
// assign color values be applied to points depending on their density
'heatmap-color': [
'interpolate',
['linear'],
['heatmap-density'],
0, 'rgba(236,222,239,0)',
0.2, 'rgb(208,209,230)',
0.4, 'rgb(166,189,219)',
0.6, 'rgb(103,169,207)',
0.8, 'rgb(28,144,153)'
],
// increase radius as zoom increases
'heatmap-radius': {
stops: [
[11, 15],
[15, 20]
]
},
// decrease opacity to transition into the circle layer
'heatmap-opacity': {
default: 1,
stops: [
[14, 1],
[15, 0]
]
},
}
}, 'waterway-label');

6. Add a JSON to paint to adjust circle properties. Add stops for zoom adjustments.

map.addLayer({
id: 'trees-point',
type: 'circle',
source: 'trees',
minzoom: 14,
paint: {
// increase the radius of the circle as the zoom level and dbh value increases
'circle-radius': {
property: 'dbh',
type: 'exponential',
stops: [
[{ zoom: 15, value: 1 }, 5],
[{ zoom: 15, value: 62 }, 10],
[{ zoom: 22, value: 1 }, 20],
[{ zoom: 22, value: 62 }, 50],
]
},
'circle-color': {
property: 'dbh',
type: 'exponential',
stops: [
[0, 'rgba(236,222,239,0)'],
[10, 'rgb(236,222,239)'],
[20, 'rgb(208,209,230)'],
[30, 'rgb(166,189,219)'],
[40, 'rgb(103,169,207)'],
[50, 'rgb(28,144,153)'],
[60, 'rgb(1,108,89)']
]
},
'circle-stroke-color': 'white',
'circle-stroke-width': 1,
'circle-opacity': {
stops: [
[14, 0],
[15, 1]
]
}
}
}, 'waterway-label');

Step 3: Add Pop-Ups

  1. Use .on again to listen for click on the specified type trees-point.
map.on('click', 'trees-point', function (e) {
/* add functionality here */
});

2. When this occurs, the function will create a new pop-up using new mapboxgl.Popup()

3. Set properties to the map, such as its coordinates and HTML styling, and add it to the map

new mapboxgl.Popup()
.setLngLat(e.features[0].geometry.coordinates)
.setHTML('<b>DBH:</b> '+ e.features[0].properties.dbh)
.addTo(map);

Good job! Refresh your page and try zooming in and out of the area to watch the heatmap and circles switch as you zoom closer. If you’re having some trouble, try to troubleshoot it yourself. Or, you can view the code with extensive comments on the different parts of the code. Hope you learned a lot, let me know how it went!

--

--