/** * @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}); } ) }