В интерфейсах картографических приложений всплывающие окна (popups)
служат для отображения контекстной информации о географических объектах.
В OpenLayers они реализуются через механизм ol.Overlay,
который позволяет привязывать HTML-элементы к координатам карты и
управлять их поведением независимо от слоёв.
Popups в этой библиотеке не являются отдельной сущностью «из коробки» — это композиция DOM-элемента и оверлея, синхронизированного с координатами карты.
Ключевой механизм реализации всплывающих окон в OpenLayers — класс
Overlay.
Overlay выполняет следующие функции:
Базовая структура popup строится вокруг контейнера:
В OpenLayers popup создаётся путём передачи DOM-элемента в
ol.Overlay:
const container = document.createElement('div');
container.className = 'ol-popup';
const content = document.createElement('div');
content.className = 'ol-popup-content';
const closer = document.createElement('div');
closer.className = 'ol-popup-closer';
closer.innerHTML = '✕';
container.appendChild(closer);
container.appendChild(content);
const overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(overlay);
Ключевые параметры:
element — DOM-узел popup;autoPan — автоматическое смещение карты при выходе
popup за пределы видимости;autoPanAnimation — анимация смещения.Основной метод управления позиционированием —
setPosition.
overlay.setPosition([lon, lat]);
В OpenLayers координаты обычно передаются в проекции карты (например, EPSG:3857), поэтому часто требуется преобразование:
const coord = ol.proj.fromLonLat([37.6173, 55.7558]);
overlay.setPosition(coord);
Скрытие popup выполняется установкой null:
overlay.setPosition(undefined);
Наиболее распространённый сценарий — отображение информации о выбранном объекте слоя.
Векторные слои в OpenLayers позволяют извлекать feature по клику
через forEachFeatureAtPixel.
map.on('singleclick', function (evt) {
const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature;
});
if (feature) {
const coordinate = evt.coordinate;
const name = feature.get('name');
content.innerHTML = `<strong>${name}</strong>`;
overlay.setPosition(coordinate);
} else {
overlay.setPosition(undefined);
}
});
В этом сценарии popup выступает как слой представления данных feature, не нарушая архитектуру слоёв карты.
В OpenLayers внешний вид popup полностью определяется CSS.
Типичная структура:
<div class="ol-popup">
<div class="ol-popup-closer"></div>
<div class="ol-popup-content"></div>
</div>
Базовые стили:
.ol-popup {
position: absolute;
background-color: white;
box-shadow: 0 1px 4px rgba(0,0,0,0.3);
padding: 10px;
border-radius: 8px;
min-width: 180px;
}
.ol-popup-closer {
position: absolute;
top: 4px;
right: 8px;
cursor: pointer;
}
.ol-popup:after {
content: '';
position: absolute;
bottom: -10px;
left: 50%;
border-width: 10px;
border-style: solid;
border-color: white transparent transparent transparent;
}
Визуальная «стрелка» реализуется исключительно CSS-границами без участия API карты.
Закрытие popup обычно связывается с очисткой позиции Overlay:
closer.oncl ick = function () {
overlay.setPosition(undefined);
closer.blur();
return false;
};
В OpenLayers отсутствие позиции автоматически исключает overlay из отображения, но DOM остаётся в дереве, что позволяет повторно использовать элемент без пересоздания.
Overlay поддерживает параметр offset, позволяющий
сместить popup относительно координаты:
const overlay = new ol.Overlay({
element: container,
offset: [0, -20]
});
Типичные случаи применения:
Механизм autoPan в OpenLayers обеспечивает видимость
popup, если он выходит за границы экрана.
autoPan: true,
autoPanAnimation: {
duration: 200
}
При активации:
При работе с плотными слоями часто возникает необходимость отображать агрегированную информацию.
Подходы:
Пример:
map.on('singleclick', function (evt) {
const features = [];
map.forEachFeatureAtPixel(evt.pixel, function (feature) {
features.push(feature);
});
if (features.length > 0) {
content.innerHTML = features
.map(f => `<div>${f.get('name')}</div>`)
.join('');
overlay.setPosition(evt.coordinate);
}
});
В OpenLayers порядок определения объектов зависит от:
hitTolerance;map.forEachFeatureAtPixel(evt.pixel, callback, {
hitTolerance: 5
});
hitTolerance расширяет область клика, что критично для
точечных объектов.
Overlay работает вне WebGL/Canvas рендеринга, что делает его относительно лёгким, но при массовом использовании возникают ограничения:
Оптимизация достигается через:
При изменении центра или масштаба карты popup автоматически пересчитывает позицию.
map.getView().animate({
center: coord,
zoom: 10,
duration: 800
});
Overlay в OpenLayers синхронизируется с трансформациями view, сохраняя привязку к географической точке без дополнительного кода.
Хотя технически возможно создавать несколько overlay, в типовых архитектурах применяется один экземпляр:
При необходимости множественных popup-ов используется массив overlay:
const overlays = [];
overlays.push(new ol.Overlay({ element: el1 }));
overlays.push(new ol.Overlay({ element: el2 }));
Каждый overlay управляется независимо, но требует синхронизации жизненного цикла.
При использовании кластерных источников:
feature.get('features');const clusterFeatures = feature.get('features');
if (clusterFeatures.length > 1) {
content.innerHTML = clusterFeatures.length + ' объектов';
}
В OpenLayers это стандартный подход для плотных точечных наборов данных.
Popup всегда привязан к координате, но событие клика предоставляет пиксель:
const coordinate = map.getCoordinateFromPixel(evt.pixel);
overlay.setPosition(coordinate);
Этот механизм позволяет:
В более сложных сценариях OpenLayers popup становится частью UI-системы:
Overlay при этом используется как контейнер для произвольного HTML, а не только для отображения информации.