Иконки и маркеры

В визуализациях поверх карт и произвольных координатных систем иконки и маркеры выступают базовым способом представления дискретных объектов. В Deck.gl для этих целей используется набор специализированных слоёв, среди которых ключевую роль играет IconLayer, а также вспомогательные подходы через ScatterplotLayer и TextLayer. Архитектура библиотеки ориентирована на высокопроизводительный рендеринг через WebGL, поэтому даже большое количество маркеров обрабатывается на GPU, а не на CPU.


Модель данных для маркеров

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

Типичный формат:

const data = [
  {
    position: [71.4304, 51.1282],
    name: "Объект A",
    type: "station",
    size: 1
  },
  {
    position: [71.4500, 51.1200],
    name: "Объект B",
    type: "station",
    size: 2
  }
];

Ключевой элемент — position, представляющий координаты в формате [longitude, latitude]. Для 3D-визуализаций добавляется третья координата высоты [lng, lat, z].


IconLayer: базовый слой иконок

IconLayer предназначен для рендеринга спрайтовых иконок, собранных в атлас (sprite atlas). Это наиболее производительный способ отображения большого количества однотипных маркеров.

Основная конфигурация слоя

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

const iconLayer = new IconLayer({
  id: 'icon-layer',
  data,
  pickable: true,
  iconAtlas: '/icons/atlas.png',
  iconMapping: {
    station: {x: 0, y: 0, width: 32, height: 32},
    bus: {x: 32, y: 0, width: 32, height: 32}
  },
  getIcon: d => d.type,
  getPosition: d => d.position,
  getSize: d => d.size || 24,
  sizeScale: 1,
  sizeUnits: 'pixels'
});

Атлас и сопоставление иконок

IconAtlas

iconAtlas — это изображение, содержащее набор иконок в виде сетки или произвольного размещения. Использование атласа минимизирует количество текстурных переключений на GPU.

IconMapping

iconMapping описывает координаты каждой иконки внутри атласа:

iconMapping: {
  airport: {
    x: 0,
    y: 0,
    width: 64,
    height: 64,
    anchorY: 32
  },
  train: {
    x: 64,
    y: 0,
    width: 64,
    height: 64,
    anchorY: 32
  }
}

Параметр anchorY управляет точкой привязки, что особенно важно для маркеров, которые должны «стоять» на координате нижней частью.


Доступ к данным через getIcon

Функция getIcon определяет, какую иконку использовать для каждого объекта:

getIcon: d => {
  if (d.type === 'airport') return 'airport';
  if (d.type === 'train') return 'train';
  return 'default';
}

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


Размеры и масштабирование

getSize и sizeScale

getSize: d => d.size,
sizeScale: 10

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

sizeUnits

  • meters — размер в реальных метрах
  • pixels — фиксированный размер на экране
sizeUnits: 'meters'

Использование метров важно при работе с 3D-картами, где объекты должны сохранять масштаб относительно земли.


Billboard и ориентация иконок

По умолчанию иконки в Deck.gl используют режим billboard — они всегда повернуты к камере.

billboard: true

Это обеспечивает читаемость независимо от угла обзора. В 3D-сценах можно отключать billboard для создания эффектов пространственного размещения объектов.


Цветовая кастомизация

Хотя иконки обычно задаются через текстуры, Deck.gl позволяет применять цветовые фильтры:

getColor: d => [255, 0, 0, 200]

Это работает как умножение цвета пикселей текстуры на заданный RGBA-вектор.


ScatterplotLayer как альтернатива маркерам

Для простых маркеров без текстур используется ScatterplotLayer. Он эффективен при визуализации точек, где не требуется уникальная графика.

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

const scatter = new ScatterplotLayer({
  id: 'scatter',
  data,
  getPosition: d => d.position,
  getRadius: d => d.size * 100,
  getFillColor: d => [0, 128, 255, 180],
  pickable: true
});

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


TextLayer для подписей маркеров

Часто иконки сопровождаются текстом. Для этого используется TextLayer.

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

const textLayer = new TextLayer({
  id: 'text',
  data,
  getPosition: d => d.position,
  getText: d => d.name,
  getSize: 16,
  getColor: [0, 0, 0, 255],
  getAngle: 0,
  billboard: true
});

Комбинация IconLayer + TextLayer является стандартным паттерном построения интерактивных карт.


Комбинирование слоёв маркеров

Deck.gl построен на концепции композиции слоёв. Маркеры редко используются изолированно — чаще они объединяются в стек:

const layers = [
  iconLayer,
  scatter,
  textLayer
];

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


Производительность и GPU-рендеринг

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

  • батчинг однотипных иконок
  • минимизация draw calls через атлас
  • использование instanced rendering
  • кэширование геометрии

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


Координатные системы и проекции

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

  • COORDINATE_SYSTEM.LNGLAT — географические координаты
  • COORDINATE_SYSTEM.METER_OFFSETS — локальные метры
  • COORDINATE_SYSTEM.CARTESIAN — произвольные сцены

Для маркеров на карте чаще всего используется LNGLAT, где данные интерпретируются через проекцию Web Mercator.


Интерактивность маркеров

Параметр pickable включает обработку событий наведения и клика.

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

Объект info содержит данные слоя, координаты курсора и пиксельные позиции, что позволяет строить интерактивные интерфейсы поверх карты.


Динамическое обновление маркеров

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

setData(newData);

При этом GPU-пайплайн перестраивается минимально, если структура данных остаётся совместимой.


Типичные ошибки при работе с иконками

  • отсутствие iconMapping для используемых ключей
  • слишком большие атласы без оптимизации текстур
  • использование pixels вместо meters в 3D-сценах
  • несогласованность anchor-точек, приводящая к «прыгающим» маркерам
  • чрезмерное количество уникальных иконок вместо атласа

Оптимизационные практики

  • объединение иконок в один атлас
  • использование sizeUnits: 'meters' для масштабируемых сцен
  • минимизация количества уникальных текстур
  • кэширование данных вне render loop
  • отключение pickable, если интерактивность не требуется

Слои маркеров в 3D-сценах

В 3D-режиме маркеры могут располагаться на разной высоте:

getPosition: d => [d.lng, d.lat, d.height]

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


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

Для продвинутых сценариев IconLayer может быть расширен через шейдерные модификации. Это позволяет реализовать эффекты:

  • пульсации маркеров
  • анимации появления
  • цветовые градиенты по данным
  • реакцию на время или состояние

Deck.gl предоставляет shaderModules для внедрения GLSL-кода без полного переписывания слоя.


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

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

  • кластеризация точек
  • heatmap-слои
  • multi-resolution rendering

Тем не менее IconLayer остаётся базовым элементом, на который опираются более сложные визуальные конструкции.