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

Picking в Deck.gl представляет собой систему определения объектов сцены, находящихся под курсором или в заданной экранной области. В основе лежит GPU-based выбор объектов, при котором каждый интерактивный элемент получает уникальную идентификацию в offscreen-буфере, позволяя быстро и точно определять попадания без перебора данных на CPU.

Механизм picking интегрирован в рендер-пайплайн и работает на уровне слоёв (layers), поддерживая как простые геометрии, так и сложные агрегированные структуры.


Базовый принцип работы picking

Каждый объект, который может участвовать в выборе, рендерится в специальном режиме в скрытый буфер. Вместо привычного цвета используется закодированный идентификатор объекта.

Ключевые особенности:

  • каждый объект получает уникальный picking color
  • рендер происходит в offscreen framebuffer
  • результат читается через readPixels
  • сопоставление цвета и объекта выполняется внутри Deck.gl

Этот подход обеспечивает:

  • стабильную производительность при больших объёмах данных
  • отсутствие необходимости перебора объектов на CPU
  • поддержку сложных сцен с тысячами элементов

Включение picking на уровне слоя

Для того чтобы объект стал доступен для выбора, слой должен поддерживать и включать параметр pickable.

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

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

При отсутствии pickable: true слой полностью исключается из picking-прохода.


Обработка событий hover и click

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

onHover

const layer = new ScatterplotLayer({
  id: 'points',
  data,
  pickable: true,

  onHover: info => {
    const {object, x, y, coordinate, layer} = info;
    if (object) {
      console.log('Hover object:', object);
      console.log('Screen coords:', x, y);
      console.log('Geo coords:', coordinate);
    }
  }
});

Структура info:

  • object — выбранный объект данных
  • index — индекс в массиве data
  • x, y — координаты курсора в пикселях
  • coordinate — географические координаты (если применимо)
  • layer — ссылка на слой
  • color — picking color (внутреннее использование)

onClick

const layer = new ScatterplotLayer({
  id: 'points',
  data,
  pickable: true,

  onClick: info => {
    if (info.object) {
      console.log('Clicked:', info.object);
    }
  }
});

Click-событие использует тот же механизм picking, но фиксирует событие при нажатии мыши.


Программный picking через Deck

Помимо событий слоёв, Deck.gl предоставляет низкоуровневые методы API.

pickObject

const info = deck.pickObject({x: 100, y: 200});

console.log(info.object);

Возвращает ближайший объект под координатами.


pickMultipleObjects

Используется для получения всех объектов в пиксельной области:

const infos = deck.pickMultipleObjects({x: 100, y: 200, radius: 5});

Особенно полезно при плотных данных, где несколько объектов перекрывают друг друга.


pickObjects

const infos = deck.pickObjects({x: 100, y: 200});

Возвращает все объекты, включая из разных слоёв, упорядоченные по глубине.


Структура результата picking

Результат любого picking-запроса имеет унифицированную структуру:

{
  object,
  index,
  layer,
  sourceLayer,
  x,
  y,
  coordinate,
  color
}

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

  • sourceLayer полезен для composite layers
  • coordinate зависит от проекции слоя
  • layer может отличаться от sourceLayer в сложных слоях

Подсветка объектов при наведении

Deck.gl поддерживает автоматическую подсветку через autoHighlight.

const layer = new ScatterplotLayer({
  id: 'points',
  data,
  pickable: true,
  autoHighlight: true,
  highlightColor: [0, 255, 0, 180]
});

Механизм работает через внутренний state слоя и не требует ручного управления.


Radius picking и область захвата

В реальных сценариях курсор редко попадает точно в центр объекта. Для этого используется радиус выбора.

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

На уровне API:

deck.pickMultipleObjects({
  x: 100,
  y: 100,
  radius: 10
});

Радиус расширяет область поиска в экранных координатах.


Depth-based picking и перекрытия

При наличии перекрывающихся объектов используется depth buffer. Deck.gl учитывает z-index сцены и выбирает ближайший объект к камере.

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

  • работает при использовании WebGL depth test
  • учитывает трансформации камеры
  • корректно обрабатывает 3D сцены (extruded polygons, meshes)

Picking в composite layers

Composite layers (например, GeoJsonLayer) агрегируют множество подслоёв. Picking в этом случае проходит через цепочку:

  1. Composite layer получает событие
  2. Делегирует его подслою
  3. Возвращает нормализованный результат
import {GeoJsonLayer} from '@deck.gl/layers';

const layer = new GeoJsonLayer({
  id: 'geojson',
  data,
  pickable: true,
  onClick: info => {
    console.log(info.object);
  }
});

В info.object может находиться feature GeoJSON.


Picking в агрегированных слоях

Слои вроде HexagonLayer или GridLayer возвращают не исходные объекты, а агрегаты.

import {HexagonLayer} from '@deck.gl/aggregation-layers';

const layer = new HexagonLayer({
  id: 'hex',
  data,
  pickable: true,
  getPosition: d => d.position,
  getElevationWeight: d => d.value,
  onHover: info => {
    console.log(info.object.points);
  }
});

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

  • object содержит агрегированные данные
  • доступен список исходных точек (points)
  • координата соответствует центру ячейки

Picking и MVT слои

В MVTLayer picking работает на уровне тайлов и векторных фич.

import {MVTLayer} from '@deck.gl/geo-layers';

const layer = new MVTLayer({
  id: 'mvt',
  data: 'https://tiles/{z}/{x}/{y}.pbf',
  pickable: true,
  onClick: info => {
    console.log(info.object.properties);
  }
});

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

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

Оптимизация picking

При работе с большими наборами данных важны оптимизации.

Минимизация pickable слоёв

Каждый pickable слой увеличивает нагрузку:

  • дополнительный rendering pass
  • увеличение framebuffer операций

Рекомендуется включать picking только там, где он нужен.


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

Binary attributes позволяют ускорить рендер и picking:

data: {
  length: n,
  attributes: {
    getPosition: {value: new Float32Array(...), size: 3}
  }
}

Преимущества:

  • меньше JS-обработки
  • быстрее GPU upload
  • стабильнее performance при больших объёмах

Custom picking и override поведения

В некоторых слоях можно переопределить поведение через getPickingInfo.

const layer = new ScatterplotLayer({
  id: 'points',
  data,
  pickable: true,

  getPickingInfo: ({info}) => {
    return {
      ...info,
      object: {
        ...info.object,
        custom: true
      }
    };
  }
});

Это позволяет:

  • модифицировать payload
  • добавлять вычисленные поля
  • фильтровать результаты picking

Hit tolerance и точность выбора

Точность picking зависит от нескольких факторов:

  • размер объекта в пикселях
  • плотность данных
  • zoom level
  • параметры камеры

Для точечных данных часто используются:

  • radiusPixels
  • minPixelSize
  • увеличение hit area

Ограничения picking-системы

Несмотря на высокую эффективность, существуют ограничения:

  • прозрачные пиксели могут влиять на hit-test
  • сложные custom layers требуют ручной поддержки picking
  • при высоких нагрузках возможны задержки framebuffer readback
  • WebGL контекст ограничивает размер буфера выборки

Использование picking в интерактивных сценариях

Типовые сценарии:

  • интерактивные карты с геоданными
  • визуализация потоков (flows, arcs)
  • выбор точек в scatterplot анализе
  • работа с 3D сценами (extruded buildings, meshes)
  • выделение кластеров и агрегатов

Механизм остаётся единым, независимо от типа слоя: GPU-based идентификация с последующим сопоставлением данных на уровне Deck.gl runtime.