HTML-маркеры в Mapbox GL JS представляют собой механизм отображения на карте произвольных DOM-элементов вместо стандартных векторных или растровых иконок. Такой подход позволяет создавать полностью кастомные интерактивные объекты: сложные бейджи, карточки, индикаторы состояния, мини-интерфейсы и динамические элементы, которые синхронизируются с координатами карты.
В отличие от стандартных SymbolLayer или
CircleLayer, HTML-маркер основан на обычном DOM-элементе,
который привязывается к координатам карты через API
Marker.
Создание маркера начинается с формирования HTML-элемента:
const el = document.createElement('div');
el.className = 'custom-marker';
el.innerHTML = '<div class="dot"></div><span>Точка</span>';
Далее элемент передаётся в конструктор:
const marker = new mapboxgl.Marker(el)
.setLngLat([30.5, 50.5])
.addTo(map);
Ключевая особенность — полный контроль над содержимым маркера через DOM.
HTML-маркеры не являются частью WebGL-рендеринга карты. Они
существуют поверх canvas-слоя и позиционируются через трансформации CSS
(transform: translate(...)), которые пересчитываются при
каждом изменении состояния карты: панорамировании, зуме или
вращении.
Это приводит к нескольким важным последствиям:
На практике HTML-маркер почти всегда включает структуру:
const el = document.createElement('div');
el.className = 'marker';
const icon = document.createElement('div');
icon.className = 'marker__icon';
const label = document.createElement('div');
label.className = 'marker__label';
label.textContent = 'Объект';
el.appendChild(icon);
el.appendChild(label);
CSS определяет внешний вид:
.marker {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
}
.marker__icon {
width: 14px;
height: 14px;
border-radius: 50%;
background: #ff4d4f;
}
.marker__label {
font-size: 12px;
color: #333;
margin-top: 4px;
}
Такой подход позволяет строить визуальные компоненты любой сложности, включая анимации и состояния.
HTML-маркеры поддерживают настройку точки привязки через
anchor:
const marker = new mapboxgl.Marker(el, {
anchor: 'bottom'
})
.setLngLat([30.5, 50.5])
.addTo(map);
Доступные значения:
centertopbottomleftrighttop-left, bottom-right)Якорь определяет, какая точка DOM-элемента совпадает с координатой на карте.
Для тонкой настройки позиционирования используется
offset:
const marker = new mapboxgl.Marker(el, {
offset: [0, -10]
})
.setLngLat([30.5, 50.5])
.addTo(map);
Offset особенно важен при нестандартных формах маркеров, где центр геометрии не совпадает с визуальным центром.
HTML-маркеры поддерживают нативные события DOM:
el.addEventListener('click', () => {
console.log('Маркер нажат');
});
Также можно комбинировать с всплывающими окнами:
const popup = new mapboxgl.Popup({ offset: 25 })
.setText('Информация об объекте');
const marker = new mapboxgl.Marker(el)
.setLngLat([30.5, 50.5])
.setPopup(popup)
.addTo(map);
Popup привязывается к маркеру и автоматически синхронизируется с его положением.
Положение маркера может изменяться в реальном времени:
marker.setLngLat([31.0, 51.0]);
Также можно полностью заменить содержимое DOM:
el.innerHTML = '<div class="updated">Новый статус</div>';
Такой подход часто используется в трекинговых системах и мониторинге объектов.
Удаление маркера из карты:
marker.remove();
При удалении DOM-элемент также исключается из слоя карты, но при этом может сохраняться в памяти, если на него остаются ссылки.
Рекомендуется явно очищать обработчики событий:
el.removeEventListener('click', handler);
HTML-маркеры являются одним из наиболее ресурсоёмких способов отображения объектов на карте.
Основные ограничения:
Практические оптимизации:
GeoJSONSourcewill-change: transformПри большом объёме данных HTML-маркеры часто комбинируются с кластеризацией:
map.addSource('points', {
type: 'geojson',
data: geojson,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
Кластеры отображаются как отдельные HTML-маркеры, содержащие число объектов:
const el = document.createElement('div');
el.className = 'cluster-marker';
el.textContent = count;
Такой подход уменьшает нагрузку и повышает читаемость карты.
HTML-маркеры могут быть интерактивными:
const marker = new mapboxgl.Marker({
element: el,
draggable: true
})
.setLngLat([30.5, 50.5])
.addTo(map);
Обработка изменения позиции:
marker.on('dragend', () => {
const lngLat = marker.getLngLat();
console.log(lngLat);
});
Это часто используется в интерфейсах выбора точки на карте.
HTML-маркеры всегда находятся поверх canvas, но порядок их наложения регулируется CSS:
.marker {
position: absolute;
z-index: 10;
}
Для сложных интерфейсов применяются уровни:
В отличие от WebGL-слоёв, HTML-маркеры не автоматически меняют визуальный масштаб.
Компенсация реализуется вручную:
map.on('zoom', () => {
const zoom = map.getZoom();
el.style.transform = `scale(${zoom / 10})`;
});
Такой подход используется для визуальной согласованности элементов при разных уровнях увеличения.
HTML-маркеры наследуют поведение DOM и могут быть адаптированы для доступности:
el.setAttribute('role', 'button');
el.setAttribute('tabindex', '0');
Обработка клавиатуры:
el.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
console.log('Активирован маркер');
}
});
Это делает возможной работу без мыши и улучшает интеграцию с вспомогательными технологиями.
В реальных приложениях HTML-маркеры часто используются вместе с WebGL-слоями:
Такой гибрид позволяет балансировать производительность и гибкость интерфейса.
При большом количестве точек создаются менеджеры маркеров:
const markers = [];
data.forEach(point => {
const marker = new mapboxgl.Marker(el.cloneNode(true))
.setLngLat(point.coords)
.addTo(map);
markers.push(marker);
});
Для массовых операций:
markers.forEach(m => m.remove());
markers.length = 0;
setLngLat в цикле анимацииHTML-маркеры автоматически синхронизируются с:
При этом пересчёт позиции происходит через внутренний layout engine, что делает важным контроль количества элементов и их сложности.