Тепловая карта | MapGL | 2GIS Documentation
MapGL JS API

Слой тепловой карты

MapGL API позволяет визуализировать GeoJSON данные в виде тепловой карты, которая используется для отображения большого количества точек в виде градиента цвета в соответствии с их плотностью на карте и заданной палитрой.

Чтобы создать слой тепловой карты, необходимо подключить источник GeoJSON данных к карте. Более подробную информацию можно найти в примерах по работе с GeoJSON. Для получения корректной визуализации GeoJSON данные должны состоять из типов Point или MultiPoint:

const data = {
    type: 'FeatureCollection',
    features: [
        {
            type: 'Feature',
            properties: { bar: 1 },
            geometry: {
                type: 'MultiPoint',
                coordinates: [
                    [55.44, 25.34],
                    [55.43, 25.37],
                    [55.41, 25.34],
                ],
            },
        },
        {
            type: 'Feature',
            properties: { bar: 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',
    filter: ['match', ['sourceAttr', 'purpose'], ['heatmap'], true, false],
    type: 'heatmap',
    style: {
        weight: ['get', 'bar'],
        radius: 50,
        opacity: 0.8,
        intensity: 0.8,
        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)',
        ],
        downscale: 1,
    },
};

Разберем подробнее каждое из стилевых свойств слоя:

  • color: палитра цветов тепловой карты в зависимости от плотности, значения которой находятся в диапазоне от 0 до 1. Важно заметить, что при нулевой плотности необходимо задавать прозрачные цвета. Это создаст эффект размытия по краям точки и предотвратит закрашивание цветом всей карты.

  • radius: радиус точки в пикселях. Визуально итоговый размер будет зависеть от заданной палитры и значений интенсивности и веса.

  • weight: множитель функции ядра, применяющийся к конкретной точке. Если значение задано константой, то оно будет применено ко всем точкам. Также оно может быть задано через get выражение как в примере выше. Или через interpolate выражение в зависимости от значения свойства в properties объекта, например, ['interpolate', ['linear'], ['get', 'bar'], 0, 0, 4, 2]. Чем больше значение множителя, тем выше значение плотности, образованной функцией ядра точки.

  • intensity: множитель функции ядра, применяющийся ко всем точкам. Чем больше значение множителя, тем выше значение плотности, образованной функцией ядра точек.

  • opacity: параметр, задающий уровень непрозрачности тепловой карты.

  • downscale: делитель разрешения текстуры тепловой карты. Чем больше его значение, тем выше производительность при отрисовке и хуже качество итогового изображения тепловой карты, и наоборот. При этом при значениях делителя больше 1 возможны эффекты мерцания тепловой карты при перемещении, наклоне, повороте и изменении масштаба карты.

Далее добавляем созданный стилевой слой к текущему стилю карты. При этом дожидаемся окончания его загрузки:

map.on('styleload', () => {
    map.addLayer(layer);
});
<!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: { bar: 1 },
                        geometry: {
                            type: 'MultiPoint',
                            coordinates: [
                                [55.44, 25.34],
                                [55.43, 25.37],
                                [55.41, 25.34],
                            ],
                        },
                    },
                    {
                        type: 'Feature',
                        properties: { bar: 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: {
                    weight: ['get', 'bar'],
                    radius: 50,
                    opacity: 0.8,
                    intensity: 0.8,
                    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)',
                    ],
                    downscale: 1,
                },
            };

            map.on('styleload', () => {
                map.addLayer(layer);
            });
        </script>
    </body>
</html>