Тепловая карта (Heatmap) — это способ визуализации большого количества точечных данных, при котором отдельные объекты отображаются не в виде маркеров, а как области различной интенсивности. Чем выше концентрация объектов или больше их вес, тем ярче и насыщеннее становится соответствующий участок карты.
В OpenLayers тепловые карты используются для отображения:
Тепловые карты особенно полезны в ситуациях, когда на карте присутствуют тысячи и десятки тысяч точек, из-за чего использование обычных маркеров становится неэффективным.
В OpenLayers тепловая карта реализована через класс
Heatmap.
Импорт:
import Heatmap from 'ol/layer/Heatmap.js';
Тепловой слой строится на основе векторного источника данных. Каждая точка получает некоторый уровень влияния, после чего движок визуализации вычисляет суммарную интенсивность в различных областях карты.
Схема работы выглядит следующим образом:
Точки → Векторный источник → Heatmap → Растеризация → Карта
Чем ближе точки расположены друг к другу, тем выше плотность и ярче результирующее отображение.
Минимальный пример:
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';
import Heatmap from 'ol/layer/Heatmap.js';
import VectorSource from 'ol/source/Vector.js';
import Feature from 'ol/Feature.js';
import Point from 'ol/geom/Point.js';
const source = new VectorSource();
source.addFeature(
new Feature({
geometry: new Point([4180000, 7500000])
})
);
source.addFeature(
new Feature({
geometry: new Point([4200000, 7520000])
})
);
const heatmapLayer = new Heatmap({
source: source
});
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}),
heatmapLayer
],
view: new View({
center: [4190000, 7510000],
zoom: 8
})
});
Каждая точка автоматически участвует в построении тепловой карты.
Свойство blur определяет степень размытия каждой
точки.
const heatmapLayer = new Heatmap({
source: source,
blur: 20
});
Влияние параметра:
| Значение | Результат |
|---|---|
| 5 | Резкие области |
| 10 | Небольшое размытие |
| 20 | Стандартный вариант |
| 30 | Мягкие переходы |
| 50+ | Очень широкое распределение |
Пример:
const heatmapLayer = new Heatmap({
source: source,
blur: 40
});
Большие значения позволяют визуализировать общие тенденции, а небольшие — локальные скопления объектов.
Радиус определяет область влияния каждой точки.
const heatmapLayer = new Heatmap({
source: source,
radius: 15
});
Сравнение значений:
radius: 5
Компактные пятна.
radius: 20
Средняя зона воздействия.
radius: 50
Широкое распределение интенсивности.
Часто параметры radius и blur используются
совместно:
const heatmapLayer = new Heatmap({
source: source,
radius: 25,
blur: 30
});
Не все точки имеют одинаковую значимость.
Например:
В таком случае каждая точка должна иметь собственный вес.
Создание объектов:
const feature = new Feature({
geometry: new Point(coordinates)
});
feature.set('weight', 0.8);
source.addFeature(feature);
Настройка тепловой карты:
const heatmapLayer = new Heatmap({
source: source,
weight: function(feature) {
return feature.get('weight');
}
});
Вес должен находиться в диапазоне:
0.0 → 1.0
Где:
0.0 = минимальное влияние
1.0 = максимальное влияние
Часто исходные данные содержат реальные значения:
{
count: 350
}
Необходимо преобразовать их в диапазон от 0 до 1.
Пример:
const maxValue = 1000;
const heatmapLayer = new Heatmap({
source: source,
weight: function(feature) {
return feature.get('count') / maxValue;
}
});
Более безопасный вариант:
const heatmapLayer = new Heatmap({
source: source,
weight: function(feature) {
const value = feature.get('count') / 1000;
return Math.min(value, 1);
}
});
На практике данные обычно загружаются из GeoJSON.
Пример:
import GeoJSON from 'ol/format/GeoJSON.js';
import VectorSource from 'ol/source/Vector.js';
const source = new VectorSource({
url: '/data/points.geojson',
format: new GeoJSON()
});
Создание слоя:
const heatmapLayer = new Heatmap({
source: source,
radius: 20,
blur: 15
});
Структура GeoJSON:
{
"type": "Feature",
"properties": {
"weight": 0.7
},
"geometry": {
"type": "Point",
"coordinates": [37.62, 55.75]
}
}
Использование свойства:
const heatmapLayer = new Heatmap({
source: source,
weight: feature => feature.get('weight')
});
Параметры можно изменять после создания слоя.
Изменение радиуса:
heatmapLayer.setRadius(40);
Изменение размытия:
heatmapLayer.setBlur(25);
Пример со слайдером:
<input type="range" id="radius" min="1" max="100">
document
.getElementById('radius')
.addEventListener('input', function() {
heatmapLayer.setRadius(
Number(this.value)
);
});
Такой подход позволяет создавать интерактивные панели настройки визуализации.
По умолчанию OpenLayers использует стандартную цветовую палитру.
Возможна установка собственного градиента:
const heatmapLayer = new Heatmap({
source: source,
gradient: [
'#0000ff',
'#00ffff',
'#00ff00',
'#ffff00',
'#ff0000'
]
});
Интерпретация:
Синий → низкая плотность
Голубой → умеренная плотность
Зелёный → средняя плотность
Жёлтый → высокая плотность
Красный → максимальная плотность
Иногда требуется использовать один цвет.
Пример:
const heatmapLayer = new Heatmap({
source: source,
gradient: [
'rgba(255,255,255,0)',
'rgba(0,128,255,1)'
]
});
Такой вариант часто применяется в корпоративных системах аналитики.
gradient: [
'#001f3f',
'#0074D9',
'#7FDBFF'
]
gradient: [
'#ffffcc',
'#ffeda0',
'#feb24c',
'#fd8d3c',
'#f03b20',
'#bd0026'
]
gradient: [
'#edf8e9',
'#bae4b3',
'#74c476',
'#31a354',
'#006d2c'
]
Выбор цветовой схемы зависит от характера отображаемых данных.
Тепловые карты часто используются совместно с потоковыми данными.
Добавление новой точки:
function addPoint(x, y, weight) {
const feature = new Feature({
geometry: new Point([x, y])
});
feature.set('weight', weight);
source.addFeature(feature);
}
Периодическое обновление:
setInterval(() => {
addPoint(
randomX(),
randomY(),
Math.random()
);
}, 1000);
После добавления объектов слой автоматически перерисовывается.
Для визуализации текущей активности часто требуется ограничивать историю данных.
Пример:
setInterval(() => {
const features = source.getFeatures();
if (features.length > 5000) {
source.removeFeature(features[0]);
}
}, 1000);
Подобный механизм используется для отображения:
Тепловые карты способны отображать десятки тысяч точек, однако существуют ограничения.
Основные рекомендации:
Большой радиус увеличивает вычислительную нагрузку.
Плохо:
radius: 100
Лучше:
radius: 15
Вместо:
100000 точек
целесообразно использовать:
10000–30000 точек
при отображении в браузере.
Если исходный набор содержит миллионы записей, агрегацию лучше выполнять на сервере.
Тепловая карта может использоваться вместе с векторными слоями.
Пример:
layers: [
osmLayer,
heatmapLayer,
vectorLayer
]
Распространённая схема:
OSM
↓
Heatmap
↓
Маркеры объектов
При таком подходе пользователь одновременно видит:
Иногда необходимо визуализировать несколько типов событий.
Создание отдельных источников:
const accidentsSource = new VectorSource();
const trafficSource = new VectorSource();
Создание слоёв:
const accidentsHeatmap = new Heatmap({
source: accidentsSource
});
const trafficHeatmap = new Heatmap({
source: trafficSource
});
Для каждого слоя можно использовать собственную палитру:
gradient: [
'#ffff00',
'#ff0000'
]
и
gradient: [
'#00ffff',
'#0000ff'
]
Такой подход позволяет визуализировать несколько независимых наборов данных одновременно.
Допустим, имеется набор координат пользователей интернет-магазина.
Каждая запись содержит:
{
longitude: 37.62,
latitude: 55.75,
visits: 250
}
Создание объекта:
const feature = new Feature({
geometry: new Point(
fromLonLat([
item.longitude,
item.latitude
])
)
});
feature.set(
'weight',
item.visits / 1000
);
Настройка слоя:
const heatmapLayer = new Heatmap({
source: source,
radius: 25,
blur: 20,
weight: feature =>
Math.min(
feature.get('weight'),
1
)
});
Результат позволяет быстро определить:
Несмотря на высокую наглядность, тепловые карты имеют ряд особенностей:
По этой причине тепловые карты часто используются совместно с кластеризацией, маркерами и аналитическими панелями, формируя комплексную систему пространственной визуализации данных в приложениях на базе OpenLayers.