Работа с хуками

В основе архитектуры OpenLayers лежит система наблюдаемых объектов (ol/Observable) и событий, через которую реализуются все точки расширения поведения. В отличие от классических «хуков» в UI-фреймворках, здесь под хуками фактически понимаются события жизненного цикла карты, слоёв, источников данных, взаимодействий и рендеринга.

Каждый ключевой объект библиотеки — карта, представление, слой, источник данных, интеракция — наследует поведение наблюдаемого объекта и предоставляет механизм подписки на события через on, once, un.

Ключевая особенность: система событий не является вспомогательной надстройкой, а представляет собой основной способ управления состоянием и реакциями системы.


Observable как базовый механизм расширения

Базовый класс ol/Observable реализует паттерн наблюдателя. Любой объект, наследующий его, становится источником событий.

Подписка на события:

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

Одноразовая подписка:

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

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

function handler(e) {
  console.log(e);
}

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

События в OpenLayers не просто уведомления, а структурированные объекты, содержащие контекст: координаты, пиксели, состояние слоя, текущее представление карты.


Жизненный цикл карты как набор хуков

Объект ol/Map является центральным источником событий, отражающих весь цикл работы визуализации.

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

postrender и prerender

Эти события относятся к WebGL / Canvas-пайплайну рендеринга:

map.on('postrender', function (event) {
  const frameState = event.frameState;
});

frameState содержит текущее состояние сцены: масштаб, центр, вращение, разрешение, список слоёв и их состояние.

rendercomplete

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

map.on('rendercomplete', function () {
  console.log('Карта полностью отрисована');
});

Используется для экспорта изображения или синхронизации внешних процессов.

moveend и movestart

Хуки перемещения карты:

map.on('movestart', () => {
  console.log('Начало движения карты');
});

map.on('moveend', () => {
  console.log('Окончание движения карты');
});

Хуки изменения View (ol/View)

ol/View управляет состоянием камеры: центр, масштаб, проекция, вращение. Все изменения доступны через события.

Основные события представления

change:center

view.on('change:center', () => {
  console.log('Изменён центр');
});

change:resolution

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

view.on('change:resolution', () => {
  console.log('Изменён масштаб');
});

change:rotation

view.on('change:rotation', () => {
  console.log('Изменение угла поворота');
});

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


Хуки взаимодействий (Interactions)

Механизм ol/interaction предоставляет поведенческие расширения карты. Каждая интеракция также генерирует события, формируя собственные хуки.

Sel ect interaction

import Sel ect fr om 'ol/interaction/Sel ect';

const select = new Select();

select.on('select', function (e) {
  console.log('Выбрано объектов:', e.selected.length);
});

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


Draw interaction

import Draw fr om 'ol/interaction/Draw';

const draw = new Draw({
  type: 'Polygon'
});

draw.on('drawstart', function () {
  console.log('Начало рисования');
});

draw.on('drawend', function (e) {
  console.log('Завершено рисование', e.feature);
});

Хуки рисования позволяют внедрять бизнес-логику в момент создания геометрии.


Modify interaction

import Modify fr om 'ol/interaction/Modify';

const modify = new Modify({ source: vectorSource });

modify.on('modifystart', () => {
  console.log('Начало редактирования');
});

modify.on('modifyend', () => {
  console.log('Конец редактирования');
});

Хуки слоёв (Layer events)

Слои (ol/layer/Layer) также поддерживают событийную модель.

Изменение состояния слоя

layer.on('change:visible', () => {
  console.log('Видимость слоя изменилась');
});
layer.on('change:opacity', () => {
  console.log('Изменена прозрачность');
});

Хуки источников данных (Sources)

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

TileSource события

tileSource.on('tileloadstart', function (e) {
  console.log('Начало загрузки тайла');
});

tileSource.on('tileloadend', function (e) {
  console.log('Тайл загружен');
});

tileSource.on('tileloaderror', function (e) {
  console.log('Ошибка загрузки тайла');
});

Эти события критичны для реализации прогресс-баров и контроля состояния карты.


VectorSource события

vectorSource.on('addfeature', function (e) {
  console.log('Добавлен объект', e.feature);
});

vectorSource.on('removefeature', function (e) {
  console.log('Удалён объект', e.feature);
});

Хуки рендеринга слоя

OpenLayers предоставляет низкоуровневые события отрисовки, которые позволяют вмешиваться в процесс визуализации.

prerender и postrender слоя

layer.on('prerender', function (event) {
  const context = event.context;
});
layer.on('postrender', function (event) {
  const context = event.context;
});

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


FrameState как глобальный хук состояния сцены

Во время рендеринга формируется объект frameState, содержащий полное описание сцены:

  • текущий extent
  • resolution
  • rotation
  • время анимации
  • список слоёв
  • состояние источников
map.on('postrender', function (event) {
  const state = event.frameState;

  console.log(state.viewState.center);
});

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


Пользовательские хуки через Observable

Собственные расширения поведения реализуются через наследование ol/Observable.

import BaseObject fr om 'ol/Object';

class CustomModel extends BaseObject {
  setValue(val) {
    this.set('value', val);
    this.dispatchEvent('valuechange');
  }
}

const model = new CustomModel();

model.on('valuechange', () => {
  console.log('Значение изменено');
});

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


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

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

map.on('singleclick', function (e) {
  map.forEachFeatureAtPixel(e.pixel, function (feature) {
    console.log(feature);
  });
});

Этот паттерн позволяет строить «хуки клика по объектам», не привязываясь к конкретному слою.


Уровни событийной модели

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

  1. Input events — pointermove, click, dblclick
  2. Map events — moveend, render, postrender
  3. View events — change:center, change:resolution
  4. Layer events — visibility, opacity, z-index
  5. Source events — загрузка данных
  6. Interaction events — draw, select, modify

Каждый уровень предоставляет собственный набор точек расширения, при этом все они объединены общей системой Observable.


Перехват pointer-событий как универсальный хук

map.on('pointermove', function (event) {
  const coordinate = event.coordinate;
  const pixel = event.pixel;
});

Pointer-события являются фундаментом для построения пользовательских инструментов: подсветка объектов, tooltips, измерения.


Хуки синхронизации состояния

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

map.on('moveend', () => {
  const center = map.getView().getCenter();
  const zoom = map.getView().getZoom();

  syncExternalState({ center, zoom });
});

Прерывание и контроль поведения через события

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

map.on('singleclick', function (e) {
  if (e.originalEvent.ctrlKey) {
    e.preventDefault();
  }
});

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


Комбинирование хуков для построения сложных сценариев

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

  • moveend + rendercomplete — стабильное обновление данных
  • drawend + addfeature — валидация геометрии
  • tileloadend + postrender — контроль прогресса загрузки и отрисовки
  • select + change:resolution — адаптивное поведение UI

Особенности асинхронной природы событий

Многие хуки OpenLayers зависят от асинхронных процессов:

  • загрузка тайлов
  • декодирование векторных данных
  • WebGL рендеринг
  • анимации View

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


Стабилизация состояния через цепочки событий

Типичный паттерн стабилизации карты:

let rendering = false;

map.on('renderstart', () => rendering = true);
map.on('rendercomplete', () => rendering = false);

Такой подход позволяет блокировать операции до завершения отрисовки.


Расширение системы хуков через пользовательские события

map.dispatchEvent('custom:event');
map.on('custom:event', () => {
  console.log('Пользовательское событие');
});

Пользовательские события интегрируются в общую систему без необходимости модификации ядра библиотеки.


Итоговая структура событийной модели

Архитектура OpenLayers строится на единообразном механизме:

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

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