Deck.gl и Leaflet решают разные задачи визуализации геоданных. Leaflet предоставляет лёгкую и удобную систему работы с картами, тайлами, маркерами и слоями, тогда как Deck.gl ориентирован на высокопроизводительную GPU-визуализацию больших объёмов пространственных данных через WebGL.
Интеграция двух библиотек позволяет объединить преимущества обеих технологий:
Типичная архитектура выглядит следующим образом:
Leaflet Map
├── TileLayer
├── Marker Layers
├── GeoJSON Layers
└── Deck.gl Layer
├── ScatterplotLayer
├── ArcLayer
├── HexagonLayer
├── GridLayer
└── PolygonLayer
В такой конфигурации Leaflet отвечает за карту и навигацию, а Deck.gl рисует данные поверх карты через отдельный WebGL-канвас.
Для интеграции используется пакет:
npm install @deck.gl/core
npm install @deck.gl/layers
npm install @deck.gl/leaflet
npm install leaflet
Главным элементом выступает класс:
LeafletLayer
Он создаёт мост между жизненным циклом Leaflet и системой рендеринга Deck.gl.
Импорт:
import L from 'leaflet';
import { LeafletLayer } from '@deck.gl/leaflet';
import { ScatterplotLayer } from '@deck.gl/layers';
Базовая карта создаётся стандартным способом.
const map = L.map('map').setView(
[55.751244, 37.618423],
10
);
L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: '© OpenStreetMap'
}
).addTo(map);
HTML-контейнер:
<div id="map"></div>
CSS:
#map {
width: 100%;
height: 600px;
}
После этого карта полностью управляется Leaflet.
Создадим слой точек.
const points = [
{
position: [37.62, 55.75],
size: 100
},
{
position: [37.70, 55.80],
size: 200
}
];
Описание слоя:
const scatterplotLayer =
new ScatterplotLayer({
id: 'scatter',
data: points,
getPosition: d => d.position,
getRadius: d => d.size,
getFillColor: [255, 0, 0],
radiusUnits: 'meters',
pickable: true
});
Создание LeafletLayer:
const deckLayer = new LeafletLayer({
layers: [scatterplotLayer]
});
Подключение:
map.addLayer(deckLayer);
После добавления точки отображаются поверх тайлов Leaflet.
Одной из самых сложных задач интеграции является синхронизация камеры.
В обычном приложении Deck.gl самостоятельно управляет объектом ViewState:
{
longitude,
latitude,
zoom,
pitch,
bearing
}
При работе с Leaflet управление передаётся карте Leaflet.
Каждый раз при:
LeafletLayer получает обновлённые параметры и автоматически передаёт их в Deck.gl.
Разработчику не требуется самостоятельно вычислять:
longitude
latitude
zoom
Все параметры берутся из текущего состояния Leaflet.
Слои могут изменяться динамически.
Например, после получения новых данных:
function updatePoints(data) {
deckLayer.setProps({
layers: [
new ScatterplotLayer({
id: 'scatter',
data,
getPosition: d => d.position,
getRadius: 100,
getFillColor: [0, 128, 255]
})
]
});
}
Deck.gl выполнит внутреннее сравнение свойств и перерисует только изменившиеся части сцены.
Часто требуется отображать разные типы объектов одновременно.
import {
ScatterplotLayer,
ArcLayer
} from '@deck.gl/layers';
Создание слоёв:
const pointsLayer =
new ScatterplotLayer({
id: 'points',
data: points,
getPosition: d => d.position,
getFillColor: [255, 140, 0],
getRadius: 80
});
const arcsLayer =
new ArcLayer({
id: 'arcs',
data: routes,
getSourcePosition:
d => d.source,
getTargetPosition:
d => d.target,
getSourceColor:
[0, 128, 255],
getTargetColor:
[255, 0, 0],
getWidth: 5
});
Передача в LeafletLayer:
deckLayer.setProps({
layers: [
pointsLayer,
arcsLayer
]
});
Порядок в массиве определяет порядок отрисовки.
Deck.gl поддерживает выбор объектов через механизм picking.
Включение:
pickable: true
Обработка наведения:
new ScatterplotLayer({
id: 'points',
data,
pickable: true,
onHover: info => {
if (info.object) {
console.log(info.object);
}
}
});
Обработка клика:
new ScatterplotLayer({
id: 'points',
data,
pickable: true,
onClick: info => {
console.log(info.object);
}
});
Объект info содержит:
{
object,
x,
y,
coordinate,
index,
layer
}
Это позволяет создавать всплывающие окна, панели информации и другие элементы интерфейса.
Часто события Deck.gl используются для открытия Popup Leaflet.
onClick: info => {
if (!info.object) {
return;
}
const [lng, lat] =
info.object.position;
L.popup()
.setLatLng([lat, lng])
.setContent(
info.object.name
)
.openOn(map);
}
В результате визуализация остаётся в Deck.gl, а пользовательский интерфейс строится средствами Leaflet.
Deck.gl способен отображать GeoJSON поверх Leaflet.
import {
GeoJsonLayer
} from '@deck.gl/layers';
Создание слоя:
const geoLayer =
new GeoJsonLayer({
id: 'geojson',
data: geojson,
stroked: true,
filled: true,
pointRadiusMinPixels: 5,
getLineColor:
[0, 0, 0],
getFillColor:
[0, 150, 255, 120],
getPointRadius: 50
});
Добавление:
deckLayer.setProps({
layers: [geoLayer]
});
Преимущество перед Leaflet GeoJSON заключается в том, что визуализация выполняется через GPU и значительно лучше масштабируется на больших объёмах данных.
Одно из основных преимуществ Deck.gl — возможность отображения очень больших наборов данных.
Пример:
const layer =
new ScatterplotLayer({
id: 'big-data',
data: millionPoints,
getPosition:
d => d.coordinates,
getRadius: 20,
getFillColor:
[255, 0, 0]
});
Для Leaflet такое количество объектов стало бы серьёзной нагрузкой.
Deck.gl использует:
Поэтому производительность остаётся высокой даже при сотнях тысяч и миллионах объектов.
Для анализа плотности данных часто применяется агрегирование.
import {
HexagonLayer
} from '@deck.gl/aggregation-layers';
Создание слоя:
const layer =
new HexagonLayer({
id: 'hex',
data: points,
getPosition:
d => d.position,
radius: 500,
elevationScale: 50,
extruded: true
});
Добавление:
deckLayer.setProps({
layers: [layer]
});
Карта Leaflet остаётся двумерной, а Deck.gl создаёт трёхмерную визуализацию поверх неё.
Тепловые карты хорошо подходят для анализа концентрации объектов.
import {
HeatmapLayer
} from '@deck.gl/aggregation-layers';
Пример:
const heatmap =
new HeatmapLayer({
id: 'heatmap',
data: points,
getPosition:
d => d.position,
getWeight:
d => d.weight
});
Подключение:
deckLayer.setProps({
layers: [heatmap]
});
GPU-агрегация позволяет строить тепловые карты практически в реальном времени.
Отображение полигонов:
import {
PolygonLayer
} from '@deck.gl/layers';
Создание:
const polygons =
new PolygonLayer({
id: 'districts',
data,
getPolygon:
d => d.polygon,
getFillColor:
[0, 120, 255, 80],
getLineColor:
[0, 0, 0],
lineWidthMinPixels: 2,
pickable: true
});
Подходит для отображения:
Leaflet использует концепцию панелей (panes).
Deck.gl слой можно поместить в нужную панель.
const deckLayer =
new LeafletLayer({
pane: 'overlayPane',
layers: [layer]
});
Создание собственной панели:
map.createPane('deckPane');
Настройка:
map.getPane('deckPane')
.style.zIndex = 500;
Использование:
const deckLayer =
new LeafletLayer({
pane: 'deckPane',
layers: [layer]
});
Это позволяет точно контролировать расположение относительно маркеров, всплывающих окон и других элементов Leaflet.
Общая прозрачность слоя:
new ScatterplotLayer({
id: 'points',
data,
opacity: 0.5
});
Или через альфа-канал цвета:
getFillColor: [
255,
0,
0,
120
]
Комбинация прозрачности особенно полезна при наложении нескольких аналитических слоёв.
При удалении слоя необходимо освобождать ресурсы.
Удаление из карты:
map.removeLayer(deckLayer);
Или полное уничтожение:
deckLayer.remove();
Deck.gl автоматически освобождает:
Это предотвращает утечки памяти при длительной работе приложения.
Несмотря на удобство интеграции, существуют некоторые ограничения.
Leaflet является преимущественно двумерной системой.
Поэтому возможности:
pitch
bearing
либо отсутствуют, либо ограничены по сравнению с полноценным использованием Deck.gl совместно с Mapbox или MapLibre.
События мыши сначала обрабатываются Leaflet.
При сложных сценариях может потребоваться настройка:
pointer-events
или дополнительная координация обработчиков.
Хотя Deck.gl способен отображать экструзии и трёхмерные объекты, сама карта Leaflet остаётся плоской.
Для полноценных трёхмерных сцен обычно используют:
Интеграция Deck.gl с Leaflet позволяет сохранить простоту классической веб-карты и одновременно получить производительность WebGL, необходимую для визуализации больших пространственных наборов данных и построения сложных аналитических представлений.