Понятие палубы (Deck)

Объект Deck является центральным элементом библиотеки Deck.gl и выступает в роли управляющего контейнера для всех визуализаций. Именно он отвечает за создание и поддержку WebGL-контекста, управление слоями, обработку пользовательского взаимодействия, обновление состояния сцены и организацию процесса рендеринга.

В архитектуре библиотеки Deck представляет собой своеобразную «палубу», на которой размещаются различные слои визуализации. Независимо от того, используются ли точки, линии, полигоны, тепловые карты или трёхмерные объекты, все они существуют внутри единственного экземпляра Deck.

Упрощённая схема взаимодействия компонентов выглядит следующим образом:

Deck
 ├── View
 ├── ViewState
 ├── Controller
 ├── Layer
 │    ├── ScatterplotLayer
 │    ├── GeoJsonLayer
 │    ├── ArcLayer
 │    └── ...
 └── Effects

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


Создание экземпляра Deck

Работа с библиотекой практически всегда начинается с создания объекта Deck.

Простейший пример:

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

const deck = new Deck({
  initialViewState: {
    longitude: 37.6176,
    latitude: 55.7558,
    zoom: 10,
    pitch: 0,
    bearing: 0
  },

  controller: true,

  layers: []
});

После создания экземпляра происходит:

  1. Инициализация WebGL.
  2. Создание внутреннего цикла рендеринга.
  3. Подготовка механизмов обработки событий.
  4. Настройка камеры.
  5. Подготовка системы управления слоями.

С этого момента объект готов отображать любые слои Deck.gl.


Основные обязанности Deck

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

Deck хранит список активных слоёв.

Пример:

const deck = new Deck({
  layers: [
    citiesLayer,
    roadsLayer,
    buildingsLayer
  ]
});

Каждый слой представляет отдельную сущность визуализации.

Deck выполняет следующие операции:

  • добавляет слои в сцену;
  • удаляет ненужные слои;
  • определяет порядок отрисовки;
  • обновляет данные;
  • передаёт параметры рендеринга.

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


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

Deck отвечает за настройку виртуальной камеры.

Камера определяется через объект состояния представления:

initialViewState: {
  longitude: -74.006,
  latitude: 40.7128,
  zoom: 12,
  pitch: 45,
  bearing: 20
}

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

Параметр Назначение
longitude Долгота центра карты
latitude Широта центра карты
zoom Масштаб
pitch Наклон камеры
bearing Поворот карты

Deck преобразует эти значения в матрицы проекции и вида, необходимые для работы WebGL.


Управление рендерингом

Отрисовка сцены производится централизованно через Deck.

В процессе рендеринга выполняются следующие этапы:

Изменение данных
        ↓
Обновление слоёв
        ↓
Подготовка атрибутов
        ↓
Обновление буферов GPU
        ↓
Вызов WebGL
        ↓
Отображение кадра

Разработчик не работает напрямую с WebGL-вызовами. Deck автоматически организует весь процесс.


Управление жизненным циклом

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

Создание
    ↓
Инициализация
    ↓
Обновление
    ↓
Рендеринг
    ↓
Удаление

Deck контролирует переходы между этими этапами.

Например, если изменились данные слоя:

deck.setProps({
  layers: [newLayer]
});

Deck самостоятельно определяет:

  • какие данные изменились;
  • какие буферы требуется пересоздать;
  • какие вычисления можно пропустить;
  • какие слои необходимо перерисовать.

Свойства объекта Deck

Конструктор принимает большой набор параметров.

parent

Позволяет указать контейнер DOM.

new Deck({
  parent: document.getElementById('map')
});

Внутри контейнера создаётся элемент Canvas, через который осуществляется визуализация.


canvas

Использование уже существующего элемента Canvas.

new Deck({
  canvas: 'deck-canvas'
});

Либо:

new Deck({
  canvas: document.getElementById('deck-canvas')
});

Такой подход полезен при интеграции с существующим приложением.


layers

Список слоёв.

new Deck({
  layers: [
    scatterLayer,
    geoJsonLayer
  ]
});

Это наиболее часто изменяемое свойство.


initialViewState

Начальное положение камеры.

new Deck({
  initialViewState: {
    longitude: 30,
    latitude: 60,
    zoom: 8
  }
});

Используется при первом запуске визуализации.


viewState

Полностью управляемое состояние камеры.

new Deck({
  viewState: currentViewState
});

В отличие от initialViewState, изменения должны передаваться извне.

Подход широко используется в React-приложениях.


controller

Включает взаимодействие пользователя с камерой.

new Deck({
  controller: true
});

После активации становятся доступны:

  • масштабирование колесом мыши;
  • перемещение карты;
  • вращение сцены;
  • наклон камеры.

views

Позволяет создавать несколько областей просмотра.

Пример:

new Deck({
  views: [
    new MapView(),
    new FirstPersonView()
  ]
});

Один экземпляр Deck способен обслуживать сразу несколько камер.


Обновление свойств Deck

После создания объекта его конфигурацию можно менять.

Для этого используется метод setProps.

