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

Архитектура событийного механизма

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

События реализованы через систему ol.Observable, обеспечивающую единый интерфейс:

  • регистрация обработчиков через on
  • однократное выполнение через once
  • удаление подписок через un
  • массовое отключение через dispose

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


Регистрация и управление обработчиками

Базовый механизм подписки на события карты строится вокруг метода map.on:

map.on('click', function (event) {
  console.log(event.coordinate);
});

Каждое событие передаёт объект event, содержащий контекст:

  • coordinate — координаты точки в системе карты
  • pixel — позиция курсора в пикселях относительно контейнера карты
  • map — ссылка на экземпляр карты

Удаление обработчика осуществляется через un:

function handler(event) {
  console.log(event.pixel);
}

map.on('pointermove', handler);
map.un('pointermove', handler);

Однократные события применяются при необходимости выполнить действие строго один раз:

map.once('rendercomplete', function () {
  console.log('Первичный рендер завершён');
});

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

События ol.Map делятся на несколько категорий: пользовательские взаимодействия, события движения карты и события рендеринга.

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

click

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

map.on('click', function (event) {
  console.log('Click:', event.coordinate);
});

singleclick

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

map.on('singleclick', function (event) {
  console.log('Single click:', event.pixel);
});

dblclick

Активируется при двойном клике и часто используется для масштабирования или пользовательских действий.

map.on('dblclick', function (event) {
  console.log('Double click zoom trigger');
});

pointermove

Срабатывает при перемещении курсора над картой. Является одним из наиболее частых событий.

map.on('pointermove', function (event) {
  console.log(event.coordinate);
});

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

moveend

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

map.on('moveend', function () {
  const view = map.getView();
  console.log(view.getZoom(), view.getCenter());
});

movestart

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

map.on('movestart', function () {
  console.log('Начало перемещения карты');
});

postrender

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

map.on('postrender', function () {
  console.log('Кадр отрисован');
});

События рендеринга

precompose

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

map.on('precompose', function (event) {
  const ctx = event.context;
  ctx.globalAlpha = 0.8;
});

postcompose

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

map.on('postcompose', function (event) {
  const ctx = event.context;
  ctx.fillStyle = 'rgba(0,0,0,0.1)';
});

rendercomplete

Фиксирует завершение полного цикла рендеринга карты, включая все слои и анимации.

map.on('rendercomplete', function () {
  console.log('Рендер завершён полностью');
});

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

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

  • coordinate — географическая или проекционная координата
  • pixel — экранные координаты
  • frameState — состояние рендера на момент события
  • target — источник события
  • type — строковое имя события

Для событий рендеринга дополнительно доступен объект context, предоставляющий доступ к Canvas API:

map.on('postcompose', function (event) {
  const ctx = event.context;
  ctx.save();
  ctx.restore();
});

Делегирование и фильтрация событий

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

map.on('singleclick', function (event) {
  const feature = map.forEachFeatureAtPixel(event.pixel, function (f) {
    return f;
  });

  if (feature) {
    console.log('Объект найден');
  }
});

Такой подход позволяет реализовать поведение, зависящее от слоёв, объектов или текущего масштаба.


Приоритеты и взаимодействие событий

Некоторые события имеют пересекающуюся семантику. Например, click, singleclick и dblclick формируются из одного низкоуровневого потока pointer-событий. Порядок их вызова зависит от внутреннего таймера обработки взаимодействий.

События движения карты (moveend, movestart) связаны с изменениями ol.View и могут инициироваться как пользовательскими действиями, так и программным изменением состояния:

map.getView().setZoom(10);

Подписка на изменения View

Отдельный класс событий связан с объектом View, который управляет центром, масштабом и проекцией карты:

map.getView().on('change:center', function () {
  console.log('Центр карты изменён');
});

map.getView().on('change:resolution', function () {
  console.log('Масштаб изменён');
});

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


Удаление и очистка подписок

При большом количестве обработчиков критически важно управлять их жизненным циклом. Полное удаление всех подписок выполняется через dispose:

map.dispose();

Также возможно точечное управление через сохранение ссылок на функции-обработчики и последующее удаление через un.


Особенности событийного потока

Событийная модель карты основана на следующих принципах:

  • единый поток pointer-событий
  • разделение пользовательских и рендеринговых событий
  • синхронизация с циклом отрисовки Canvas
  • независимость событий View от событий Map

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