Heatmap
Using a GeoJSON data source and map styles, you can display a heatmap layer on the map: a set of circles with a gradient fill that merge into a single object if they are close to each other.
To do this, you need to create a GeoJSON data source by calling the GeoJsonSource() method and specifying a unique attribute for this data source (for example, purpose: 'heatmap'
). The GeoJSON object must contain only Point
and MultiPoint
objects (centers of the circles).
Important
The heatmap layer is not supported in the 3D Terrain map mode.
const data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { customProperty: 1 },
geometry: {
type: 'MultiPoint',
coordinates: [
[55.44, 25.34],
[55.43, 25.37],
[55.41, 25.34],
],
},
},
{
type: 'Feature',
properties: { customProperty: 2 },
geometry: {
type: 'Point',
coordinates: [55.4, 25.3],
},
},
],
};
const source = new mapgl.GeoJsonSource(map, {
data,
attributes: {
purpose: 'heatmap',
},
});
After that, you need to create a layer style, specifying heatmap as the layer type and filtering by the attribute that was specified when the GeoJsonSource() method was called (purpose = heatmap
).
const layer = {
id: 'my-heatmap-layer',
filter: ['match', ['sourceAttr', 'purpose'], ['heatmap'], true, false],
type: 'heatmap',
style: {
color: [
'interpolate',
['linear'],
['heatmap-density'],
0,
'rgba(0, 0, 0, 0)',
0.2,
'rgba(172, 32, 135, 1)',
0.4,
'rgba(255, 154, 0, 1)',
0.6,
'rgba(255, 252, 0, 1)',
0.8,
'rgba(255, 255, 63, 1)',
1,
'rgba(255, 255, 255, 1)',
],
radius: 50,
weight: ['get', 'customProperty'],
intensity: 0.8,
opacity: 0.8,
downscale: 1,
},
};
map.on('styleload', () => {
map.addLayer(layer);
});
List of layer properties:
color
- array of colors for the gradient, from the perimeter (0.0
) to the center of the circle (1.0
). It is important to specify a transparent color for the perimeter, otherwise the whole map will be filled with that color.radius
- radius of the circle in pixels.weight
- heat intensity for the specific point. The higher the value, the larger the size of the central part of the circle (colors closer to1.0
from thecolor
array will become more prevalent). It only makes sense to specify ExtractorExpression or InterpolateExpression as a value, using one of the properties of the object. Otherwise, the heat intensity will be set for all points of the source.intensity
- heat intensity modifier that will be applied to all points.opacity
- opacity of the layer (1
- the layer is fully visible,0
- the layer is completely transparent and invisible).downscale
- resolution modifier. The higher the value, the lower the resolution of the heatmap layer, and the faster the rendering. Default is1
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>2GIS Map API</title>
<meta name="description" content="Heatmap layer example" />
<style>
html,
body,
#container {
margin: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="https://mapgl.2gis.com/api/js/v1"></script>
<script>
const map = new mapgl.Map('container', {
center: [55.425, 25.355],
zoom: 10,
key: 'Your API access key',
});
const data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { customProperty: 1 },
geometry: {
type: 'MultiPoint',
coordinates: [
[55.44, 25.34],
[55.43, 25.37],
[55.41, 25.34],
],
},
},
{
type: 'Feature',
properties: { customProperty: 2 },
geometry: {
type: 'Point',
coordinates: [55.4, 25.3],
},
},
],
};
const source = new mapgl.GeoJsonSource(map, {
data,
attributes: {
purpose: 'heatmap',
},
});
const layer = {
id: 'my-heatmap-layer', // Each layer ID must be unique
// Data filtering logic
filter: [
'match',
['sourceAttr', 'purpose'],
['heatmap'],
true, // Result if value of purpose source attribute equals "heatmap"
false, // Result if not
],
// Drawing object type
type: 'heatmap',
// Style of drawing object
style: {
color: [
'interpolate',
['linear'],
['heatmap-density'],
0,
'rgba(0, 0, 0, 0)',
0.2,
'rgba(172, 32, 135, 1)',
0.4,
'rgba(255, 154, 0, 1)',
0.6,
'rgba(255, 252, 0, 1)',
0.8,
'rgba(255, 255, 63, 1)',
1,
'rgba(255, 255, 255, 1)',
],
radius: 50,
weight: ['get', 'customProperty'],
intensity: 0.8,
opacity: 0.8,
downscale: 1,
},
};
map.on('styleload', () => {
map.addLayer(layer);
});
</script>
</body>
</html>