Создание первого проекта

Создание проекта на основе Deck.gl обычно начинается с подготовки окружения JavaScript-приложения и выбора сборщика модулей. На практике чаще всего используется связка Node.js, npm (или yarn) и современного бандлера — Vite, Webpack или Parcel.

Базовая структура проекта формируется через инициализацию:

npm init -y

После создания package.json устанавливаются основные зависимости:

npm install deck.gl react react-dom
npm install @deck.gl/core @deck.gl/layers

При использовании интеграции с картами дополнительно подключается Mapbox:

npm install mapbox-gl

Для проектов с Vite установка выполняется иначе:

npm create vite@latest deckgl-app
cd deckgl-app
npm install

Архитектура Deck.gl-проекта

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

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

  • Deck instance — контейнер визуализации
  • Layers — декларативные визуальные компоненты
  • ViewState — состояние камеры (позиция, масштаб, угол)
  • Controller — управление интерактивностью
  • Data — входные геоданные

Подготовка базовой HTML-страницы

Минимальная HTML-структура для подключения приложения:

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <title>Deck.gl проект</title>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
      #app {
        width: 100vw;
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

Контейнер #app используется как поверхность для WebGL-рендеринга.

Создание первой сцены Deck.gl

Основная точка входа приложения — создание экземпляра Deck.

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

const data = [
  {position: [37.78, -122.41], size: 100},
  {position: [37.79, -122.42], size: 200},
  {position: [37.77, -122.43], size: 150}
];

const deckgl = new Deck({
  initialViewState: {
    longitude: -122.41,
    latitude: 37.78,
    zoom: 11,
    pitch: 0,
    bearing: 0
  },
  controller: true,
  layers: [
    new ScatterplotLayer({
      id: 'scatter',
      data,
      getPosition: d => d.position,
      getRadius: d => d.size,
      getFillColor: [255, 140, 0]
    })
  ],
  getTooltip: ({object}) => object && `size: ${object.size}`
});

Настройка ViewState и камеры

ViewState определяет поведение виртуальной камеры. Он включает ключевые параметры:

  • longitude — долгота центра
  • latitude — широта центра
  • zoom — уровень масштабирования
  • pitch — наклон камеры
  • bearing — поворот карты

Пример изменения состояния:

const viewState = {
  longitude: -73.935242,
  latitude: 40.73061,
  zoom: 10,
  pitch: 45,
  bearing: 30
};

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

onViewStateChange: ({viewState}) => {
  deckgl.setProps({viewState});
}

Подключение слоёв

Deck.gl использует систему слоёв, где каждый слой отвечает за собственный тип визуализации.

Точечный слой

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

new ScatterplotLayer({
  id: 'points',
  data,
  getPosition: d => d.position,
  getRadius: d => d.size,
  getFillColor: [0, 128, 255],
  radiusUnits: 'meters'
});

Линейный слой

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

new PathLayer({
  id: 'paths',
  data: [
    {path: [[-122.4, 37.7], [-122.5, 37.8]]}
  ],
  getPath: d => d.path,
  getColor: [255, 0, 0],
  widthMinPixels: 2
});

Полигональный слой

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

new PolygonLayer({
  id: 'polygons',
  data: [
    {
      contour: [
        [-122.4, 37.7],
        [-122.5, 37.7],
        [-122.5, 37.8],
        [-122.4, 37.8]
      ]
    }
  ],
  getPolygon: d => d.contour,
  getFillColor: [0, 200, 100, 150]
});

Связка Deck.gl с Mapbox

Deck.gl часто используется поверх Mapbox-карт, что позволяет комбинировать векторные тайлы и WebGL-слои.

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

mapboxgl.accessToken = 'TOKEN';

const map = new mapboxgl.Map({
  container: 'app',
  style: 'mapbox://styles/mapbox/dark-v11',
  center: [-122.41, 37.78],
  zoom: 11
});

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

map.addControl(overlay);

Организация данных

Deck.gl работает с различными форматами данных: массивы объектов, GeoJSON, бинарные форматы.

GeoJSON пример:

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

new GeoJsonLayer({
  id: 'geojson',
  data: '/data/regions.geojson',
  filled: true,
  stroked: true,
  getFillColor: [200, 0, 80, 120],
  getLineColor: [255, 255, 255]
});

Обновление данных и реактивность

Deck.gl поддерживает обновление слоёв через пересоздание конфигурации:

function updateData(newData) {
  deckgl.setProps({
    layers: [
      new ScatterplotLayer({
        id: 'scatter',
        data: newData,
        getPosition: d => d.position,
        getRadius: d => d.size
      })
    ]
  });
}

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

Оптимизация первого проекта

Производительность в Deck.gl зависит от структуры данных и количества отрисовываемых объектов.

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

  • использование binary attributes вместо JS-объектов
  • уменьшение числа слоёв
  • применение updateTriggers
  • отключение лишней интерактивности
  • использование instanced rendering

Пример updateTriggers:

new ScatterplotLayer({
  id: 'optimized',
  data,
  getColor: d => d.color,
  updateTriggers: {
    getColor: [data]
  }
});

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

Deck.gl поддерживает обработку событий:

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

Дополнительно доступны:

  • onHover
  • onDrag
  • onDragStart
  • onDragEnd

Интеграция с React

Deck.gl часто используется вместе с React через DeckGL компонент.

import DeckGL from '@deck.gl/react';
import {ScatterplotLayer} from '@deck.gl/layers';

function App() {
  const layers = [
    new ScatterplotLayer({
      id: 'scatter',
      data,
      getPosition: d => d.position,
      getRadius: d => d.size
    })
  ];

  return (
    <DeckGL
      initialViewState={{
        longitude: -122.41,
        latitude: 37.78,
        zoom: 11
      }}
      controller={true}
      layers={layers}
    />
  );
}

Базовая структура проекта

Типичная структура приложения:

deckgl-app/
 ├── src/
 │   ├── layers/
 │   ├── data/
 │   ├── utils/
 │   ├── main.js
 ├── index.html
 ├── package.json
 ├── vite.config.js

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

Работа с координатами

Deck.gl использует форматы:

  • [longitude, latitude]
  • Web Mercator projection
  • иногда [x, y, z] в кастомных слоях

Пример преобразования:

function normalizeCoordinates(d) {
  return {
    position: [d.lon, d.lat]
  };
}

Использование кастомных слоёв

При необходимости реализуются WebGL-слои:

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

class CustomLayer extends Layer {
  initializeState() {}
  draw({uniforms}) {
    // WebGL rendering logic
  }
}

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

Управление состоянием визуализации

Состояние карты отделяется от данных. Это позволяет строить предсказуемые визуализации:

const state = {
  viewState: {
    longitude: 0,
    latitude: 0,
    zoom: 1
  },
  data: []
};

Обновления происходят через замену состояния, что упрощает синхронизацию UI и WebGL-слоя.