Тепловая карта
С помощью источника данных GeoJSON и стилей карты на карте можно нарисовать тепловой слой: набор градиентных кругов, которые сливаются в единый объект при приближении к друг другу.
Чтобы это сделать, нужно подключить источник данных с помощью метода GeoJsonSource(), указав уникальный атрибут для этого источника (например, purpose: 'heatmap'
). Подключаемый GeoJSON должен состоять только из объектов Point
и MultiPoint
(центры кругов).
Важно
Тепловая карта не поддерживается в режиме отображения 3D-рельефа на карте.
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',
},
});
После этого нужно создать стиль для теплового слоя, указав для него тип heatmap и фильтр по указанному при подключении GeoJSON атрибуту (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);
});
Описание параметров:
color
- набор цветов для градиента, от периметра (0.0
) до центра круга (1.0
). Для периметра важно указать прозрачный цвет, иначе им будет закрашена вся карта.radius
- радиус круга в пикселях.weight
- интенсивность точки. Чем выше значение, тем больше размер центра круга (сильнее будут преобладать цвета ближе к1.0
из массиваcolor
). В качестве значения имеет смысл указывать только ExtractorExpression или InterpolateExpression, используя одно из свойств объекта, иначе интенсивность будет применена ко всем точкам.intensity
- модификатор интенсивности для всех точек теплового слоя.opacity
- прозрачность слоя (1
- слой непрозрачный,0
- слой полностью прозрачный).downscale
- модификатор разрешения. Чем выше значение, тем ниже качество изображения теплового слоя и выше скорость отрисовки. По умолчанию1
.
<!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>