Deck.gl overlay

Связка Mapbox GL JS и Deck.gl формирует архитектуру, в которой Mapbox отвечает за рендеринг базовой карты и управление камерой, а Deck.gl — за высокоуровневую визуализацию больших наборов данных поверх карты. Такая модель позволяет разделить ответственность: карта остаётся интерактивной и быстрой, а сложные визуальные слои выполняются WebGL-движком Deck.gl.

Основная идея заключается в использовании Deck.gl как оверлея, синхронизированного с состоянием камеры Mapbox GL JS. При каждом изменении viewport данные пересчитываются и перерисовываются в соответствии с текущим состоянием карты.

Архитектурная модель оверлея

Deck.gl не заменяет Mapbox GL JS, а встраивается в его рендеринг как дополнительный слой. В зависимости от версии API используются два основных подхода:

  • MapboxOverlay (современный способ интеграции)
  • кастомный CustomLayerInterface (низкоуровневый метод Mapbox)

В обоих случаях Deck.gl получает матрицы камеры и параметры вида от Mapbox, после чего строит собственную сцену WebGL.

Ключевые элементы архитектуры:

  • Mapbox GL JS — управление тайлами, базовой картой, взаимодействием
  • Deck.gl — WebGL-рендеринг аналитических и визуальных слоёв
  • Camera synchronization — согласование параметров вида
  • Layer system Deck.gl — декларативное описание визуализаций

Модель данных и слойная абстракция Deck.gl

Deck.gl работает с концепцией слоёв (layers), каждый из которых описывает, как визуализировать набор данных. Каждый слой является иммутабельной декларацией:

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

Типовые слои:

  • ScatterplotLayer — точки
  • GeoJsonLayer — геометрии GeoJSON
  • LineLayer — линии маршрутов
  • PolygonLayer — полигоны
  • ArcLayer — дуги между точками

Каждый слой оптимизирован под GPU и использует WebGL для батчинга отрисовки.

Подключение Deck.gl через MapboxOverlay

Современный способ интеграции основан на объекте MapboxOverlay, который связывает экземпляр Deck.gl с Mapbox GL JS.

import mapboxgl from 'mapbox-gl';
import { MapboxOverlay } from '@deck.gl/mapbox';
import { ScatterplotLayer } from '@deck.gl/layers';

mapboxgl.accessToken = 'YOUR_TOKEN';

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/dark-v11',
  center: [37.618423, 55.751244],
  zoom: 10
});

const deckOverlay = new MapboxOverlay({
  layers: [
    new ScatterplotLayer({
      id: 'scatter',
      data: [
        { position: [37.62, 55.75], size: 100 }
      ],
      getPosition: d => d.position,
      getRadius: d => d.size,
      getFillColor: [255, 140, 0]
    })
  ]
});

map.addControl(deckOverlay);

В этом режиме Deck.gl полностью синхронизируется с картой, включая:

  • zoom
  • bearing
  • pitch
  • projection matrix

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

Низкоуровневая интеграция через Mapbox Custom Layer Interface позволяет вручную управлять жизненным циклом WebGL-контекста.

const deckLayer = {
  id: 'custom-deck',
  type: 'custom',
  renderingMode: '3d',

  onAdd: function (map, gl) {
    this.deck = new Deck({
      gl,
      layers: [
        new ScatterplotLayer({
          data: [],
          getPosition: d => d.position,
          getRadius: 50
        })
      ]
    });
  },

  render: function (gl, matrix) {
    this.deck.setProps({
      viewState: {
        longitude: map.getCenter().lng,
        latitude: map.getCenter().lat,
        zoom: map.getZoom(),
        bearing: map.getBearing(),
        pitch: map.getPitch()
      }
    });

    this.deck.redraw();
  }
};

map.on('load', () => {
  map.addLayer(deckLayer);
});

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

Синхронизация камеры и координатная система

Mapbox GL JS использует Web Mercator projection, и Deck.gl работает в той же системе координат, что обеспечивает прямую совместимость.

Основные параметры синхронизации:

  • longitude
  • latitude
  • zoom
  • bearing
  • pitch

Deck.gl преобразует географические координаты в экранные через матрицы:

  • view matrix
  • projection matrix
  • model matrix

При каждом движении карты пересчитываются трансформации, что обеспечивает плавную интерактивность.

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

