UNPKG

leaflet

Version:

JavaScript library for mobile-friendly interactive maps

348 lines (274 loc) 8.52 kB
/* * L.Popup is used for displaying popups on the map. */ L.Map.mergeOptions({ closePopupOnClick: true }); L.Popup = L.Layer.extend({ options: { pane: 'popupPane', minWidth: 50, maxWidth: 300, // maxHeight: <Number>, offset: [0, 7], autoPan: true, autoPanPadding: [5, 5], // autoPanPaddingTopLeft: <Point>, // autoPanPaddingBottomRight: <Point>, closeButton: true, autoClose: true, // keepInView: false, // className: '', zoomAnimation: true }, initialize: function (options, source) { L.setOptions(this, options); this._source = source; }, onAdd: function (map) { this._zoomAnimated = this._zoomAnimated && this.options.zoomAnimation; if (!this._container) { this._initLayout(); } if (map._fadeAnimated) { L.DomUtil.setOpacity(this._container, 0); } clearTimeout(this._removeTimeout); this.getPane().appendChild(this._container); this.update(); if (map._fadeAnimated) { L.DomUtil.setOpacity(this._container, 1); } map.fire('popupopen', {popup: this}); if (this._source) { this._source.fire('popupopen', {popup: this}, true); } }, openOn: function (map) { map.openPopup(this); return this; }, onRemove: function (map) { if (map._fadeAnimated) { L.DomUtil.setOpacity(this._container, 0); this._removeTimeout = setTimeout(L.bind(L.DomUtil.remove, L.DomUtil, this._container), 200); } else { L.DomUtil.remove(this._container); } map.fire('popupclose', {popup: this}); if (this._source) { this._source.fire('popupclose', {popup: this}, true); } }, getLatLng: function () { return this._latlng; }, setLatLng: function (latlng) { this._latlng = L.latLng(latlng); if (this._map) { this._updatePosition(); this._adjustPan(); } return this; }, getContent: function () { return this._content; }, setContent: function (content) { this._content = content; this.update(); return this; }, getElement: function () { return this._container; }, update: function () { if (!this._map) { return; } this._container.style.visibility = 'hidden'; this._updateContent(); this._updateLayout(); this._updatePosition(); this._container.style.visibility = ''; this._adjustPan(); }, getEvents: function () { var events = { zoom: this._updatePosition, viewreset: this._updatePosition }; if (this._zoomAnimated) { events.zoomanim = this._animateZoom; } if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) { events.preclick = this._close; } if (this.options.keepInView) { events.moveend = this._adjustPan; } return events; }, isOpen: function () { return !!this._map && this._map.hasLayer(this); }, bringToFront: function () { if (this._map) { L.DomUtil.toFront(this._container); } return this; }, bringToBack: function () { if (this._map) { L.DomUtil.toBack(this._container); } return this; }, _close: function () { if (this._map) { this._map.closePopup(this); } }, _initLayout: function () { var prefix = 'leaflet-popup', container = this._container = L.DomUtil.create('div', prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide')); if (this.options.closeButton) { var closeButton = this._closeButton = L.DomUtil.create('a', prefix + '-close-button', container); closeButton.href = '#close'; closeButton.innerHTML = '&#215;'; L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this); } var wrapper = this._wrapper = L.DomUtil.create('div', prefix + '-content-wrapper', container); this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); L.DomEvent .disableClickPropagation(wrapper) .disableScrollPropagation(this._contentNode) .on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); }, _updateContent: function () { if (!this._content) { return; } var node = this._contentNode; var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content; if (typeof content === 'string') { node.innerHTML = content; } else { while (node.hasChildNodes()) { node.removeChild(node.firstChild); } node.appendChild(content); } this.fire('contentupdate'); }, _updateLayout: function () { var container = this._contentNode, style = container.style; style.width = ''; style.whiteSpace = 'nowrap'; var width = container.offsetWidth; width = Math.min(width, this.options.maxWidth); width = Math.max(width, this.options.minWidth); style.width = (width + 1) + 'px'; style.whiteSpace = ''; style.height = ''; var height = container.offsetHeight, maxHeight = this.options.maxHeight, scrolledClass = 'leaflet-popup-scrolled'; if (maxHeight && height > maxHeight) { style.height = maxHeight + 'px'; L.DomUtil.addClass(container, scrolledClass); } else { L.DomUtil.removeClass(container, scrolledClass); } this._containerWidth = this._container.offsetWidth; }, _updatePosition: function () { if (!this._map) { return; } var pos = this._map.latLngToLayerPoint(this._latlng), offset = L.point(this.options.offset); if (this._zoomAnimated) { L.DomUtil.setPosition(this._container, pos); } else { offset = offset.add(pos); } var bottom = this._containerBottom = -offset.y, left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x; // bottom position the popup in case the height of the popup changes (images loading etc) this._container.style.bottom = bottom + 'px'; this._container.style.left = left + 'px'; }, _animateZoom: function (e) { var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center); L.DomUtil.setPosition(this._container, pos); }, _adjustPan: function () { if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; } var map = this._map, containerHeight = this._container.offsetHeight, containerWidth = this._containerWidth, layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom); if (this._zoomAnimated) { layerPos._add(L.DomUtil.getPosition(this._container)); } var containerPos = map.layerPointToContainerPoint(layerPos), padding = L.point(this.options.autoPanPadding), paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding), paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding), size = map.getSize(), dx = 0, dy = 0; if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right dx = containerPos.x + containerWidth - size.x + paddingBR.x; } if (containerPos.x - dx - paddingTL.x < 0) { // left dx = containerPos.x - paddingTL.x; } if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom dy = containerPos.y + containerHeight - size.y + paddingBR.y; } if (containerPos.y - dy - paddingTL.y < 0) { // top dy = containerPos.y - paddingTL.y; } if (dx || dy) { map .fire('autopanstart') .panBy([dx, dy]); } }, _onCloseButtonClick: function (e) { this._close(); L.DomEvent.stop(e); } }); L.popup = function (options, source) { return new L.Popup(options, source); }; L.Map.include({ openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object]) if (!(popup instanceof L.Popup)) { popup = new L.Popup(options).setContent(popup); } if (latlng) { popup.setLatLng(latlng); } if (this.hasLayer(popup)) { return this; } if (this._popup && this._popup.options.autoClose) { this.closePopup(); } this._popup = popup; return this.addLayer(popup); }, closePopup: function (popup) { if (!popup || popup === this._popup) { popup = this._popup; this._popup = null; } if (popup) { this.removeLayer(popup); } return this; } });