Маркеры и overlays

Базовая концепция маркеров

В Mapbox GL JS маркеры представляют собой HTML-элементы, привязанные к координатам карты. Они используются для отображения точек интереса, пользовательских объектов и интерактивных элементов поверх карты.

Основной класс для работы с маркерами — mapboxgl.Marker. Он создаёт DOM-элемент, который синхронизируется с географическими координатами.

Ключевые особенности:

  • маркеры являются HTML-слоями поверх WebGL-карты
  • легко кастомизируются через DOM
  • поддерживают события и перетаскивание
  • менее производительны при большом количестве объектов по сравнению с слоями (layers)

Создание стандартного маркера

Базовый маркер создаётся через конструктор:

const marker = new mapboxgl.Marker()
  .setLngLat([30.5, 50.5])
  .addTo(map);

Разбор этапов:

  • new mapboxgl.Marker() — создание экземпляра
  • .setLngLat([lng, lat]) — установка координат
  • .addTo(map) — добавление на карту

Удаление маркера:

marker.remove();

Кастомизация внешнего вида маркера

Маркеры могут использовать собственный HTML-элемент вместо стандартного синего пина.

const el = document.createElement('div');
el.className = 'custom-marker';
el.style.width = '20px';
el.style.height = '20px';
el.style.backgroundColor = 'red';
el.style.borderRadius = '50%';

const marker = new mapboxgl.Marker(el)
  .setLngLat([30.5, 50.5])
  .addTo(map);

Подход позволяет:

  • использовать SVG-иконки
  • добавлять сложные структуры (бейджи, аватары)
  • применять CSS-анимации

Параметры маркера

Конструктор mapboxgl.Marker поддерживает опции:

const marker = new mapboxgl.Marker({
  color: '#ff0000',
  draggable: true,
  rotation: 45,
  anchor: 'bottom'
});

Основные параметры:

  • color — цвет стандартного маркера
  • draggable — включение перетаскивания
  • rotation — поворот маркера
  • anchor — точка привязки (center, top, bottom, left, right)

Перетаскиваемые маркеры

Маркер может изменять координаты пользователем:

const marker = new mapboxgl.Marker({ draggable: true })
  .setLngLat([30.5, 50.5])
  .addTo(map);

marker.on('dragend', () => {
  const lngLat = marker.getLngLat();
  console.log(lngLat);
});

События:

  • dragstart
  • drag
  • dragend

Маркеры и производительность

Использование большого количества Marker приводит к нагрузке на DOM.

При работе с сотнями и тысячами объектов предпочтительно:

  • использовать GeoJSON Source
  • использовать symbol layer
  • включать кластеризацию

Пример слоя вместо маркеров:

map.addSource('points', {
  type: 'geojson',
  data: geojsonData
});

map.addLayer({
  id: 'points-layer',
  type: 'circle',
  source: 'points',
  paint: {
    'circle-radius': 6,
    'circle-color': '#ff0000'
  }
});

Создание всплывающего окна

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

const popup = new mapboxgl.Popup()
  .setLngLat([30.5, 50.5])
  .setHTML('<h3>Заголовок</h3><p>Описание объекта</p>')
  .addTo(map);

Привязка Popup к маркеру

const marker = new mapboxgl.Marker()
  .setLngLat([30.5, 50.5])
  .setPopup(
    new mapboxgl.Popup().setText('Информация')
  )
  .addTo(map);

Поведение:

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

Настройки Popup

new mapboxgl.Popup({
  closeButton: false,
  closeOnClick: false,
  offset: 25
});

Параметры:

  • closeButton — отображение кнопки закрытия
  • closeOnClick — закрытие при клике по карте
  • offset — смещение относительно точки привязки

Контролы как overlay-элементы

Навигационные контролы

map.addControl(new mapboxgl.NavigationControl());

Функции:

  • зум +/-
  • вращение карты

Полноэкранный режим

map.addControl(new mapboxgl.FullscreenControl());

Масштабная линейка

map.addControl(new mapboxgl.ScaleControl({
  maxWidth: 200,
  unit: 'metric'
}));

Атрибуция

map.addControl(new mapboxgl.AttributionControl({
  compact: true
}));

Пользовательские overlay через IControl

Mapbox GL JS позволяет создавать собственные UI-элементы через интерфейс IControl.

Пример кастомного overlay

class CustomControl {
  onAdd(map) {
    this.map = map;
    this.container = document.createElement('div');
    this.container.className = 'custom-control';
    this.container.textContent = 'Overlay';
    return this.container;
  }

  onRemove() {
    this.container.parentNode.removeChild(this.container);
    this.map = undefined;
  }
}

map.addControl(new CustomControl(), 'top-right');

Позиции:

  • top-left
  • top-right
  • bottom-left
  • bottom-right

HTML overlay поверх карты

Кроме контролов, можно размещать абсолютные HTML-слои:

const overlay = document.createElement('div');
overlay.style.position = 'absolute';
overlay.style.top = '10px';
overlay.style.left = '10px';
overlay.style.background = 'white';

document.body.appendChild(overlay);

Такой подход используется для:

  • сложных интерфейсов
  • панелей фильтров
  • динамических списков объектов

Разница между Marker и Layer

Marker (DOM-based)

  • HTML-элемент
  • гибкая визуализация
  • легко добавлять события
  • плохо масштабируется на тысячи объектов

Layer (WebGL-based)

  • рендеринг через GPU
  • высокая производительность
  • ограниченная кастомизация DOM
  • подходит для больших датасетов

События и взаимодействие с overlay

Клик по маркеру

marker.getElement().addEventListener('click', () => {
  console.log('clicked');
});

Работа с картой и overlay

map.on('click', (e) => {
  console.log(e.lngLat);
});

Динамическое обновление маркеров

Перемещение маркера

marker.setLngLat([31.0, 51.0]);

Обновление DOM-маркера

el.innerHTML = '<strong>New content</strong>';

Привязка маркеров к данным GeoJSON

geojson.features.forEach(feature => {
  new mapboxgl.Marker()
    .setLngLat(feature.geometry.coordinates)
    .setPopup(new mapboxgl.Popup().setText(feature.properties.name))
    .addTo(map);
});

Кластеризация как альтернатива маркерам

При большом количестве точек используется clustering:

map.addSource('points', {
  type: 'geojson',
  data: data,
  cluster: true,
  clusterMaxZoom: 14,
  clusterRadius: 50
});

Преимущества:

  • снижение нагрузки на DOM
  • оптимизация рендеринга
  • автоматическое объединение точек

Практические особенности использования overlays

  • DOM-маркеры зависят от CSS и могут конфликтовать со стилями страницы
  • Popup автоматически пересчитывает позицию при pan/zoom
  • Overlay-элементы должны учитывать трансформации карты
  • При анимациях карты все overlay пересчитываются в реальном времени

Координатная привязка и проекция

Все маркеры и overlay используют географические координаты [longitude, latitude], которые Mapbox GL JS преобразует в экранные координаты через WebGL-проекцию.

При изменении:

  • zoom
  • pitch
  • bearing

все overlay пересчитываются в соответствии с матрицей камеры карты.