В основе интеграции HTML с картой лежит принцип наложения DOM-слоя
поверх WebGL-контекста. Карта рендерится в canvas, а HTML-элементы
позиционируются относительно географических координат через проекцию
LngLat → pixel. Такой подход позволяет комбинировать
высокопроизводительную отрисовку карты с гибкой версткой интерфейсных
компонентов.
DOM-элементы не являются частью WebGL-сцены, однако синхронизируются с картой через систему трансформаций. При каждом изменении состояния карты (pan, zoom, rotate) пересчитываются координаты всех привязанных элементов.
Наиболее распространённый механизм внедрения HTML в карту —
использование Marker с опцией element.
import mapboxgl from "mapbox-gl";
const markerElement = document.createElement("div");
markerElement.className = "custom-marker";
markerElement.innerHTML = `
<div class="pin">
<span class="label">A</span>
</div>
`;
new mapboxgl.Marker({
element: markerElement,
anchor: "bottom"
})
.setLngLat([69.2401, 41.2995])
.addTo(map);
В этом подходе ключевым является полный контроль над DOM-структурой. Любая HTML-разметка, включая вложенные элементы, SVG, формы и медиа, может быть встроена внутрь маркера.
Система привязки маркеров основана на свойстве anchor,
определяющем точку соприкосновения DOM-элемента с координатой.
Основные значения:
centertopbottomleftrighttop-left,
bottom-right и т.д.)Для точного позиционирования используется CSS-трансформация
translate3d, автоматически вычисляемая библиотекой.
new mapboxgl.Marker({ anchor: "bottom" })
.setLngLat([0, 0])
.addTo(map);
HTML-маркеры полностью подчиняются CSS-каскаду. Это позволяет реализовать сложные визуальные состояния без изменения логики JavaScript.
.custom-marker {
width: 32px;
height: 32px;
background: white;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
transform: scale(1);
transition: transform 0.2s ease;
}
.custom-marker:hover {
transform: scale(1.2);
}
CSS-анимации работают независимо от карты, поскольку DOM-слой отделён от WebGL-рендера.
При большом количестве HTML-элементов возникает нагрузка на:
Рекомендуется учитывать:
transform вместо изменения
top/leftPopup-окна в Mapbox GL JS также основаны на HTML и позволяют строить сложные информационные панели.
new mapboxgl.Popup({ offset: 25 })
.setLngLat([69.2401, 41.2995])
.setHTML(`
<div class="popup-card">
<h3>Объект</h3>
<p>Описание содержимого</p>
</div>
`)
.addTo(map);
Popup создаёт отдельный DOM-контейнер, который управляется библиотекой и автоматически синхронизируется с координатами.
HTML-маркеры сохраняют стандартную модель событий браузера. Это позволяет интегрировать взаимодействие без промежуточных абстракций.
markerElement.addEventListener("click", () => {
console.log("Маркер активирован");
});
Особенность заключается в том, что события DOM не конфликтуют с
событиями карты (click, mousemove,
drag), поскольку обрабатываются в разных слоях.
IControl для кастомных HTML-компонентовИнтерфейс IControl позволяет внедрять произвольные
DOM-элементы в интерфейс карты (углы, панели, тулбары).
class CustomControl {
onAdd(map) {
this.map = map;
this.container = document.createElement("div");
this.container.className = "map-control";
this.container.innerHTML = "UI";
return this.container;
}
onRemove() {
this.container.parentNode.removeChild(this.container);
this.map = undefined;
}
}
map.addControl(new CustomControl(), "top-right");
Контролы существуют независимо от географической привязки и фиксируются относительно viewport.
HTML-слой позволяет внедрять сторонние UI-фреймворки (React, Vue, Svelte) без изменения архитектуры карты.
Типовой подход:
Marker или
ControlОсобенность заключается в необходимости учитывать частоту обновления позиции, чтобы избежать лишних ререндеров.
Каждый HTML-маркер связан с внутренним механизмом пересчёта координат при изменении состояния карты.
Ключевые триггеры:
movezoomrotateresizeПри каждом событии пересчитывается матрица проекции:
LngLat → Mercator → Screen coordinates
Несмотря на гибкость, HTML-элементы имеют архитектурные ограничения:
Поэтому HTML-слой используется преимущественно для интерактивных объектов, а не для массовой визуализации.
В рамках Mapbox GL JS применяется гибридная модель:
Такая архитектура позволяет разделять вычислительную нагрузку и обеспечивать независимость визуальных компонентов от графического рендеринга.
DOM-элементы управляются через CSS z-index, однако их
порядок дополнительно синхронизируется с внутренним порядком слоёв
карты.
.custom-marker {
position: absolute;
z-index: 10;
}
При этом карта может динамически изменять порядок элементов в зависимости от глубины слоя или приоритетов объектов.
SVG часто применяется для создания масштабируемых маркеров без потери качества при зуме.
markerElement.innerHTML = `
<svg width="40" height="40">
<circle cx="20" cy="20" r="10" fill="red"/>
</svg>
`;
SVG сохраняет чёткость при любом уровне масштабирования карты, в отличие от растровых изображений.
HTML-маркеры могут формироваться на основе данных GeoJSON, где каждый объект описывает структуру интерфейса.
data.features.forEach(feature => {
const el = document.createElement("div");
el.className = "point";
el.textContent = feature.properties.name;
new mapboxgl.Marker(el)
.setLngLat(feature.geometry.coordinates)
.addTo(map);
});
Такой подход связывает геоданные и UI-слой напрямую, без промежуточных визуализаций.
При работе с динамическими наборами данных критично корректное удаление элементов:
marker.remove();
Удаление освобождает память и отключает обработчики событий, предотвращая утечки при длительной работе карты.
При изменении угла наклона или вращении карта сохраняет согласованность DOM-слоя через компенсационные трансформации.
HTML-элементы визуально «приклеиваются» к координатам за счёт обновления матриц преобразования в каждом кадре анимации.
HTML-маркеры могут содержать полноценные интерфейсы:
При этом сохраняется независимость логики компонента от географической системы координат, что позволяет строить интерактивные GIS-интерфейсы поверх карты без модификации WebGL-слоя.