Создание heatmap слоя

Heatmap-слой в MapLibre GL JS строится на основе пространственных точечных данных. Основным форматом выступает GeoJSON с типом FeatureCollection, где каждая точка содержит координаты и, при необходимости, дополнительные числовые атрибуты, влияющие на интенсивность отображения.

Типовая структура источника данных:

map.addSource('points', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        properties: {
          magnitude: 1.2
        },
        geometry: {
          type: 'Point',
          coordinates: [71.4304, 51.1281]
        }
      },
      {
        type: 'Feature',
        properties: {
          magnitude: 2.5
        },
        geometry: {
          type: 'Point',
          coordinates: [71.4450, 51.1400]
        }
      }
    ]
  }
});

Ключевое значение имеет плотность точек и наличие числового признака, используемого для взвешивания влияния каждой точки на итоговую визуализацию.


Создание heatmap слоя

Heatmap-слой добавляется через map.addLayer с типом heatmap. Он не рисует отдельные геометрические примитивы, а формирует непрерывное распределение плотности на основе ближайших точек.

Базовая конфигурация:

map.addLayer({
  id: 'heatmap-layer',
  type: 'heatmap',
  source: 'points',
  paint: {
    'heatmap-weight': 1,
    'heatmap-intensity': 1,
    'heatmap-radius': 20,
    'heatmap-opacity': 0.8
  }
});

На этом уровне формируется простая тепловая карта, где каждая точка имеет одинаковый вклад.


Взвешивание точек (heatmap-weight)

heatmap-weight управляет вкладом каждой точки в итоговую плотность. Значение может быть константой или выражением, основанным на свойствах объекта.

Пример с использованием свойства magnitude:

'heatmap-weight': [
  'interpolate',
  ['linear'],
  ['get', 'magnitude'],
  0, 0,
  6, 1
]

Принцип работы:

  • низкие значения уменьшают влияние точки
  • высокие значения усиливают локальную плотность
  • интерполяция позволяет плавно нормализовать диапазон

Интенсивность тепловой карты (heatmap-intensity)

Параметр управляет общей «силой свечения» слоя. Особенно важен при масштабировании карты, поскольку плотность точек визуально уменьшается при увеличении масштаба.

'heatmap-intensity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0, 1,
  9, 3
]

Особенности:

  • низкий zoom требует меньшей интенсивности
  • высокий zoom усиливает детализацию
  • позволяет компенсировать визуальное разрежение данных

Радиус влияния точек (heatmap-radius)

Радиус определяет область, в пределах которой точка влияет на соседние пиксели.

'heatmap-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0, 2,
  9, 30
]

Практическое поведение:

  • малый радиус формирует «зернистую» карту
  • большой радиус создаёт сглаженные пятна
  • увеличение масштаба обычно сопровождается ростом радиуса

Прозрачность слоя (heatmap-opacity)

Контроль видимости heatmap-слоя часто используется для плавного перехода к точечному представлению данных на высоких зумах.

'heatmap-opacity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  7, 1,
  10, 0
]

Такой подход позволяет:

  • скрывать heatmap на детальном уровне
  • комбинировать с circle-слоем
  • избегать визуального конфликта слоёв

Цветовая шкала heatmap (heatmap-color)

Цветовое представление задаётся через интерполяцию плотности. Значение нормализуется в диапазоне от 0 до 1.

'heatmap-color': [
  'interpolate',
  ['linear'],
  ['heatmap-density'],
  0, 'rgba(33,102,172,0)',
  0.2, 'rgb(103,169,207)',
  0.4, 'rgb(209,229,240)',
  0.6, 'rgb(253,219,199)',
  0.8, 'rgb(239,138,98)',
  1, 'rgb(178,24,43)'
]

Принцип формирования:

  • прозрачные синие зоны соответствуют низкой плотности
  • переход к тёплым цветам отражает рост концентрации
  • максимальные значения окрашиваются в насыщенные красные оттенки

Масштабирование и адаптация к zoom

