Offscreen rendering в MapLibre GL JS представляет собой подход к отрисовке карты вне основного DOM-контекста браузера или вне видимого canvas-элемента. Этот механизм используется для задач, где необходимо генерировать карту без прямого отображения пользователю: создание изображений на сервере, генерация превью, рендеринг в Web Worker, работа с OffscreenCanvas, а также интеграция в headless-окружения.
Внутренний рендеринг MapLibre GL JS построен вокруг WebGL-контекста, который управляется через слой абстракции canvas. При offscreen-рендеринге ключевым становится разрыв между:
Рендерер MapLibre не привязан жёстко к DOM, что позволяет перенаправлять вывод в альтернативные цели при наличии совместимого canvas API.
Ключевые элементы:
1. Render loop
map._render()requestAnimationFrame или его
эмуляцию2. Style pipeline
3. GPU abstraction
В современных браузерах offscreen rendering реализуется через
OffscreenCanvas, который может быть передан в Web
Worker.
transferControlToOffscreen()// main thread
const canvas = document.createElement('canvas');
const offscreen = canvas.transferControlToOffscreen();
worker.postMessage({
type: 'init-map',
canvas: offscreen
}, [offscreen]);
// worker
import maplibregl from 'maplibre-gl';
self.onmess age = (e) => {
if (e.data.type === 'init-map') {
const map = new maplibregl.Map({
container: e.data.canvas,
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 2
});
map.on('load', () => {
map.render();
});
}
};
В обычном DOM-режиме карта привязана к событиям браузера. В offscreen-режиме поведение изменяется:
Нет:
Вместо этого используется:
map.resize()Offscreen rendering часто переводит карту в режим ручного управления:
map.triggerRepaint() — принудительный пересчёт
кадраmap.once('render', ...) — контроль завершения
кадраmap.isMoving() — проверка активности анимацииOffscreen rendering широко используется в Node.js окружениях для генерации статических изображений карт.
Типичный стек:
import { createCanvas } from 'canvas';
import maplibregl from 'maplibre-gl';
const canvas = createCanvas(800, 600);
const map = new maplibregl.Map({
container: canvas,
style: 'https://demotiles.maplibre.org/style.json',
center: [30, 50],
zoom: 4,
interactive: false
});
map.once('idle', () => {
const buffer = canvas.toBuffer('image/png');
console.log(buffer);
});
В offscreen rendering важную роль играет определение момента завершения рендера.
Событие idle возникает, когда:
map.once('idle', () => {
// карта полностью отрисована
});
Это критично для headless рендеринга, где необходимо получить финальный кадр.
Offscreen rendering позволяет разгрузить UI-поток, но вводит новые ограничения:
OffscreenCanvas требует явного контроля разрешения:
const dpr = 2;
const canvas = new OffscreenCanvas(1024 * dpr, 768 * dpr);
map.resize();
В MapLibre важно учитывать:
pixelRatioРендеринг проходит следующие стадии:
Offscreen rendering особенно чувствителен к источникам данных:
Ключевая особенность — асинхронность загрузки:
map.on('data', (e) => {
if (e.dataType === 'source' && e.isSourceLoaded) {
map.triggerRepaint();
}
});
Offscreen rendering часто применяется для генерации множества карт:
Методы зависят от окружения:
canvas.toBlob((blob) => {
// загрузка или сохранение
});
const buffer = canvas.toBuffer('image/png');
При многократном создании карт без destroy возникает деградация GPU памяти.
Canvas и viewport должны быть синхронизированы, иначе возникают артефакты.
Ранний экспорт приводит к неполным изображениям.
MapLibre использует внутренний цикл:
В worker-режиме этот цикл может быть эмулирован вручную:
function frame() {
map._render();
setTimeout(frame, 16);
}
frame();
В сложных приложениях используется разделение:
Это позволяет строить архитектуры:
Анимации камеры (zoom, rotate, flyTo) в offscreen режиме требуют:
moveendmap.flyTo({ center: [10, 20], zoom: 5 });
map.once('moveend', () => {
map.once('idle', exportImage);
});
Без DOM:
Это приводит к более детерминированному рендерингу, но требует ручного управления всеми параметрами viewport.
Offscreen rendering становится основой для горизонтального масштабирования:
Такая архитектура характерна для систем: