События клика и наведения

В Kepler.gl взаимодействие с картой строится поверх архитектуры deck.gl, где каждый визуальный слой поддерживает picking (определение объекта под курсором) и генерацию событий наведения и клика. События формируются на уровне WebGL-контекста, а затем проксируются в React-компонент KeplerGl через колбэки onClick и onHover.

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


Архитектура обработки взаимодействий

Вся система событий в Kepler.gl опирается на три уровня:

1. Deck.gl picking engine Определяет объект под курсором на основе GPU-рендеринга и буферов идентификации.

2. Kepler.gl interaction state Хранит состояние взаимодействий: выделение, hover, tooltip, активные объекты.

3. React callbacks KeplerGl Передают события наружу в пользовательское приложение.


Событие наведения (hover)

Наведение курсора является основным механизмом получения контекстной информации без фиксации выбора объекта.

Механика hover

При движении мыши выполняется пересчёт:

  • координат курсора в координаты карты
  • попадания в геометрию слоя
  • ближайшего объекта в пределах tolerance

После этого формируется объект события:

{
  x: 512,
  y: 320,
  coordinate: [37.78, -122.41],
  object: {
    id: 42,
    type: "feature",
    properties: {
      name: "Point A",
      value: 100
    }
  },
  layer: {
    id: "points-layer"
  }
}

Колбэк onHover

Kepler.gl предоставляет обработчик:

<KeplerGl
  id="map"
  mapboxApiAccessToken={token}
  onHo ver={(info) => {
    console.log(info);
  }}
/>

Поведение:

  • вызывается при каждом изменении объекта под курсором
  • при выходе курсора за объект возвращается object: null
  • обновление происходит на каждом mousemove

Типичные сценарии использования hover

  • отображение кастомных tooltip
  • подсветка связанных объектов
  • динамическое обновление панели данных
  • синхронизация с внешними графиками

Tooltip как встроенная реакция hover

Kepler.gl имеет встроенную систему tooltip, которая активируется через interactionConfig.

const config = {
  interactionConfig: {
    tooltip: {
      enabled: true,
      fieldsToShow: {
        points: ["name", "value"]
      }
    }
  }
};

Логика отображения

Tooltip строится на основе:

  • слоя, в котором произошло событие
  • списка полей, разрешённых к отображению
  • текущего объекта hover

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


Событие клика (click)

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

Механизм обработки click

При клике выполняется:

  1. picking объекта под курсором
  2. фиксация объекта как selected
  3. передача события наружу через callback
  4. обновление internal selection state

Структура события click

{
  x: 420,
  y: 210,
  coordinate: [55.75, 37.61],
  object: {
    id: 17,
    properties: {
      category: "A",
      value: 300
    }
  },
  layer: {
    id: "heatmap-layer"
  }
}

Колбэк onClick

<KeplerGl
  id="map"
  mapboxApiAccessToken={token}
  onCl ick={(info) => {
    if (info.object) {
      console.log("Выбран объект:", info.object);
    }
  }}
/>

Отличие click от hover

Различие заключается не только в типе события, но и в семантике состояния:

  • hover — временное состояние без фиксации
  • click — устойчивое состояние выбора

Hover не изменяет глобальный state приложения, тогда как click часто используется для:

  • фильтрации данных
  • закрепления объекта
  • построения связей
  • запуска внешних действий

Взаимодействие с состоянием слоя

Каждое событие связано с конкретным слоем Kepler.gl. Это важно при работе с несколькими источниками данных.

layer: {
  id: "trips-layer",
  type: "line",
  config: {
    color: [255, 0, 0]
  }
}

При обработке событий часто используется фильтрация по layer.id:

onCl ick={(info) => {
  if (info.layer?.id === "trips-layer") {
    handleTripSelection(info.object);
  }
}}

Глубокая интеграция с deck.gl picking

Kepler.gl не реализует собственный механизм определения объектов, а использует deck.gl:

  • pickObject — определение одного объекта
  • pickMultipleObjects — для stacked layers
  • pickingRadius — зона захвата курсора

Влияние плотности данных

При высокой плотности объектов:

  • hover может возвращать разные объекты при минимальном движении
  • click может попадать в верхний визуальный слой
  • приоритет слоя определяется порядком рендеринга

Обработка нескольких объектов под курсором

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

{
  objects: [
    { id: 1, layer: "points" },
    { id: 2, layer: "clusters" }
  ],
  layer: {
    id: "clusters"
  }
}

Выбор активного объекта определяется:

  • порядком слоёв
  • настройками интерактивности слоя
  • режимом clustering

Отключение интерактивности

Интерактивность можно управлять на уровне конфигурации:

interactionConfig: {
  tooltip: {
    enabled: false
  }
}

Дополнительно слой может быть полностью исключён из picking:

config: {
  enable3d: true,
  isVisible: true,
  visConfig: {
    interactive: false
  }
}

Кастомная обработка событий

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

Пример внешнего state-driven подхода

const [selected, setSelected] = useState(null);

<KeplerGl
  id="map"
  onCl ick={(info) => setSelected(info.object)}
  onHo ver={(info) => setHovered(info.object)}
/>

Такой подход позволяет:

  • синхронизировать карту с таблицами
  • строить внешние панели анализа
  • интегрировать карту в BI-системы

Особенности производительности

Обработка hover событий является высокочастотной операцией:

  • вызывается на каждом mousemove
  • требует минимизации тяжёлых вычислений в callback
  • рекомендуется использовать debounce для внешней логики
const debouncedHover = useMemo(
  () => debounce(setHovered, 50),
  []
);

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

1. Тяжёлая логика в onHover Приводит к фризам интерфейса при движении курсора.

2. Игнорирование object === null Неочищенное состояние hover создаёт визуальные артефакты.

3. Отсутствие фильтрации по слоям События разных слоёв начинают конфликтовать в логике приложения.

4. Использование click как hover Приводит к неправильной семантике взаимодействия и усложнению UX.


События и временные состояния данных

Hover и click часто используются как триггеры для временных вычислений:

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

Это позволяет использовать Kepler.gl не только как визуализатор, но и как интерактивный аналитический инструмент, где карта становится входом в вычислительную модель данных.