Класс Marker

В Mapbox GL JS маркеры представляют собой отдельный слой пользовательских DOM-элементов, привязанных к географическим координатам на карте WebGL. В отличие от источников и слоёв (sources и layers), маркеры не рендерятся в WebGL-пайплайне, а существуют как HTML-элементы, позиционируемые поверх карты. Это делает их гибкими для сложного UI, но менее производительными при большом количестве объектов.

Класс Marker реализует привязку DOM-элемента к координатам карты. Он работает поверх экземпляра Map и синхронизируется с его состоянием (zoom, center, bearing, pitch).

Создание маркера:

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

В основе лежит контейнерный HTMLElement, который либо создаётся библиотекой автоматически, либо передаётся разработчиком.

Конструктор и базовые параметры

Сигнатура конструктора:

new mapboxgl.Marker(options)

Основные опции:

  • element — пользовательский DOM-элемент маркера
  • anchor — точка привязки (например, "center", "top", "bottom")
  • offset — смещение маркера в пикселях
  • color — цвет стандартного маркера
  • scale — масштаб стандартного маркера
  • draggable — возможность перетаскивания

Пример:

const marker = new mapboxgl.Marker({
  color: '#ff0000',
  scale: 1.2,
  draggable: true
});

Привязка к координатам

Метод setLngLat определяет географическое положение:

marker.setLngLat([longitude, latitude]);

Внутренне координаты преобразуются в экранные пиксели с учётом текущего состояния камеры карты: зума, наклона и поворота.

Получение текущей позиции:

const lngLat = marker.getLngLat();

Добавление и удаление с карты

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

marker.addTo(map);

Удаление:

marker.remove();

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

Пользовательский HTML-элемент

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

const el = document.createElement('div');
el.className = 'custom-marker';
el.style.width = '20px';
el.style.height = '20px';
el.style.background = 'blue';

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

Это позволяет создавать сложные визуальные компоненты: аватары, SVG-иконки, мини-карточки состояния.

Перетаскивание (dragging)

При включённой опции draggable: true маркер становится интерактивным:

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

Доступны события:

  • dragstart
  • drag
  • dragend

Пример обработки:

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

При перетаскивании происходит постоянный пересчёт координат на основе позиции курсора и матрицы трансформации карты.

События маркера

Marker поддерживает проксирование DOM-событий:

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

Также доступны события через API карты при использовании popup или взаимодействий через контейнер.

Связь с Popup

Маркер часто используется вместе с всплывающими окнами:

const popup = new mapboxgl.Popup({ offset: 25 })
  .setText('Точка интереса');

new mapboxgl.Marker()
  .setLngLat([30, 50])
  .setPopup(popup)
  .addTo(map);

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

Anchor и позиционирование

Параметр anchor управляет точкой привязки DOM-элемента:

  • "center"
  • "top"
  • "bottom"
  • "left"
  • "right"
  • комбинированные варианты ("top-left", "bottom-right")

Пример:

new mapboxgl.Marker({ anchor: 'bottom' })

Это критично при работе с иконками, имеющими “ножку” (например, стандартные пины).

Offset и корректировка позиции

offset задаёт смещение в пикселях относительно географической точки:

new mapboxgl.Marker({
  offset: [0, -10]
});

Используется для точной подгонки UI-элементов, особенно при кастомных иконках разного размера.

Масштабирование и поведение при зуме

Marker не масштабируется автоматически как WebGL-слой. Его размер фиксирован в пикселях, поэтому при изменении зума:

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

Это создаёт эффект “плавающих UI-элементов”, что полезно для интерфейсных меток, но может быть ограничением при большом количестве объектов.

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

Marker основан на DOM, поэтому:

  • большое количество маркеров (сотни/тысячи) приводит к деградации производительности
  • каждое изменение карты вызывает перерасчёт позиции DOM-элементов
  • не использует GPU-рендеринг

Для массовых данных предпочтительнее использовать GeoJSONSource и circle/symbol layers внутри Mapbox GL JS.

Кастомные маркеры и сложные компоненты

Marker часто применяется как контейнер для сложного UI:

const el = document.createElement('div');

el.innerHTML = `
  <div class="card">
    <strong>Объект</strong>
    <span>Статус: активен</span>
  </div>
`;

new mapboxgl.Marker(el)
  .setLngLat([30, 50])
  .addTo(map);

Такие конструкции позволяют внедрять полноценные интерактивные элементы поверх карты.

Управление жизненным циклом

Типичный жизненный цикл:

  1. Создание экземпляра Marker
  2. Установка координат
  3. Добавление в карту
  4. Обновление позиции при необходимости
  5. Удаление из карты
marker.setLngLat([31, 51]);
marker.addTo(map);
marker.remove();

Экземпляр остаётся пригодным для повторного использования.

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

Marker автоматически подписывается на изменения:

  • move
  • zoom
  • rotate
  • pitch

При каждом изменении камеры происходит перерасчёт проекции координат в экранное пространство с использованием матрицы трансформации WebGL-сцены.

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

Marker применяется в следующих сценариях:

  • точки интереса (POI)
  • пользовательские события на карте
  • отображение динамических объектов (курьеры, транспорт)
  • интерфейсные метки с HTML-контентом

При этом архитектурно важно разделять:

  • визуальные геоданные (layers)
  • UI-объекты (Marker)

В Mapbox экосистеме это разделение считается ключевым для масштабируемых картографических приложений.