Событие render является одним из ключевых механизмов,
позволяющих отслеживать процесс отрисовки карты на каждом кадре. Оно
вызывается каждый раз, когда карта перерисовывается, независимо от
причины: движение камеры, изменение источника данных, анимации слоёв или
внутренние запросы перерисовки.
В отличие от событий высокого уровня (moveend,
zoomend), render относится к низкоуровневому
циклу визуализации и тесно связан с WebGL-конвейером.
map.on('render', () => {
console.log('Карта перерисована');
});
Процесс отрисовки в MapLibre GL JS можно условно разделить на несколько этапов:
Изменение состояния карты
Планирование перерисовки Внутренний механизм вызывает
map.triggerRepaint().
Композиция сцены
Отрисовка кадра
Событие render Срабатывает после завершения
очередного кадра.
Событие может вызываться десятки раз в секунду при активной интерактивности.
Состояние «покоя» карты фиксируется через событие
idle.
map.on('idle', () => {
console.log('Карта находится в стабильном состоянии');
});
Разница принципиальна: render отражает процесс,
idle — завершённое состояние.
Событие render часто применяется для построения
пользовательских анимаций поверх карты без использования внешнего
requestAnimationFrame.
map.on('render', () => {
const center = map.getCenter();
const zoom = map.getZoom();
updateCustomOverlay(center, zoom);
});
Такой подход позволяет синхронизировать кастомные WebGL-слои, DOM-оверлеи или Canvas-элементы с текущим состоянием камеры.
Высокая частота вызовов накладывает ограничения:
render приводит к деградации
производительностиОптимальный подход — минимизация логики внутри обработчика и перенос вычислений в кэшируемые структуры.
let lastZoom;
map.on('render', () => {
const zoom = map.getZoom();
if (zoom !== lastZoom) {
lastZoom = zoom;
updateZoomDependentLayers(zoom);
}
});
Метод map.triggerRepaint() напрямую влияет на генерацию
событий render. Он принудительно помечает карту как
требующую обновления.
map.triggerRepaint();
Это используется:
Без вызова triggerRepaint карта может перейти в
состояние idle, даже если внешние данные изменились.
При загрузке тайлов и GeoJSON данных render тесно связан
с событиями:
datasourcedatadataloadingКаждое обновление источника может инициировать новый цикл рендера.
map.on('sourcedata', (e) => {
if (e.isSourceLoaded) {
console.log('Источник загружен');
}
});
Типичный порядок внутри одного цикла отрисовки:
dataloadingdatarenderПри завершении всех активных задач дополнительно может быть вызван
idle.
render применяется для синхронизации внешних
интерфейсных элементов с состоянием карты:
map.on('render', () => {
const bearing = map.getBearing();
compassElement.style.transform = `rotate(${bearing}deg)`;
});
Такой подход обеспечивает точную привязку к визуальному состоянию без задержек между кадрами.
При активных изменениях камеры (flyTo,
easeTo, jumpTo) последовательность событий
становится непрерывной:
renderidlemap.flyTo({
center: [30, 50],
zoom: 10,
duration: 2000
});
Во время выполнения будут происходить многократные вызовы
render.
render, вызывающее
рекурсиюrender как замену
бизнес-логике// проблемный паттерн
map.on('render', () => {
map.setZoom(map.getZoom() + 0.01);
});
Подобный код приводит к неконтролируемому циклу перерисовки.
render часто используется как точка профилирования:
let lastTime = performance.now();
let frames = 0;
map.on('render', () => {
frames++;
const now = performance.now();
if (now - lastTime >= 1000) {
console.log('FPS:', frames);
frames = 0;
lastTime = now;
}
});
Такой подход позволяет выявлять узкие места в рендер-пайплайне.
При создании кастомных слоёв через CustomLayerInterface
событие render часто используется для синхронизации
WebGL-контекста.
const customLayer = {
onRender(gl, matrix) {
drawSomething(gl, matrix);
}
};
Хотя здесь используется собственный API слоя, он концептуально
совпадает с циклом render.