Canvas source

Назначение Canvas source

Canvas source представляет собой тип источника данных, который использует HTMLCanvasElement как динамическую текстуру для отображения на карте. В отличие от растровых тайлов или векторных данных, canvas source позволяет интегрировать произвольную 2D-графику, генерируемую в реальном времени, непосредственно в систему рендеринга карты.

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

Canvas source интегрируется в систему стилей Mapbox GL JS как обычный источник данных и может использоваться совместно с любыми слоями, поддерживающими растровое отображение.


Базовая структура Canvas source

Источник типа canvas задаётся через map.addSource:

map.addSource('dynamic-canvas', {
  type: 'canvas',
  canvas: 'myCanvasId',
  coordinates: [
    [-80.425, 46.437],
    [-71.516, 46.437],
    [-71.516, 37.936],
    [-80.425, 37.936]
  ],
  animate: true
});

Параметры:

  • type — всегда "canvas"
  • canvas — DOM-элемент <canvas> или его идентификатор
  • coordinates — географические координаты четырёх углов изображения
  • animate — включает постоянное обновление источника

Геопривязка canvas

Canvas source отображается как текстура, растянутая на четырёхугольник, заданный координатами. Порядок координат строго фиксирован:

  1. Левый верхний угол
  2. Правый верхний угол
  3. Правый нижний угол
  4. Левый нижний угол

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

coordinates: [
  [lon1, lat1],
  [lon2, lat2],
  [lon3, lat3],
  [lon4, lat4]
]

Неправильный порядок координат приводит к искажению изображения или его зеркальному отображению.


Создание и управление canvas

Canvas может быть создан вручную или получен из DOM:

const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;

const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 512, 512);

После создания он передаётся в источник:

map.addSource('rect-canvas', {
  type: 'canvas',
  canvas: canvas,
  coordinates: [...]
});

Canvas остаётся обычным HTML-элементом, поэтому любые операции 2D API автоматически отражаются на карте при обновлении источника.


Анимация и параметр animate

Флаг animate: true включает режим постоянного перерисовывания. В этом режиме Mapbox GL JS повторно считывает содержимое canvas и обновляет текстуру на каждом кадре рендера.

map.addSource('animated', {
  type: 'canvas',
  canvas: canvas,
  coordinates: [...],
  animate: true
});

Применение:

  • визуализация потоков данных
  • симуляции частиц
  • динамические тепловые карты
  • эффекты свечения или движения

Без animate обновление происходит только при явном изменении источника или вызове обновления слоя.


Обновление содержимого canvas

Mapbox GL JS не управляет содержимым canvas напрямую. Обновление осуществляется через стандартный 2D контекст:

const ctx = canvas.getContext('2d');

function render() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'blue';
  ctx.fillRect(Math.random() * 512, 100, 50, 50);

  requestAnimationFrame(render);
}

render();

При включённом animate изменения автоматически отражаются на карте.


Использование в слоях

Canvas source обычно используется через слой типа raster:

map.addLayer({
  id: 'canvas-layer',
  type: 'raster',
  source: 'dynamic-canvas'
});

Слой raster интерпретирует canvas как текстуру и отображает её без дополнительных преобразований.


Координатные ограничения

Canvas source требует строго четыре координаты. Это означает:

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

При необходимости сложных форм требуется либо пересоздание источника, либо использование других типов (например, geojson + fill-extrusion).


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

Для изменения положения canvas используется setCoordinates:

const source = map.getSource('dynamic-canvas');

source.setCoordinates([
  [-81, 47],
  [-70, 47],
  [-70, 37],
  [-81, 37]
]);

Это позволяет перемещать текстуру без пересоздания canvas.


Производительность и особенности рендеринга

Canvas source является ресурсозатратным элементом при активной анимации. Основные факторы влияния:

  • частота перерисовки canvas
  • разрешение canvas (width/height)
  • масштаб карты и частота перерендеринга WebGL сцены

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

Рекомендуется:

  • ограничивать размер canvas до необходимого минимума
  • использовать requestAnimationFrame вместо setInterval
  • отключать animate при статичном содержимом

Масштабирование и пикселизация

Canvas source не автоматически адаптируется к devicePixelRatio. При высоких DPI экранах может наблюдаться размытость.

Решение:

const dpr = window.devicePixelRatio;

canvas.width = 512 * dpr;
canvas.height = 512 * dpr;

ctx.scale(dpr, dpr);

Это обеспечивает чёткое отображение на Retina-экранах.


Взаимодействие с камерой карты

Canvas source жёстко привязан к географическим координатам. При изменении:

  • масштаба карты
  • наклона (pitch)
  • вращения (bearing)

текстура трансформируется вместе с картой, сохраняя географическую привязку.

Однако сам canvas не «знает» о камере и не адаптирует своё содержимое под перспективу.


Типичные сценарии использования

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

  • моделирование погодных явлений (ветер, облака)
  • отображение тепловых распределений
  • генерация пользовательских тайлов на лету
  • визуальные эффекты поверх географии
  • интерактивные графики, привязанные к регионам

Ограничения модели

Несмотря на гибкость, canvas source имеет ряд архитектурных ограничений:

  • отсутствие векторной семантики
  • невозможность стилизации через Mapbox Style Spec
  • отсутствие семантического взаимодействия с данными карты
  • ограничение на прямоугольную проекцию

Canvas source является по сути «чёрным ящиком», который WebGL интерпретирует как текстуру.


Отличие от raster и image source

Canvas source часто сравнивается с другими типами источников:

  • raster source — статичные или тайловые изображения
  • image source — одиночное изображение с координатами
  • canvas source — динамическая текстура с возможностью перерисовки

Главное отличие заключается в том, что canvas source остаётся программно управляемым объектом, а не статическим ресурсом.


Взаимодействие с WebGL контекстом

Внутри Mapbox GL JS canvas source преобразуется в WebGL-текстуру. При каждом обновлении выполняется:

  • чтение пикселей canvas
  • загрузка данных в GPU texture
  • привязка к quad geometry

Это делает canvas source мостом между 2D Canvas API и WebGL рендерингом карты.


Практические аспекты интеграции

При построении сложных систем важно учитывать:

  • синхронизацию обновлений canvas и карты
  • управление жизненным циклом источника
  • предотвращение утечек памяти при частых пересозданиях

Оптимальная стратегия — создание одного canvas source и обновление его содержимого без удаления источника из карты.


Поведение при удалении источника

Удаление выполняется стандартно:

map.removeSource('dynamic-canvas');

После удаления связь с canvas разрывается, но сам DOM-элемент остаётся доступным и может быть переиспользован.