Создание попапов

Popup представляет собой всплывающий интерфейсный слой, привязанный к координате карты или к DOM-объекту. Он используется для отображения контекстной информации о геообъектах без перехода к отдельным страницам или панелям интерфейса. В архитектуре MapLibre GL JS popup является частью API Popup, который интегрируется с картой через WebGL-рендеринг и DOM-оверлеи.

Основная модель popup основана на привязке к географической точке (LngLat) и динамическом формировании содержимого через HTML или DOM-элементы.


Базовая инициализация Popup

Создание popup выполняется через конструктор maplibregl.Popup, возвращающий экземпляр всплывающего окна.

const popup = new maplibregl.Popup();

По умолчанию popup создаётся без координат и содержимого. Для отображения требуется задать позицию и контент.


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

Popup отображается на карте через метод setLngLat, принимающий массив координат [longitude, latitude].

const popup = new maplibregl.Popup()
  .setLngLat([37.6173, 55.7558])
  .setHTML("<h3>Москва</h3><p>Столица</p>")
  .addTo(map);

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

  • координаты задаются в формате [lng, lat]
  • popup фиксируется относительно географической точки
  • позиционирование автоматически пересчитывается при зуме и панорамировании

Формирование содержимого popup

HTML-контент

Метод setHTML задаёт содержимое в виде строки HTML.

popup.setHTML(`
  <div>
    <strong>Объект</strong>
    <p>Описание объекта на карте</p>
  </div>
`);

Особенности:

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

DOM-элемент

Метод setDOMContent позволяет использовать уже созданный DOM-узел.

const container = document.createElement("div");
container.className = "popup-content";
container.innerText = "Динамический контент";

popup.setDOMContent(container);

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

  • возможность сложной интерактивной логики
  • работа с событиями внутри popup
  • интеграция с UI-фреймворками

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

Popup часто используется совместно с маркерами.

const popup = new maplibregl.Popup({ offset: 25 })
  .setHTML("Маркер");

const marker = new maplibregl.Marker()
  .setLngLat([37.6173, 55.7558])
  .setPopup(popup)
  .addTo(map);

Поведение:

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

Параметры конфигурации Popup

Конструктор принимает объект настроек:

const popup = new maplibregl.Popup({
  closeButton: true,
  closeOnClick: false,
  maxWidth: "300px",
  anchor: "top"
});

closeButton

Управляет отображением кнопки закрытия.

  • true — кнопка отображается
  • false — отключена

closeOnClick

Определяет закрытие popup при клике на карту.

  • true — закрывается при клике вне popup
  • false — остаётся открытым

maxWidth

Ограничивает ширину содержимого.

  • принимает CSS-значения (200px, 20em, none)

anchor

Определяет точку привязки popup относительно координаты.

Возможные значения:

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

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

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

popup.addTo(map);

Закрытие

popup.remove();

или

popup.isOpen();

Проверка состояния позволяет управлять логикой интерфейса при множественных popup.


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

map.on("click", "cities-layer", (e) => {
  const feature = e.features[0];

  new maplibregl.Popup()
    .setLngLat(feature.geometry.coordinates)
    .setHTML(`<strong>${feature.properties.name}</strong>`)
    .addTo(map);
});

Особенности работы:

  • e.features содержит данные из vector tile слоя
  • координаты извлекаются из geometry
  • popup создаётся динамически на каждый клик

Использование с queryRenderedFeatures

Для более гибкой логики popup формируется на основе запроса к рендеру:

map.on("click", (e) => {
  const features = map.queryRenderedFeatures(e.point, {
    layers: ["cities-layer"]
  });

  if (!features.length) return;

  const feature = features[0];

  new maplibregl.Popup()
    .setLngLat(feature.geometry.coordinates)
    .setHTML(feature.properties.name)
    .addTo(map);
});

Механика:

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

Смещение popup

Параметр offset управляет смещением относительно точки привязки.

const popup = new maplibregl.Popup({
  offset: [0, -10]
});

Варианты:

  • число — одинаковое смещение по всем осям
  • объект — смещение по anchor-позициям
  • массив — точная настройка по направлениям

Автотрекинг курсора

Popup может следовать за курсором при движении мыши:

const popup = new maplibregl.Popup({
  closeButton: false,
  closeOnClick: false
});

map.on("mousemove", (e) => {
  popup
    .setLngLat(e.lngLat)
    .setHTML(`x: ${e.lngLat.lng}, y: ${e.lngLat.lat}`)
    .addTo(map);
});

Поведение:

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

Стилизация popup

Визуальное оформление управляется через CSS классы MapLibre:

  • .maplibregl-popup
  • .maplibregl-popup-content
  • .maplibregl-popup-tip

Пример кастомизации:

.maplibregl-popup-content {
  background-color: #1e1e1e;
  color: #fff;
  border-radius: 6px;
  padding: 10px;
}

.maplibregl-popup-tip {
  border-top-color: #1e1e1e;
}

Работа с множественными popup

При создании нескольких popup требуется контроль перекрытий:

let activePopup = null;

map.on("click", (e) => {
  if (activePopup) activePopup.remove();

  activePopup = new maplibregl.Popup()
    .setLngLat(e.lngLat)
    .setHTML("Новый popup")
    .addTo(map);
});

Логика:

  • хранение текущего экземпляра
  • удаление перед созданием нового
  • предотвращение накопления DOM-элементов

Интерактивные элементы внутри popup

Popup поддерживает события DOM:

const container = document.createElement("div");

const button = document.createElement("button");
button.textContent = "Действие";

button.addEventListener("click", () => {
  console.log("click inside popup");
});

container.appendChild(button);

const popup = new maplibregl.Popup()
  .setLngLat([37.6, 55.7])
  .setDOMContent(container)
  .addTo(map);

Особенности:

  • события не блокируются картой
  • DOM остаётся активным при открытом popup
  • возможно использование сложных UI-компонентов

Поведение при перемещении карты

Popup автоматически синхронизируется с состоянием карты:

  • пересчитывает позицию при zoom
  • обновляет координаты при pan
  • сохраняет привязку к географической точке

Если координата выходит за пределы viewport, popup может быть скрыт или смещён в зависимости от anchor-логики.


Контроль отображения через API карты

Popup может управляться глобально через карту:

map.closePopup();

или через хранение ссылок на экземпляры.

Модель управления:

  • локальные popup (привязанные к объектам)
  • глобальные popup (UI-слой взаимодействия)
  • временные popup (hover-интеракции)