deck.setProps({
  layers: [newLayer]
});

Также возможно обновление камеры:

deck.setProps({
  viewState: {
    longitude: 10,
    latitude: 50,
    zoom: 5
  }
});

Deck анализирует различия между старым и новым состоянием и выполняет только необходимые операции.

Такой механизм называется diffing и позволяет существенно уменьшить нагрузку на процессор и видеокарту.


Связь Deck и слоёв

Каждый слой существует исключительно внутри объекта Deck.

Пример:

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

const deck = new Deck({
  layers: [layer]
});

Слой не занимается:

  • созданием WebGL-контекста;
  • управлением камерой;
  • обработкой событий браузера.

Все эти обязанности находятся на стороне Deck.

Сам слой отвечает только за:

  • подготовку данных;
  • настройку атрибутов;
  • логику отрисовки конкретного типа объектов.

Подобное разделение делает архитектуру библиотеки модульной и расширяемой.


Работа с событиями

Deck содержит встроенную систему обработки пользовательских действий.

Поддерживаются события:

  • клик;
  • двойной клик;
  • наведение курсора;
  • захват объекта;
  • отпускание объекта;
  • перемещение мыши.

Пример:

new Deck({
  onClick: info => {
    console.log(info);
  }
});

Объект info содержит информацию о выбранном объекте.

Например:

{
  object: {...},
  index: 15,
  x: 340,
  y: 220,
  coordinate: [37.6, 55.7]
}

Deck автоматически определяет объект под курсором посредством механизма picking.


Picking и выбор объектов

Одной из важнейших возможностей Deck является система выбора объектов.

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

Движение мыши
       ↓
Специальный проход рендеринга
       ↓
Определение объекта
       ↓
Формирование PickingInfo
       ↓
Вызов обработчика события

Разработчику не требуется реализовывать собственную систему пересечений лучей и геометрии.

Пример:

new ScatterplotLayer({
  pickable: true,

  onHover: info => {
    console.log(info.object);
  }
});

Все вычисления выполняются внутри Deck.


Интеграция с картографическими движками

Deck часто работает совместно с картографическими библиотеками.

Наиболее распространённые варианты:

  • Mapbox GL JS
  • MapLibre GL JS
  • Google Maps JavaScript API

В подобных сценариях карта отображает базовую подложку, а Deck рисует поверх неё собственные визуализации.

Схема выглядит следующим образом:

Картографический движок
          ↓
Базовая карта
          ↓
Deck
          ↓
Слои визуализации

Это позволяет комбинировать мощные картографические возможности с высокопроизводительной GPU-визуализацией.


Использование нескольких представлений

Deck поддерживает концепцию нескольких окон просмотра.

Пример:

new Deck({
  views: [
    new MapView({
      id: 'map'
    }),

    new FirstPersonView({
      id: 'first-person'
    })
  ]
});

В результате одна сцена может одновременно отображаться:

  • сверху;
  • сбоку;
  • от первого лица;
  • в отдельном мини-окне.

Управление всеми представлениями остаётся централизованным через единый объект Deck.


Эффекты и постобработка

Deck способен управлять графическими эффектами.

Пример подключения эффектов:

new Deck({
  effects: [
    lightingEffect
  ]
});

Через механизм эффектов реализуются:

  • освещение;
  • тени;
  • атмосферные эффекты;
  • постобработка изображения;
  • дополнительные проходы рендеринга.

Все эффекты координируются объектом Deck и интегрируются в общий графический конвейер.


Освобождение ресурсов

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

Для этого используется метод:

deck.finalize();

Во время выполнения метода освобождаются:

  • буферы GPU;
  • текстуры;
  • WebGL-программы;
  • обработчики событий;
  • внутренние менеджеры состояния.

Особенно важно вызывать finalize() в одностраничных приложениях, где компоненты могут создаваться и удаляться многократно.


Внутренние подсистемы Deck

Внутри объекта Deck работает несколько специализированных менеджеров.

LayerManager

Отвечает за:

  • регистрацию слоёв;
  • обновление слоёв;
  • жизненный цикл слоёв;
  • порядок рендеринга.

ViewManager

Управляет:

  • представлениями;
  • камерами;
  • матрицами преобразований.

EffectManager

Контролирует:

  • эффекты;
  • освещение;
  • постобработку.

EventManager

Обрабатывает:

  • мышь;
  • касания;
  • жесты;
  • клавиатурные события.

Совместная работа этих компонентов образует единый механизм визуализации, скрывающий сложность WebGL-инфраструктуры за простым интерфейсом объекта Deck.


Почему Deck является фундаментом всей библиотеки

Практически каждая операция в Deck.gl проходит через объект Deck:

  • создание сцены;
  • подключение слоёв;
  • настройка камеры;
  • обработка событий;
  • выбор объектов;
  • управление эффектами;
  • организация рендеринга;
  • освобождение ресурсов.

По этой причине Deck рассматривается как центральная точка управления приложением и основной контейнер, объединяющий все остальные компоненты экосистемы Deck.gl в единую высокопроизводительную систему визуализации данных.