Обработчики событий

В MapLibre GL JS взаимодействие с картой строится вокруг событийной модели. Почти любое изменение состояния карты, пользовательское действие или завершение внутреннего процесса рендеринга сопровождается генерацией событий, к которым подключаются обработчики.

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


Регистрация обработчиков событий

Базовый механизм подписки на события реализован через методы объекта карты:

  • on(type, listener) — добавление обработчика
  • off(type, listener) — удаление обработчика
  • once(type, listener) — одноразовое выполнение обработчика
map.on('load', () => {
  console.log('Карта полностью загружена');
});

Обработчики могут регистрироваться как на глобальные события карты, так и на события конкретных слоёв или источников.


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

События жизненного цикла отражают этапы инициализации и рендеринга карты.

load

Срабатывает после полной загрузки стиля, источников и ресурсов.

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

idle

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

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

render

Срабатывает при каждом цикле рендеринга. Частота высокая, требует осторожного использования.

map.on('render', () => {
  console.log('Карта перерисовывается');
});

remove

Возникает при уничтожении экземпляра карты. Применяется для очистки ресурсов.


События изменения состояния карты

Карта генерирует события при изменении положения, масштаба и ориентации.

move, zoom, rotate, pitch

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

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

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

  • moveend
  • zoomend
  • rotateend
  • pitchend

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

map.on('zoomend', () => {
  console.log('Зум завершён');
});

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

Мышь и указатель

MapLibre GL JS поддерживает события pointer-уровня:

  • click
  • dblclick
  • mousedown
  • mouseup
  • mousemove
  • mouseenter
  • mouseleave
  • mouseover
  • mouseout
map.on('click', (e) => {
  console.log(e.lngLat);
});

Объект события содержит координаты, экранные координаты и данные о фичах под курсором.


Работа с объектами карты через события

Одним из ключевых механизмов является извлечение объектов слоя при взаимодействии.

queryRenderedFeatures

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

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

  console.log(features);
});

Типичный сценарий — обработка кликов по векторным слоям для отображения всплывающих окон или выделения объектов.


События слоёв

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

map.on('click', 'cities-layer', (e) => {
  console.log('Клик по объекту слоя');
});

Поддерживаются события:

  • click
  • mouseenter
  • mouseleave
  • mousemove

Механизм основан на hit-testing в пределах заданного слоя, что снижает необходимость ручной фильтрации через queryRenderedFeatures.


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

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

  • sourcedata — любые изменения данных источника
  • data — глобальное событие обновления данных
  • dataloading — начало загрузки
  • dataabort — прерывание загрузки
map.on('sourcedata', (e) => {
  console.log(e.sourceId, e.isSourceLoaded);
});

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


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

Изменения стиля карты также сопровождаются событиями:

  • styledata
  • styleimagemissing
  • style.load
map.on('styledata', () => {
  console.log('Стиль изменён');
});

styleimagemissing особенно важен при использовании пользовательских иконок: событие сигнализирует об отсутствии изображения в стиле.


Объект события

Каждое событие содержит объект с информацией о контексте.

Основные поля:

  • type — тип события
  • target — экземпляр карты
  • lngLat — географические координаты
  • point — экранные координаты
  • features — найденные геообъекты
  • originalEvent — нативное DOM-событие
map.on('click', (e) => {
  console.log(e.type);
  console.log(e.lngLat);
  console.log(e.point);
});

Делегирование и приоритет событий

MapLibre GL JS использует систему приоритетов:

  1. События слоя (layer-specific)
  2. Глобальные события карты
  3. DOM-события canvas

При совпадении обработчиков сначала выполняется наиболее специфичный уровень.


Одноразовые обработчики

Метод once применяется для событий, которые должны сработать единожды.

map.once('idle', () => {
  console.log('Первое завершение рендера');
});

Типичный сценарий — инициализация после первой полной отрисовки карты.


Удаление обработчиков

Удаление подписок критично при динамических интерфейсах и SPA-архитектурах.

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

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

Невычищенные обработчики приводят к утечкам памяти и дублированию логики.


Производительность событийной модели

События mousemove, render, move генерируются с высокой частотой. Их обработка требует оптимизации:

  • использование requestAnimationFrame
  • ограничение частоты через throttle
  • минимизация вычислений внутри обработчиков
let last;
map.on('mousemove', (e) => {
  const now = Date.now();
  if (now - last < 50) return;
  last = now;
});

События и состояние интерфейса

Событийная модель часто используется для синхронизации UI:

  • обновление координат курсора
  • отображение информации о слое
  • управление popups
  • динамическая фильтрация данных
map.on('mousemove', (e) => {
  const features = map.queryRenderedFeatures(e.point);
  updateSidebar(features);
});

Обработка всплывающих окон через события

Типовой сценарий — привязка popups к кликам по объектам.

map.on('click', 'cities-layer', (e) => {
  const coordinates = e.lngLat;
  const description = e.features[0].properties.name;

  new maplibregl.Popup()
    .setLngLat(coordinates)
    .setHTML(description)
    .addTo(map);
});

Комбинирование событий

Сложные сценарии используют цепочки событий:

  • mousemove → подсветка объекта
  • click → фиксация выбора
  • mouseleave → сброс состояния
  • zoomend → перерисовка интерфейса

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


Особенности работы с touch-событиями

На мобильных устройствах события pointer объединяют мышь и сенсорный ввод. MapLibre GL JS абстрагирует различия через единый набор событий, сохраняя совместимость логики.


Взаимодействие с рендерингом

События рендеринга тесно связаны с WebGL-пайплайном:

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

События позволяют отслеживать эти процессы без доступа к внутренним механизмам WebGL.


Ошибки и нестандартные события

Некоторые события сигнализируют о проблемах:

  • error — ошибки загрузки ресурсов или стиля
  • styleimagemissing — отсутствие изображений
  • dataabort — прерывание загрузки тайлов
map.on('error', (e) => {
  console.error(e.error);
});

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