Canvas-слои

В экосистеме HERE Technologies визуализация на карте строится вокруг слоёв, которые формируют единое графическое пространство поверх тайловой подложки. Поверх стандартных растровых и векторных слоёв активно применяется HTML5 Canvas, позволяющий создавать динамические визуальные элементы без привязки к DOM-дереву карты и без ограничения стандартными маркерами.

В контексте HERE Maps API for JavaScript canvas-слои выступают инструментом низкоуровневой отрисовки, обеспечивающим максимальную гибкость при работе с пользовательской графикой: тепловыми картами, потоками движения, анимациями, сложными геометрическими проекциями и высокочастотными обновлениями данных.


Место Canvas в слоистой модели карты

Архитектура отображения карты строится как стек слоёв:

  • базовые тайловые слои (raster / vector tiles)
  • объектные слои (маршруты, полигоны, маркеры)
  • DOM-слои (HTML-элементы поверх карты)
  • canvas-слои (пиксельная графика поверх или между слоями)

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

Ключевая особенность заключается в том, что canvas не хранит геометрические объекты в структуре карты — он хранит только изображение текущего кадра.


Принцип интеграции HTML5 Canvas с картой

Canvas-слой создаётся как отдельный HTML-элемент, синхронизированный с состоянием карты:

  • масштаб (zoom level)
  • центр карты (center)
  • угол поворота (bearing)
  • наклон (tilt, если доступен)

Каждое изменение состояния карты вызывает перерасчёт координат и перерисовку содержимого canvas.

Основная проблема, которую решает интеграция — преобразование географических координат в экранные пиксели и обратно.


Географические и экранные координаты

Работа canvas-слоя невозможна без системы трансформаций:

  • географические координаты: широта/долгота
  • мировые координаты карты (projection space)
  • экранные координаты (pixel space)

Типичный процесс преобразования:

  1. Lat/Lng → мировая проекция карты
  2. мировая проекция → пиксели viewport
  3. пиксели → canvas drawing context

В HERE Maps JavaScript API для этого используется объект viewport карты, предоставляющий методы конвертации координат.


Инициализация canvas-оверлея

Canvas обычно создаётся как отдельный слой поверх карты:

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

map.getElement().appendChild(canvas);

Размер canvas синхронизируется с размером viewport:

function resizeCanvas() {
    const size = map.getViewPort().getSize();
    canvas.width = size.w;
    canvas.height = size.h;
}

Критически важно учитывать devicePixelRatio, иначе изображение становится размытым на высокоплотных экранах:

const ratio = window.devicePixelRatio || 1;
canvas.width = size.w * ratio;
canvas.height = size.h * ratio;
ctx.scale(ratio, ratio);

Событийная модель обновления

Canvas-слой не обновляется самостоятельно. Перерисовка привязывается к событиям карты:

  • изменение центра
  • изменение масштаба
  • завершение инерционного движения
  • изменение размера viewport

Типовая модель:

map.addEventListener('mapviewchange', redraw);
map.addEventListener('mapviewchangeend', redraw);

В высоконагруженных сценариях используется requestAnimationFrame, чтобы избежать избыточных перерисовок:

function scheduleRedraw() {
    requestAnimationFrame(redraw);
}

Преобразование координат в процессе отрисовки

Основная операция canvas-слоя — перевод набора географических точек в пиксельные координаты.

const point = map.geoToScreen({ lat, lng });
ctx.fillRect(point.x, point.y, 2, 2);

Для линий и полигонов применяется последовательное преобразование массива координат:

ctx.beginPath();

path.forEach((coord, i) => {
    const p = map.geoToScreen(coord);
    if (i === 0) ctx.moveTo(p.x, p.y);
    else ctx.lineTo(p.x, p.y);
});

ctx.stroke();

Организация слоёв внутри canvas-отрисовки

Даже внутри одного canvas логически формируются подслои:

  • фоновые эффекты (heatmap, gradient fields)
  • динамические потоки (traffic flow, particles)
  • геометрические объекты (routes, areas)
  • интерактивные элементы (hover highlights)

Порядок отрисовки строго определяет визуальную иерархию.


Производительность и управление перерисовкой

Canvas-слои чувствительны к частоте обновления. Основные ограничения:

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

Оптимизация достигается через:

Кэширование экранных координат

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

Инкрементальная отрисовка

Перерисовываются только изменённые области:

ctx.clearRect(dirty.x, dirty.y, dirty.w, dirty.h);

Батчинг операций

Снижение количества вызовов fill/stroke:

  • объединение линий
  • группировка точек
  • использование Path2D

Работа с большим количеством объектов

Canvas особенно эффективен при тысячах объектов, где объектная модель карты становится узким местом.

Сценарии применения:

  • трекинг GPS-устройств в реальном времени
  • визуализация потоков транспорта
  • отображение heatmap на основе событий
  • моделирование распределённых данных

При этом объекты не становятся частью сцены карты — они остаются пикселями.


Heatmap-реализация через canvas

Тепловые карты строятся через накопление плотности точек:

  1. каждая точка добавляет вес в canvas
  2. используется радиальный градиент
  3. применяется цветовая интерполяция
const gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0, 'rgba(255,0,0,0.8)');
gradient.addColorStop(1, 'rgba(255,0,0,0)');

ctx.fillStyle = gradient;
ctx.fillRect(x - radius, y - radius, radius * 2, radius * 2);

Анимация в canvas-слое

Динамические эффекты реализуются через непрерывный цикл перерисовки:

  • перемещение частиц
  • изменение прозрачности
  • морфинг линий
function animate() {
    updateState();
    redraw();
    requestAnimationFrame(animate);
}

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


Обработка взаимодействия с пользователем

Canvas не имеет встроенной модели событий по объектам, поэтому используется обратная логика:

  1. координата клика → экранные координаты
  2. поиск ближайшего объекта вручную
  3. вычисление попадания в геометрию
map.addEventListener('tap', (e) => {
    const p = e.currentPointer.viewportX;
    const q = e.currentPointer.viewportY;
    hitTest(p, q);
});

Для сложных сцен применяются пространственные индексы (quadtree, grid indexing).


Масштабирование и адаптация к zoom level

Canvas-слой чувствителен к изменению масштаба карты. При увеличении zoom:

  • увеличивается плотность пикселей объектов
  • меняется радиус отображаемых элементов
  • пересчитываются размеры геометрии

Масштабирование часто реализуется через коэффициент:

const scale = Math.pow(2, zoom - baseZoom);

Связь canvas и объектных слоёв

Canvas-слой не заменяет объектные слои, а дополняет их:

  • объектные слои отвечают за структурированную геометрию
  • canvas — за визуальные эффекты и высокочастотные данные

Типичная архитектура комбинирует оба подхода:

  • маркеры остаются объектами карты
  • динамика движения отрисовывается в canvas
  • статическая геометрия — в vector layer

Ограничения canvas-слоёв

Несмотря на гибкость, присутствуют ограничения:

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

Canvas остаётся CPU-ориентированным инструментом, что определяет его место в архитектуре визуализации.


Типовые архитектуры использования

На практике применяются несколько шаблонов:

Overlay-слой поверх карты

Canvas полностью перекрывает карту и синхронизируется с viewport.

Интегрированный слой

Canvas работает как часть комбинированной сцены вместе с объектными слоями.

Многослойный canvas стек

Несколько canvas-слоёв разделяют разные типы данных:

  • слой анимаций
  • слой статической геометрии
  • слой интерактивных эффектов