ano-mr-site/lib/js/popup-manager.js

127 lines
5.1 KiB
JavaScript

/**
* @typedef {Object} PopupManagerArg
* @property {ol.Map} map - ol-карта
* @property {HTMLElement} popup_div - контейнер всплывающего окна
* @property {HTMLElement} [popup_close] - закрывашка
* @property {(feature: ol.Feature) => void} map_on - поведение при нажатии на map
* @property {[number, number]} offset - смещение popup
*/
/**
* Управление и создание ol-popup
*
* @class PopupManager
* @property {ol.Map} map - ol-карта
* @property {HTMLElement} popup_div - контейнер всплывающего окна
* @property {HTMLElement} [popup_close] - закрывашка
* @property {(feature: ol.Feature) => void} map_on - поведение при нажатии на map
*/
class PopupManager {
/**
* @param {PopupManagerArg} args
*/
constructor ({map, popup_div, popup_close, map_on = (feature) => {}, offset = [0, 0]}) {
/** Безопасный вызов */
recovery(
/**
* @function
* @param {PopupManager} self
*/
self => {
/** Инъекция карты */
if(map && map instanceof ol.Map) self.map = map
else throw new Error("Аргумент 'map' невалиден")
/** Инъекция поведения при нажатии на map */
this.set_map_on(map_on)
/** Инъекция popup-элемента */
if(popup_div && popup_div instanceof HTMLElement)
self.popup_div = popup_div
else throw new Error("Аргумент 'popup_div' невалиден")
/** Инициализация popup-элемента */
self.overlay = new ol.Overlay({
element: self.popup_div,
autoPan: true,
offset: offset
})
/** Регристрация overlay */
self.map.addOverlay(self.overlay)
/** Добавление поведения при нажатии на карту */
self.map.on('click', evt => {
/** Получение данных маркера */
const feature = self.map.forEachFeatureAtPixel(
evt.pixel,
(feature, _) => feature,
{ hitTolerance: 8 }
)
if(feature) {
/** Вызов переданной функции */
self.map_on(feature)
/** Прилинковка popup */
self.set_popup(feature.getGeometry().getCoordinates())
} else {
/** Олинковка popup */
self.set_popup()
}
})
/** При нажатии не на маркеры убрать popup */
document.addEventListener('click', event => {
if (!event.target.closest('.ol-viewport') && !event.target.closest('.popup')) {
self.set_popup()
}
})
/** Инъекция и инициалиазция закрывашки (если есть) */
if(popup_close) {
/** Инъекция закрывашки */
if (popup_close instanceof HTMLElement) self.popup_close = popup_close
else throw new Error("Аргумент 'popup_close' невалиден")
/** Инициаилазиця закрывашки */
self.popup_close.onclick = function () {
/** Отлинковка от координат */
self.set_popup()
/** Скрытие */
popup_close.blur()
return false
}
}
},
(...e) => {
console.log("Ошибка при инициалиазции PopupManager");
e.forEach(er => {throw er});
}
) (this)
}
/**
* @function
* @param {[number, number] | undefined} [coord] - координаты привязки
*/
set_popup = recovery(
(coord = undefined) => this.overlay.setPosition(coord),
(...e) => {
console.log("Ошибка скрытии popup (PopupManager.set_popup)");
e.forEach(er => {throw er});
}
)
/**
* Изменение поведения при нажатии на map
* @function
* @param {(feature: Object) => void} map_on - поведение при нажатии на map
*/
set_map_on = recovery(
map_on => this.map_on = map_on,
(...e) => {
console.log("Ошибка при инициалиазции PopupManager.set_map_on");
e.forEach(er => {throw er});
}
)
}