UNPKG

maplair

Version:

JavaScript library for mobile-friendly interactive maps

224 lines (223 loc) • 8 kB
import { Point } from "../geometry/Point.js"; import Browser_default from "../core/Browser.js"; import { disableClickPropagation, disableScrollPropagation, on, stop, stopPropagation } from "../dom/DomEvent.js"; import { create, getPosition, setPosition } from "../dom/DomUtil.js"; import { I18n } from "../core/I18n.js"; import { Layer } from "./Layer.js"; import { FeatureGroup } from "./FeatureGroup.js"; import { Path } from "./vector/Path.js"; import { DivOverlay } from "./DivOverlay.js"; //#region src/layer/Popup.js var Popup = class Popup extends DivOverlay { static { this.setDefaultOptions({ pane: "popupPane", offset: [0, 7], maxWidth: 300, minWidth: 50, maxHeight: null, autoPan: !Browser_default.reducedMotion, autoPanPaddingTopLeft: null, autoPanPaddingBottomRight: null, autoPanPadding: [5, 5], keepInView: false, closeButton: true, autoClose: true, closeOnEscapeKey: true, className: "", trackResize: true }); } constructor(...args) { super(...args); this.callInitHooks(Popup); } openOn(map) { map = arguments.length ? map : this._source._map; if (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) map.removeLayer(map._popup); map._popup = this; return super.openOn(map); } onAdd(map) { super.onAdd(map); map.fire("popupopen", { popup: this }); if (this._source) { this._source.fire("popupopen", { popup: this }, true); if (!(this._source instanceof Path)) this._source.on("preclick", stopPropagation); } } onRemove(map) { super.onRemove(map); map.fire("popupclose", { popup: this }); if (this._source) { this._source.fire("popupclose", { popup: this }, true); if (!(this._source instanceof Path)) this._source.off("preclick", stopPropagation); } } getEvents() { const events = super.getEvents(); if (this.options.closeOnClick ?? this._map.options.closePopupOnClick) events.preclick = this.close; if (this.options.keepInView) events.moveend = this._adjustPan; return events; } _initLayout() { const prefix = "maplair-popup", container = this._container = create("div", `${prefix} ${this.options.className || ""} maplair-zoom-animated`); const wrapper = this._wrapper = create("div", `${prefix}-content-wrapper`, container); this._contentNode = create("div", `${prefix}-content`, wrapper); disableClickPropagation(container); disableScrollPropagation(this._contentNode); on(container, "contextmenu", stopPropagation); this._tipContainer = create("div", `${prefix}-tip-container`, container); this._tip = create("div", `${prefix}-tip`, this._tipContainer); if (this.options.closeButton) { const closeButton = this._closeButton = create("a", `${prefix}-close-button`, container); closeButton.setAttribute("role", "button"); closeButton.setAttribute("aria-label", I18n.translate("Close popup")); closeButton.href = "#close"; closeButton.innerHTML = "<span aria-hidden=\"true\">&#215;</span>"; on(closeButton, "click", (ev) => { ev.preventDefault(); this.close(); }); } if (this.options.trackResize) { this._resizeObserver = new ResizeObserver(((entries) => { if (!this._map) return; this._containerWidth = entries[0]?.contentRect?.width; this._containerHeight = entries[0]?.contentRect?.height; this._updateLayout(); this._updatePosition(); this._adjustPan(); })); this._resizeObserver.observe(this._contentNode); } } _updateLayout() { const container = this._contentNode, style = container.style; style.maxWidth = `${this.options.maxWidth}px`; style.minWidth = `${this.options.minWidth}px`; const maxHeight = this.options.maxHeight, scrolledClass = "maplair-popup-scrolled"; if (maxHeight && (this._containerHeight ?? container.offsetHeight) > maxHeight) { style.height = `${maxHeight}px`; container.classList.add(scrolledClass); } else container.classList.remove(scrolledClass); this._containerWidth = this._container.offsetWidth; this._containerHeight = this._container.offsetHeight; this._containerMarginBottom = parseInt(getComputedStyle(this._container).marginBottom, 10) || 0; } _animateZoom(e) { const pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center), anchor = this._getAnchor(); setPosition(this._container, pos.add(anchor)); } _adjustPan() { if (!this.options.autoPan) return; this._map._panAnim?.stop(); if (this._autopanning) { this._autopanning = false; return; } const map = this._map, marginBottom = this._containerMarginBottom ?? (parseInt(getComputedStyle(this._container).marginBottom, 10) || 0), containerHeight = this._containerHeight + marginBottom, containerWidth = this._containerWidth, layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom); layerPos._add(getPosition(this._container)); const containerPos = map.layerPointToContainerPoint(layerPos), padding = new Point(this.options.autoPanPadding), paddingTL = new Point(this.options.autoPanPaddingTopLeft ?? padding), paddingBR = new Point(this.options.autoPanPaddingBottomRight ?? padding), size = map.getSize(); let dx = 0, dy = 0; if (containerPos.x + containerWidth + paddingBR.x > size.x) dx = containerPos.x + containerWidth - size.x + paddingBR.x; if (containerPos.x - dx - paddingTL.x < 0) dx = containerPos.x - paddingTL.x; if (containerPos.y + containerHeight + paddingBR.y > size.y) dy = containerPos.y + containerHeight - size.y + paddingBR.y; if (containerPos.y - dy - paddingTL.y < 0) dy = containerPos.y - paddingTL.y; if (dx || dy) { if (this.options.keepInView) this._autopanning = true; map.fire("autopanstart").panBy([dx, dy]); } } _getAnchor() { return new Point(this._source?._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]); } static register(MaplairMap) { MaplairMap.mergeOptions({ closePopupOnClick: true }); MaplairMap.include({ openPopup(popup, latlng, options) { this._initOverlay(Popup, popup, latlng, options).openOn(this); return this; }, closePopup(popup) { popup = arguments.length ? popup : this._popup; popup?.close(); return this; } }); Layer.include({ bindPopup(content, options) { this._popup = this._initOverlay(Popup, this._popup, content, options); if (!this._popupHandlersAdded) { this.on({ click: this._openPopup, keypress: this._onKeyPress, remove: this.closePopup, move: this._movePopup }); this._popupHandlersAdded = true; } return this; }, unbindPopup() { if (this._popup) { this.off({ click: this._openPopup, keypress: this._onKeyPress, remove: this.closePopup, move: this._movePopup }); this._popupHandlersAdded = false; this._popup = null; } return this; }, openPopup(latlng) { if (this._popup) { if (!(this instanceof FeatureGroup)) this._popup._source = this; if (this._popup._prepareOpen(latlng || this._latlng)) this._popup.openOn(this._map); } return this; }, closePopup() { this._popup?.close(); return this; }, togglePopup() { this._popup?.toggle(this); return this; }, isPopupOpen() { return this._popup?.isOpen() ?? false; }, setPopupContent(content) { this._popup?.setContent(content); return this; }, getPopup() { return this._popup; }, _openPopup(e) { if (!this._popup || !this._map) return; stop(e); const target = e.propagatedFrom ?? e.target; if (this._popup._source === target && !(target instanceof Path)) { if (this._map.hasLayer(this._popup)) this.closePopup(); else this.openPopup(e.latlng); return; } this._popup._source = target; this.openPopup(e.latlng); }, _movePopup(e) { this._popup.setLatLng(e.latlng); }, _onKeyPress(e) { if (e.originalEvent.code === "Enter") this._openPopup(e); } }); } }; //#endregion export { Popup }; //# sourceMappingURL=Popup.js.map