Настройка внешнего вида маркера

В MapLibre GL JS маркер представляет собой DOM-элемент, привязанный к координатам карты и перемещающийся вместе с ней при масштабировании и панорамировании. Базовая сущность Marker используется для отображения точек интереса, пользовательских объектов и интерактивных элементов интерфейса.

Создание маркера начинается с инстанцирования объекта:

import maplibregl from "maplibre-gl";

const marker = new maplibregl.Marker()
  .setLngLat([30.315868, 59.939095])
  .addTo(map);

По умолчанию используется стандартный SVG-элемент в виде синего пина. Однако визуальная настройка маркера в MapLibre GL JS может быть значительно расширена за счёт параметров конструктора и использования кастомных DOM-элементов.


Цвет и базовые параметры встроенного маркера

Встроенный маркер поддерживает ограниченную настройку внешнего вида через параметры конструктора:

const marker = new maplibregl.Marker({
  color: "#ff0000"
})
  .setLngLat([30.3, 59.9])
  .addTo(map);

Параметр color изменяет основной цвет SVG-маркера. Это быстрый способ визуально различать категории объектов без создания кастомного элемента.

Дополнительно используются:

  • rotation: угол поворота маркера в градусах
  • scale: масштабирование (в некоторых реализациях через CSS)
  • anchor: точка привязки (например, "center", "bottom")
  • offset: смещение относительно координаты

Пример:

const marker = new maplibregl.Marker({
  color: "#2ecc71",
  rotation: 45,
  anchor: "bottom",
  offset: [0, -10]
})
  .setLngLat([30.32, 59.93])
  .addTo(map);

Полностью кастомный HTML-маркер

Гибкость системы маркеров достигается через передачу DOM-элемента в конструктор Marker. Это позволяет полностью контролировать внешний вид: от простых иконок до сложных интерактивных компонентов.

const el = document.createElement("div");
el.className = "custom-marker";
el.innerHTML = `<div class="dot"></div>`;

const marker = new maplibregl.Marker(el)
  .setLngLat([30.31, 59.94])
  .addTo(map);

CSS-оформление:

.custom-marker {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.custom-marker .dot {
  width: 14px;
  height: 14px;
  background: #e74c3c;
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(0,0,0,0.3);
}

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

  • индикаторы состояния (онлайн/офлайн)
  • цветовые категории объектов
  • анимированные маркеры
  • сложные UI-элементы внутри карты

Использование изображений в качестве маркера

Вместо HTML-разметки можно использовать <img> как основу маркера:

const img = document.createElement("img");
img.src = "/icons/location.png";
img.style.width = "32px";
img.style.height = "32px";

const marker = new maplibregl.Marker(img)
  .setLngLat([30.33, 59.92])
  .addTo(map);

Преимущество такого подхода — простота и высокая производительность по сравнению с многослойными DOM-структурами.


Управление якорем и точкой привязки

Визуальное положение маркера относительно координаты на карте определяется параметром anchor. Он задаёт, какая точка элемента считается «географической привязкой».

Основные значения:

  • center
  • top
  • bottom
  • left
  • right
  • комбинации (top-left, bottom-right)

Пример:

new maplibregl.Marker({
  anchor: "bottom"
})
  .setLngLat([30.30, 59.93])
  .addTo(map);

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


Смещение и точная подгонка положения

Параметр offset позволяет корректировать положение маркера в пикселях:

new maplibregl.Marker({
  offset: [10, -20]
})
  .setLngLat([30.31, 59.94])
  .addTo(map);

Смещение особенно полезно при:

  • использовании теней и псевдообъёмных иконок
  • работе с нестандартными размерами элементов
  • предотвращении перекрытия маркеров

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

DOM-маркеры в MapLibre GL JS сохраняют размер в пикселях, что означает отсутствие автоматической географической масштабируемости. Это может быть как преимуществом (стабильная визуализация), так и ограничением.

Для динамического изменения внешнего вида используется обработка события zoom:

map.on("zoom", () => {
  const zoom = map.getZoom();
  const scale = Math.max(0.5, Math.min(2, zoom / 10));

  document.querySelectorAll(".custom-marker").forEach(el => {
    el.style.transform = `scale(${scale})`;
  });
});

Такой подход позволяет:

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

Стилизация через классы и состояния

HTML-маркеры могут реагировать на состояние данных через CSS-классы:

el.classList.add("active");

CSS:

.custom-marker.active {
  background: #27ae60;
  transform: scale(1.2);
}

.custom-marker.inactive {
  background: #7f8c8d;
  opacity: 0.6;
}

Это позволяет реализовывать:

  • выделение выбранных объектов
  • визуальные статусы данных
  • фильтрацию отображаемых точек

Производительность и выбор подхода

В MapLibre GL JS существует два основных подхода к отображению точек:

  1. DOM-маркеры (Marker)
  2. Слои SymbolLayer с источником GeoJSON

DOM-маркеры обеспечивают максимальную гибкость внешнего вида, но создают нагрузку на DOM при большом количестве объектов.

Сравнение:

  • DOM Marker:

    • высокая гибкость
    • низкая масштабируемость (сотни элементов уже критичны)
  • Symbol Layer:

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

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

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

map.addLayer({
  id: "points-layer",
  type: "symbol",
  source: "points",
  layout: {
    "icon-image": "marker-icon",
    "icon-size": 1
  }
});

Интерактивные маркеры и события

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

el.addEventListener("click", () => {
  el.classList.toggle("active");
});

Также доступна интеграция с картой:

marker.getElement().addEventListener("mouseenter", () => {
  marker.getElement().style.cursor = "pointer";
});

Это используется для:

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

Композиция сложных визуальных маркеров

Кастомные маркеры могут включать несколько слоёв:

el.innerHTML = `
  <div class="marker-wrapper">
    <div class="pulse"></div>
    <div class="core"></div>
  </div>
`;

CSS-анимация:

.pulse {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(231, 76, 60, 0.3);
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% { transform: scale(0.8); opacity: 1; }
  100% { transform: scale(1.5); opacity: 0; }
}

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


Ограничения DOM-маркеров в контексте рендеринга карты

DOM-маркеры рендерятся поверх WebGL-слоя карты, что создаёт архитектурное разделение:

  • карта — GPU-рендеринг
  • маркеры — DOM-слой

Это приводит к следующим особенностям:

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

По этой причине архитектура приложений часто комбинирует оба подхода: слои для массовых данных и DOM-маркеры для ключевых объектов интерфейса