Postrender события

В библиотеке OpenLayers процесс отрисовки карты строится вокруг циклов рендеринга, которые запускаются при изменении состояния карты: перемещении, масштабировании, изменении слоёв или данных источников. Каждый такой цикл проходит несколько стадий, завершаясь моментом, когда итоговое изображение уже сформировано и записано в canvas или WebGL-контекст. Именно на этом этапе возникает событие postrender.

postrender — это финальная точка рендер-цикла, в которой карта уже полностью отрисована, но ещё не передана в следующий кадровый цикл браузера. Это делает событие ключевым для задач постобработки, синхронизации интерфейса и кастомной графики поверх готового кадра.


Место postrender в цикле отрисовки

Типичный рендер-цикл OpenLayers включает следующие этапы:

  • подготовка состояния карты (frameState);
  • вычисление необходимых трансформаций и тайлов;
  • отрисовка слоёв (canvas/WebGL);
  • компоновка финального изображения;
  • вызов события postrender.

На этом этапе все слои уже нарисованы, и доступен финальный результат кадра.


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

Событие postrender передаёт объект, содержащий информацию о текущем состоянии рендеринга:

  • map — экземпляр карты, инициировавший рендер;
  • frameState — состояние текущего кадра (центры, масштаб, разрешение, вращение);
  • context — графический контекст canvas (если используется canvas-рендерер).

frameState играет ключевую роль, так как позволяет точно понять, в каком состоянии находится карта в момент завершения отрисовки.


Подключение обработчика postrender

Событие привязывается непосредственно к объекту карты:

import Map from 'ol/Map.js';

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

  // анализ текущего масштаба
  const zoom = frameState.viewState.zoom;

  // доступ к canvas-контексту
  if (context) {
    context.save();
    context.fillStyle = 'rgba(255, 0, 0, 0.2)';
    context.fillRect(0, 0, context.canvas.width, context.canvas.height);
    context.restore();
  }
});

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


Отличие postrender от rendercomplete

Событие rendercomplete сигнализирует о завершении логического рендеринга всех слоёв, включая асинхронные источники (тайлы, векторные данные). В отличие от него:

  • postrender вызывается на каждом кадре рендера;
  • rendercomplete вызывается один раз после завершения полной загрузки и отрисовки всех данных.

Таким образом, postrender ориентирован на непрерывные эффекты, а rendercomplete — на фиксацию завершённого состояния карты.


Использование frameState в postrender

Объект frameState содержит детализированную информацию о текущем состоянии визуализации:

  • viewState.center — координаты центра карты;
  • viewState.rotation — угол поворота;
  • viewState.resolution — текущий масштаб;
  • size — размер viewport;
  • time — временная метка кадра.

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

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

  const scale = state.resolution;

  document.body.setAttribute('data-map-scale', scale);
});

Кастомная отрисовка поверх canvas

Одно из наиболее распространённых применений postrender — добавление собственных графических элементов поверх уже готового изображения карты.

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

  if (!context) return;

  const width = context.canvas.width;
  const height = context.canvas.height;

  context.save();

  context.strokeStyle = 'blue';
  context.lineWidth = 2;
  context.strokeRect(10, 10, width - 20, height - 20);

  context.restore();
});

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


Влияние postrender на производительность

Поскольку событие вызывается на каждом кадре рендеринга, его обработчик должен выполняться максимально быстро. Любые тяжёлые вычисления внутри postrender приводят к:

  • падению частоты кадров;
  • увеличению времени отклика интерфейса;
  • перегрузке главного потока браузера.

Оптимизация обычно строится вокруг следующих принципов:

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

Анимации и синхронизация с кадрами

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

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

  const pulse = Math.sin(elapsed / 500);

  // значение pulse может использоваться для анимации элементов
});

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


Работа с несколькими слоями

При наличии нескольких слоёв postrender вызывается после завершения компоновки всех визуальных элементов. Это позволяет:

  • добавлять единые эффекты поверх всех слоёв;
  • выполнять глобальную постобработку изображения;
  • анализировать итоговое состояние сцены.

Векторные и тайловые слои не требуют отдельной синхронизации — итоговый canvas уже содержит объединённый результат.


Ограничения и особенности поведения

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

  • не гарантирует изменение состояния между вызовами;
  • может вызываться чаще, чем изменяется визуальная сцена;
  • зависит от стратегии перерисовки (idle, animation, interaction);
  • не предназначено для долгих операций или загрузки данных.

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


Связь с другими render-событиями

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

  • prerender — вызывается перед началом отрисовки;
  • postrender — вызывается после завершения кадра;
  • rendercomplete — сигнал завершения полной отрисовки всех источников.

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