События карты

Архитектура взаимодействия с картой в Mapbox GL JS построена вокруг событийной модели, в которой все пользовательские действия, изменения состояния карты и внутренние процессы рендеринга транслируются в поток событий. Этот механизм обеспечивает контроль над поведением карты без необходимости вмешиваться в рендеринговый цикл WebGL.

Базовая модель событий

Экземпляр карты в Mapbox GL JS реализует интерфейс событийного эмиттера. Основные методы работы с событиями:

  • map.on(type, listener) — регистрация обработчика
  • map.once(type, listener) — одноразовый обработчик
  • map.off(type, listener) — удаление обработчика

События делятся на несколько категорий:

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

Каждое событие передаёт объект с контекстной информацией: координаты, состояние карты, целевые объекты (features), DOM-данные и внутренние параметры рендера.

События жизненного цикла

Жизненный цикл карты отражает этапы инициализации и готовности рендера.

load

Срабатывает после полной загрузки стиля, тайлов и ресурсов. На этом этапе карта готова к добавлению слоёв и источников данных.

map.on('load', () => {
  map.addSource('points', {
    type: 'geojson',
    data: '/data/points.geojson'
  });
});

style.load

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

idle

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

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

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

move

Вызывается при любом изменении центра карты.

zoom

Срабатывает при изменении масштаба.

rotate

Фиксирует изменение угла поворота.

pitch

Отражает изменение наклона камеры.

moveend, zoomend, rotateend

Завершающие события, фиксирующие окончание соответствующих трансформаций.

Пример отслеживания координат:

map.on('move', () => {
  const center = map.getCenter();
  console.log(center.lng, center.lat);
});

События пользовательского взаимодействия

Слой взаимодействия формируется поверх WebGL и обрабатывает события указателя (mouse/touch/pointer).

Основные события:

  • click
  • dblclick
  • mousedown
  • mouseup
  • mousemove
  • mouseenter
  • mouseleave
  • contextmenu
  • touchstart
  • touchend

Каждое событие содержит:

  • lngLat — географические координаты
  • point — пиксельные координаты
  • originalEvent — исходное DOM-событие

Пример обработки клика:

map.on('click', (e) => {
  console.log(e.lngLat);
});

События по слоям

Mapbox GL JS поддерживает привязку событий непосредственно к слоям, что позволяет обрабатывать взаимодействие с конкретными объектами карты.

map.on('click', 'cities-layer', (e) => {
  const features = map.queryRenderedFeatures(e.point, {
    layers: ['cities-layer']
  });

  console.log(features);
});

Типы событий для слоёв:

  • click
  • mouseenter
  • mouseleave
  • mousemove
  • mousedown
  • mouseup

Особенность слоя — событие срабатывает только при попадании курсора на отрисованные фичи данного слоя.

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

При взаимодействии с векторными данными событие содержит массив объектов features.

Каждый feature включает:

  • id
  • geometry
  • properties
  • layer
  • source

Пример извлечения данных:

map.on('click', (e) => {
  const features = map.queryRenderedFeatures(e.point);

  if (features.length) {
    console.log(features[0].properties);
  }
});

События источников данных

Источники (sources) генерируют события при изменении данных или их загрузке.

  • sourcedata — изменение данных источника
  • data — обновление данных тайлов
  • dataloading — начало загрузки
  • styledata — изменение стиля, влияющее на источники

Пример контроля загрузки:

map.on('dataloading', (e) => {
  console.log('Загрузка данных:', e.sourceId);
});

Системные и диагностические события

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

error

Срабатывает при возникновении ошибки в загрузке ресурсов или рендеринге.

map.on('error', (e) => {
  console.error(e.error);
});

render

Вызывается при каждом кадре отрисовки WebGL. Используется для анимаций и синхронизации внешних эффектов.

События взаимодействия с курсором

Mapbox GL JS интерпретирует положение курсора относительно слоя карты и генерирует события наведения.

  • mouseenter — вход курсора в область слоя
  • mouseleave — выход курсора
  • mouseover / mouseout — аналог DOM-логики

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

Приоритеты и распространение событий

События обрабатываются в порядке:

  1. слой (layer events)
  2. карта (map events)
  3. DOM события (через originalEvent)

Отсутствует классическая модель bubbling как в DOM, но существует логика приоритета слоёв: верхние визуально слои имеют более высокий приоритет обработки.

Контекст события

Объект события может включать:

  • координаты (lngLat)
  • экранные координаты (point)
  • состояние карты (target)
  • DOM-событие (originalEvent)
  • список фич (features, при layer events)

Это позволяет строить сложные сценарии взаимодействия, например:

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

Управление подписками и утечки памяти

При динамическом создании интерфейсов важно удалять обработчики:

function onClick(e) {
  console.log(e.lngLat);
}

map.on('click', onClick);
map.off('click', onClick);

Использование once полезно для одноразовых операций, например ожидания загрузки:

map.once('load', () => {
  console.log('Карта готова');
});

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

События mousemove и render могут вызываться десятки раз в секунду. Их обработка требует оптимизации:

  • использование requestAnimationFrame
  • дебаунсинг обработчиков
  • минимизация вычислений внутри callback

Особенно критично это при обработке большого числа features или при работе с тяжелыми слоями.

Координатные преобразования в событиях

События предоставляют уже готовые координаты, но часто требуется преобразование:

  • map.project(lngLat) — географические → пиксельные
  • map.unproject(point) — пиксельные → географические

Это используется при синхронизации UI-элементов с картой:

map.on('move', () => {
  const center = map.project(map.getCenter());
  console.log(center);
});

Связь событий с WebGL-рендерингом

События движения и взаимодействия неразрывно связаны с WebGL-циклом рендеринга. Каждый интерактивный жест:

  • изменяет матрицу камеры
  • инициирует перерасчёт тайлов
  • триггерит перерисовку слоя
  • может вызвать render и idle

Таким образом, событийная модель является связующим слоем между UI и графическим движком, реализованным внутри Mapbox экосистемы.