Deck.gl рассчитан на обработку больших массивов данных (сотни тысяч и миллионы объектов). Основные механизмы оптимизации:

Батчинг и instancing

WebGL instancing позволяет рендерить множество объектов одним draw call.

Spatial indexing

Некоторые слои используют spatial indexing для отсечения невидимых объектов.

Attribute buffers

Данные передаются в GPU через буферы, минимизируя JavaScript-вычисления во время рендера.

Dirty checking

Перерисовка происходит только при изменении props слоя.

Работа с GeoJSON слоями

GeoJsonLayer является одним из самых гибких инструментов для визуализации пространственных данных.

import { GeoJsonLayer } from '@deck.gl/layers';

const layer = new GeoJsonLayer({
  id: 'geojson',
  data: 'https://example.com/data.geojson',
  stroked: true,
  filled: true,
  getFillColor: [0, 128, 255],
  getLineColor: [255, 255, 255],
  lineWidthMinPixels: 2
});

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

  • поддержка FeatureCollection
  • стилизация по атрибутам
  • интерактивные события
  • фильтрация объектов

Интерактивность и события

Deck.gl предоставляет event system для обработки пользовательских взаимодействий:

  • onClick
  • onHover
  • onDrag

Пример обработки:

new ScatterplotLayer({
  data,
  pickable: true,
  onClick: info => {
    const object = info.object;
    console.log(object);
  }
});

Hit-testing выполняется на GPU, что позволяет быстро определять объекты под курсором.

3D-визуализация поверх карты

Deck.gl поддерживает полноценные 3D-слои, включая высотные экструдированные полигоны и геометрии.

new PolygonLayer({
  data,
  extruded: true,
  getElevation: d => d.height,
  getFillColor: [200, 0, 80]
});

При включённом pitch Mapbox GL JS сцена становится трёхмерной, а Deck.gl синхронно отрисовывает объекты в том же пространстве.

Управление состоянием слоёв

Deck.gl использует immutable-подход: любые изменения данных или стиля создают новую версию слоя.

Основные параметры обновления:

  • изменение data пересоздаёт буферы
  • изменение функций доступа (get*) требует пересчёта атрибутов
  • изменение стиля влияет только на фрагментный шейдер

Такой подход снижает количество побочных эффектов и упрощает прогнозирование рендера.

Смешивание Mapbox слоёв и Deck.gl

Deck.gl оверлей не конфликтует с нативными слоями Mapbox GL JS. Порядок рендеринга контролируется:

  • через порядок добавления слоёв
  • через beforeId (в Mapbox)
  • через z-index внутри Deck.gl сцен

Типичная схема:

  • базовая карта Mapbox
  • тематические слои Mapbox (labels, roads)
  • аналитические слои Deck.gl

Координация масштабируемости данных

При увеличении объёма данных используются стратегии:

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

Deck.gl может работать как с raw data, так и с tile-based источниками.

Использование бинарных форматов

Для повышения производительности поддерживаются бинарные форматы:

  • Arrow
  • FlatBuffers
  • binary GeoJSON

Это снижает нагрузку на парсинг и уменьшает время передачи данных в GPU.

Событийная модель взаимодействия с картой

Mapbox GL JS передаёт события движения камеры:

  • move
  • zoom
  • rotate
  • pitch

Deck.gl подписывается на эти события через overlay и пересчитывает viewState. Это обеспечивает синхронность между картой и визуализацией без ручного обновления состояния.

WebGL контекст и управление ресурсами

Deck.gl может использовать:

  • собственный WebGL context
  • контекст Mapbox GL JS

При интеграции через overlay используется общий контекст, что снижает накладные расходы и исключает дублирование ресурсов GPU.

Ресурсы управляются через:

  • lifecycle hooks (onAdd, onRemove)
  • автоматический cleanup буферов
  • перераспределение текстур

Типовые ошибки интеграции

  • рассинхронизация камеры при ручном управлении viewState
  • создание слоёв вне жизненного цикла Mapbox
  • конфликт WebGL контекстов
  • чрезмерное количество draw calls при неправильной конфигурации атрибутов
  • отсутствие memoization функций доступа (getPosition, getColor)

Масштабирование визуализаций

При работе с большими данными используется комбинация:

  • spatial filtering
  • level-of-detail (LOD)
  • GPU instancing
  • tile-based streaming

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