Создание всплывающих окон

Всплывающие окна в HERE Maps JavaScript API используются для отображения контекстной информации о географических объектах, координатах и пользовательских элементах карты. Основной механизм реализации — компонент H.ui.InfoBubble, входящий в UI-модуль API, а также DOM-ориентированные кастомные оверлеи, которые применяются в более сложных интерфейсах.

Всплывающее окно в HERE Maps представляет собой интерактивный UI-элемент, который:

  • привязывается к координатам карты (H.geo.Point);
  • автоматически позиционируется при перемещении карты;
  • поддерживает HTML-содержимое;
  • может быть связано с маркерами и событиями;
  • управляется через UI-инстанс карты (H.ui.UI).

Ключевая сущность стандартного подхода — H.ui.InfoBubble, который упрощает создание типовых информационных окон без необходимости работы с DOM напрямую.

Инициализация карты и UI

Перед созданием всплывающих окон необходимо наличие экземпляра карты и UI:

const platform = new H.service.Platform({
  apikey: 'YOUR_API_KEY'
});

const defaultLayers = platform.createDefaultLayers();

const map = new H.Map(
  document.getElementById('map'),
  defaultLayers.vector.normal.map,
  {
    center: { lat: 52.52, lng: 13.405 },
    zoom: 10,
    pixelRatio: window.devicePixelRatio
  }
);

const ui = H.ui.UI.createDefault(map, defaultLayers);

Именно объект ui управляет всплывающими окнами через коллекцию элементов интерфейса.

Создание простого InfoBubble

Базовое всплывающее окно создаётся через H.ui.InfoBubble:

const coord = { lat: 52.52, lng: 13.405 };

const bubble = new H.ui.InfoBubble(coord, {
  content: '<div>Информация о точке</div>'
});

ui.addBubble(bubble);

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

Ключевые параметры

  • координаты (lat, lng) — позиция привязки;
  • content — HTML-разметка содержимого;
  • управление через ui.addBubble и ui.removeBubble.

Привязка всплывающего окна к маркеру

Часто всплывающее окно открывается по клику на маркер:

const marker = new H.map.Marker({ lat: 52.52, lng: 13.405 });
map.addObject(marker);

marker.addEventListener('tap', (evt) => {
  const bubble = new H.ui.InfoBubble(evt.target.getGeometry(), {
    content: '<b>Берлин</b><br>Столица Германии'
  });

  ui.getBubbles().forEach(b => ui.removeBubble(b));
  ui.addBubble(bubble);
});

В этом подходе реализуется типичный сценарий: один активный popup на карте.

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

В HERE Maps отсутствует автоматическое уничтожение всплывающих окон, поэтому управление осуществляется вручную.

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

Добавление

ui.addBubble(bubble);

Удаление одного окна

ui.removeBubble(bubble);

Очистка всех окон

ui.getBubbles().forEach(b => ui.removeBubble(b));

Такой подход предотвращает накопление UI-элементов при частых взаимодействиях пользователя.

Обработка событий карты

Всплывающие окна часто создаются при клике по карте:

map.addEventListener('tap', (evt) => {
  const coord = map.screenToGeo(
    evt.currentPointer.viewportX,
    evt.currentPointer.viewportY
  );

  const bubble = new H.ui.InfoBubble(coord, {
    content: `Координаты:<br>${coord.lat.toFixed(4)}, ${coord.lng.toFixed(4)}`
  });

  ui.getBubbles().forEach(b => ui.removeBubble(b));
  ui.addBubble(bubble);
});

Здесь используется преобразование экранных координат в географические через screenToGeo.

Динамическое содержимое всплывающих окон

Содержимое может формироваться на основе внешних данных:

function createContent(data) {
  return `
    <div>
      <h4>${data.title}</h4>
      <p>${data.description}</p>
      <span>Рейтинг: ${data.rating}</span>
    </div>
  `;
}

const data = {
  title: 'Точка интереса',
  description: 'Описание объекта',
  rating: 4.7
};

const bubble = new H.ui.InfoBubble({ lat: 52.52, lng: 13.405 }, {
  content: createContent(data)
});

Такой подход часто используется при интеграции с API геоданных.

Работа с несколькими всплывающими окнами

Хотя стандартная модель предполагает одиночное активное окно, HERE Maps позволяет отображать несколько одновременно:

const points = [
  { lat: 52.52, lng: 13.405 },
  { lat: 52.5, lng: 13.4 },
  { lat: 52.49, lng: 13.39 }
];

points.forEach((p, index) => {
  const bubble = new H.ui.InfoBubble(p, {
    content: `Точка ${index + 1}`
  });

  ui.addBubble(bubble);
});

Однако при большом количестве элементов это может перегружать интерфейс и снижать читаемость карты.

Привязка к пользовательским объектам карты

Всплывающие окна могут быть связаны не только с маркерами, но и с любыми объектами H.map.Object:

const polygon = new H.map.Polygon(
  new H.geo.LineString([
    52.53, 13.40,
    52.54, 13.41,
    52.52, 13.42
  ])
);

map.addObject(polygon);

polygon.addEventListener('tap', (evt) => {
  const bubble = new H.ui.InfoBubble(evt.target.getBounds().getCenter(), {
    content: 'Полигональная область'
  });

  ui.addBubble(bubble);
});

Здесь используется центр bounding box объекта для позиционирования окна.

Стилизация всплывающих окон

Хотя InfoBubble имеет стандартный внешний вид, его содержимое полностью управляется HTML и CSS:

const bubble = new H.ui.InfoBubble(coord, {
  content: `
    <div class="custom-bubble">
      <h3>Объект</h3>
      <p>Расширенное описание</p>
    </div>
  `
});

CSS:

.custom-bubble {
  min-width: 150px;
  font-family: Arial, sans-serif;
}

.custom-bubble h3 {
  margin: 0;
  font-size: 14px;
}

Такой подход позволяет полностью интегрировать всплывающие окна в дизайн приложения.

Управление смещением и позиционированием

Позиция всплывающего окна может корректироваться с учётом визуального баланса:

const bubble = new H.ui.InfoBubble(coord, {
  content: 'Смещённое окно'
});

bubble.setPosition({
  x: 10,
  y: -20
});

Это полезно при перекрытии маркеров или плотной компоновке объектов.

Закрытие всплывающих окон

Закрытие может быть инициировано пользователем или программно:

bubble.close();

Или через UI-менеджер:

ui.removeBubble(bubble);

В большинстве сценариев предпочтительно централизованное управление через ui, чтобы избежать утечек объектов.

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

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

cluster.addEventListener('tap', (evt) => {
  const clusterBounds = evt.target.getBounds();

  const bubble = new H.ui.InfoBubble(clusterBounds.getCenter(), {
    content: 'Группа объектов'
  });

  ui.getBubbles().forEach(b => ui.removeBubble(b));
  ui.addBubble(bubble);
});

Это позволяет агрегировать информацию при масштабировании карты.

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

Наиболее устойчивые архитектурные подходы:

  • единый менеджер всплывающих окон, контролирующий состояние;
  • один активный InfoBubble на карте для предотвращения перегрузки UI;
  • разделение логики данных и рендеринга содержимого;
  • использование делегирования событий для маркеров;
  • кэширование HTML-содержимого при частых открытиях.

В сложных интерфейсах всплывающие окна часто становятся частью более крупной системы взаимодействия с картой, где они синхронизируются с боковыми панелями, фильтрами и API-запросами данных.