Структура минимального приложения

Архитектура приложения на Deck.gl строится вокруг нескольких ключевых сущностей: контейнера рендеринга, WebGL-контекста, слоя (Layer) и источника данных. Даже минимальная конфигурация предполагает наличие связки между картографической подложкой и визуализационным слоем, который отвечает за отрисовку геометрии.


Подключение библиотеки и базовая инициализация

Deck.gl может использоваться как самостоятельный WebGL-рендерер или в связке с картографическими библиотеками (Mapbox GL JS, Google Maps). В минимальном варианте без карты достаточно создать контейнер и экземпляр Deck.

Основные зависимости:

  • @deck.gl/core
  • один или несколько слоёв, например @deck.gl/layers

Простейшая структура подключения:

import {Deck} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';

Контейнер для рендеринга задаётся через DOM-элемент:

<div id="deck-container" style="width: 100vw; height: 100vh;"></div>

Инициализация экземпляра Deck

Центральная точка приложения — объект Deck. Он управляет WebGL-контекстом, жизненным циклом слоёв и обновлениями состояния.

const deckgl = new Deck({
  container: 'deck-container',
  initialViewState: {
    longitude: 37.6173,
    latitude: 55.7558,
    zoom: 10,
    pitch: 0,
    bearing: 0
  },
  controller: true,
  layers: []
});

Основные параметры:

  • container — DOM-узел или его идентификатор
  • initialViewState — начальная камера (обязательный элемент при использовании навигации)
  • controller — включение управления камерой (панорамирование, масштабирование)
  • layers — массив визуальных слоёв

Модель слоя как основа визуализации

Deck.gl не оперирует «сценой» в классическом смысле. Вместо этого используется декларативная модель слоёв.

Каждый слой описывает:

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

Пример базового слоя:

const layer = new ScatterplotLayer({
  id: 'scatter-layer',
  data: [
    {position: [37.6173, 55.7558], size: 1000}
  ],
  getPosition: d => d.position,
  getRadius: d => d.size,
  getFillColor: [255, 0, 0]
});

Передача слоёв в рендерер

Deck.gl использует реактивный подход: изменение массива слоёв приводит к перерасчёту сцены.

deckgl.setProps({
  layers: [layer]
});

Либо слои задаются сразу при инициализации:

const deckgl = new Deck({
  container: 'deck-container',
  initialViewState: {
    longitude: 37.6173,
    latitude: 55.7558,
    zoom: 10
  },
  controller: true,
  layers: [
    new ScatterplotLayer({
      id: 'points',
      data: [
        {position: [37.6173, 55.7558], size: 500}
      ],
      getPosition: d => d.position,
      getRadius: d => d.size,
      getFillColor: [0, 128, 255]
    })
  ]
});

Декларативная модель данных

Ключевой принцип Deck.gl — разделение данных и их визуального представления.

Слой не изменяет данные, а описывает, как их интерпретировать:

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

Пример с вычисляемыми свойствами:

getFillColor: d => d.value > 10 ? [255, 0, 0] : [0, 255, 0]

Обновление состояния приложения

Deck.gl не требует ручного перерисовывания сцены. Любое изменение конфигурации слоя или данных приводит к автоматическому обновлению.

Типичный цикл обновления:

const updatedLayer = new ScatterplotLayer({
  ...layer.props,
  data: newData
});

deckgl.setProps({
  layers: [updatedLayer]
});

Важный аспект: новый слой рассматривается как независимая сущность, даже при сохранении id.


Управление камерой

Параметр initialViewState задаёт начальную позицию, но дальнейшее управление осуществляется через обновление состояния.

deckgl.setProps({
  viewState: {
    longitude: 30.3351,
    latitude: 59.9343,
    zoom: 12,
    pitch: 45,
    bearing: 30
  }
});

Камера в Deck.gl является частью реактивной модели и может быть синхронизирована с внешними источниками состояния.


Минимальная структура проекта

Типовая структура приложения без фреймворков:

/project
  index.html
  index.js
  package.json

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Deck.gl App</title>
  <style>
    body { margin: 0; }
    #deck-container { width: 100vw; height: 100vh; }
  </style>
</head>
<body>
  <div id="deck-container"></div>
  <script src="./dist/bundle.js"></script>
</body>
</html>

index.js

import {Deck} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';

const data = [
  {position: [37.6173, 55.7558], value: 1},
  {position: [30.3351, 59.9343], value: 20}
];

new Deck({
  container: 'deck-container',
  initialViewState: {
    longitude: 37.6173,
    latitude: 55.7558,
    zoom: 4
  },
  controller: true,
  layers: [
    new ScatterplotLayer({
      id: 'points',
      data,
      getPosition: d => d.position,
      getRadius: d => d.value * 1000,
      getFillColor: d => d.value > 10 ? [255, 80, 80] : [80, 160, 255]
    })
  ]
});

Принцип работы рендеринга

Deck.gl использует WebGL как низкоуровневый слой отрисовки. При каждом обновлении:

  1. Слои проходят стадию подготовки данных
  2. Выполняется компиляция атрибутов
  3. Формируются буферы WebGL
  4. Производится отрисовка в одном кадре

Эта архитектура минимизирует количество draw-call’ов и обеспечивает высокую производительность даже при больших объёмах данных.


Роль уникального идентификатора слоя

Поле id используется для:

  • дифференциации слоёв при обновлении
  • оптимизации перерисовки
  • сохранения состояния между рендерами
new ScatterplotLayer({
  id: 'stable-layer',
  ...
});

Изменение id фактически создаёт новый слой без наследования оптимизаций предыдущего.


Связь слоёв и данных

Deck.gl допускает различные формы источников данных:

  • массивы объектов
  • GeoJSON
  • бинарные форматы
  • потоковые данные

Пример GeoJSON:

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

new GeoJsonLayer({
  id: 'geojson',
  data: 'https://example.com/data.geojson',
  filled: true,
  getFillColor: [200, 0, 80]
});

Минимальная реактивная модель

Даже без использования React или других фреймворков Deck.gl поддерживает реактивность через:

  • setProps
  • пересоздание слоёв
  • обновление viewState

Это формирует однонаправленный поток данных:

данные → слой → WebGL → изображение

Базовые ограничения минимальной конфигурации

При работе без дополнительных библиотек отсутствуют:

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

Поэтому координаты интерпретируются напрямую в системе долгот и широт без преобразований со стороны карты.


Роль контейнера рендеринга

DOM-элемент выполняет исключительно функцию поверхности для WebGL-контекста. Все вычисления происходят вне DOM-дерева.

container: document.getElementById('deck-container')

Любые стили контейнера влияют только на размер canvas, но не на геометрию сцены.


Обновление данных без пересоздания слоя

Оптимизированный подход предполагает сохранение экземпляра слоя:

const layer = new ScatterplotLayer({
  id: 'points',
  data: initialData
});

function update(newData) {
  deckgl.setProps({
    layers: [
      layer.clone({data: newData})
    ]
  });
}

Метод clone сохраняет внутренние оптимизации WebGL и снижает нагрузку на пересборку буферов.


Иерархия минимального приложения

Deck
 ├── ViewState (камера)
 ├── Layers[]
 │     ├── Data
 │     ├── Accessors
 │     └── Render state
 └── WebGLRenderer

Эта структура остаётся неизменной независимо от сложности приложения.