Heatmap в MapLibre GL JS чувствителен к масштабу карты. Для корректного поведения параметры часто связываются с уровнем zoom.

Типичная стратегия:

  • на малых zoom — большой радиус, высокая интенсивность
  • на средних zoom — баланс между детализацией и сглаживанием
  • на больших zoom — снижение opacity и переход к точечному слою

Пример комплексной настройки:

'heatmap-radius': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0, 10,
  12, 40
],
'heatmap-intensity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  0, 1,
  12, 4
],
'heatmap-opacity': [
  'interpolate',
  ['linear'],
  ['zoom'],
  10, 1,
  14, 0
]

Комбинирование heatmap с точечным слоем

Практически всегда heatmap используется совместно с circle-слоем, который отображает отдельные точки при высоком приближении.

map.addLayer({
  id: 'point-layer',
  type: 'circle',
  source: 'points',
  paint: {
    'circle-radius': 4,
    'circle-color': 'rgba(0, 0, 0, 0.7)',
    'circle-stroke-width': 1,
    'circle-stroke-color': '#fff',
    'circle-opacity': [
      'interpolate',
      ['linear'],
      ['zoom'],
      7, 0,
      10, 1
    ]
  }
});

Логика взаимодействия слоёв:

  • heatmap отображает агрегированную плотность
  • circle-слой показывает точные координаты
  • opacity обеспечивает плавный переход между режимами

Оптимизация производительности

При работе с большими наборами данных heatmap требует внимания к производительности рендеринга.

Ключевые подходы:

Ограничение объёма GeoJSON

Большие массивы точек могут замедлять отрисовку. Применяется серверная агрегация или тайловые источники.

Использование vector tiles

Вместо GeoJSON используется vector source:

map.addSource('tiles', {
  type: 'vector',
  url: 'mapbox://...'
});

Упрощение свойств

Минимизация вычисляемых выражений в paint снижает нагрузку на GPU.

Кластеризация как альтернатива

Хотя heatmap и clustering решают разные задачи, кластеризация может снижать плотность данных до рендеринга:

map.addSource('points', {
  type: 'geojson',
  data: geojsonData,
  cluster: true,
  clusterRadius: 40
});

Поведение плотности (heatmap-density)

heatmap-density — внутренний нормализованный параметр, отражающий локальную концентрацию точек.

Он не задаётся вручную, а вычисляется движком на основе:

  • расстояния между точками
  • веса точек
  • радиуса влияния
  • текущего масштаба

Используется исключительно в стилях цвета:

['heatmap-density']

Адаптация под разные типы данных

Heatmap применяется к разным категориям пространственных данных:

  • события и инциденты
  • пользовательская активность
  • погодные измерения
  • транспортные потоки
  • телеметрия устройств

Для каждого типа данных важна корректная нормализация значений веса, иначе визуализация становится искажённой.


Типичные ошибки при настройке heatmap

Распространённые проблемы возникают из-за неправильной конфигурации слоёв:

  • отсутствие нормализации heatmap-weight
  • слишком высокий радиус на малом zoom
  • одинаковая интенсивность на всех уровнях масштаба
  • отсутствие плавного перехода к circle-слою
  • перегруженные GeoJSON-источники

Взаимодействие с фильтрацией данных

Heatmap может динамически изменяться через setFilter, что позволяет ограничивать отображаемые точки:

map.setFilter('heatmap-layer', [
  '>=',
  ['get', 'magnitude'],
  2
]);

Такой подход используется для:

  • отображения только значимых событий
  • анализа диапазонов значений
  • интерактивной сегментации данных

Управление визуальной плотностью

Финальное качество heatmap определяется балансом трёх параметров:

  • radius
  • intensity
  • weight

Их совместная настройка позволяет управлять:

  • резкостью переходов между зонами
  • читаемостью плотных областей
  • уровнем детализации на разных zoom

Комбинированная настройка часто выполняется через interpolate и step выражения для обеспечения плавного поведения при масштабировании карты.