UNPKG

5.95 kBJavaScriptView Raw
1import {Layer} from './Layer';
2import {FeatureGroup} from './FeatureGroup';
3import * as Util from '../core/Util';
4import {toLatLng} from '../geo/LatLng';
5import {toPoint} from '../geometry/Point';
6import * as DomUtil from '../dom/DomUtil';
7
8/*
9 * @class DivOverlay
10 * @inherits Layer
11 * @aka L.DivOverlay
12 * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
13 */
14
15// @namespace DivOverlay
16export var DivOverlay = Layer.extend({
17
18 // @section
19 // @aka DivOverlay options
20 options: {
21 // @option offset: Point = Point(0, 7)
22 // The offset of the popup position. Useful to control the anchor
23 // of the popup when opening it on some overlays.
24 offset: [0, 7],
25
26 // @option className: String = ''
27 // A custom CSS class name to assign to the popup.
28 className: '',
29
30 // @option pane: String = 'popupPane'
31 // `Map pane` where the popup will be added.
32 pane: 'popupPane'
33 },
34
35 initialize: function (options, source) {
36 Util.setOptions(this, options);
37
38 this._source = source;
39 },
40
41 onAdd: function (map) {
42 this._zoomAnimated = map._zoomAnimated;
43
44 if (!this._container) {
45 this._initLayout();
46 }
47
48 if (map._fadeAnimated) {
49 DomUtil.setOpacity(this._container, 0);
50 }
51
52 clearTimeout(this._removeTimeout);
53 this.getPane().appendChild(this._container);
54 this.update();
55
56 if (map._fadeAnimated) {
57 DomUtil.setOpacity(this._container, 1);
58 }
59
60 this.bringToFront();
61 },
62
63 onRemove: function (map) {
64 if (map._fadeAnimated) {
65 DomUtil.setOpacity(this._container, 0);
66 this._removeTimeout = setTimeout(Util.bind(DomUtil.remove, undefined, this._container), 200);
67 } else {
68 DomUtil.remove(this._container);
69 }
70 },
71
72 // @namespace Popup
73 // @method getLatLng: LatLng
74 // Returns the geographical point of popup.
75 getLatLng: function () {
76 return this._latlng;
77 },
78
79 // @method setLatLng(latlng: LatLng): this
80 // Sets the geographical point where the popup will open.
81 setLatLng: function (latlng) {
82 this._latlng = toLatLng(latlng);
83 if (this._map) {
84 this._updatePosition();
85 this._adjustPan();
86 }
87 return this;
88 },
89
90 // @method getContent: String|HTMLElement
91 // Returns the content of the popup.
92 getContent: function () {
93 return this._content;
94 },
95
96 // @method setContent(htmlContent: String|HTMLElement|Function): this
97 // Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
98 setContent: function (content) {
99 this._content = content;
100 this.update();
101 return this;
102 },
103
104 // @method getElement: String|HTMLElement
105 // Alias for [getContent()](#popup-getcontent)
106 getElement: function () {
107 return this._container;
108 },
109
110 // @method update: null
111 // Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
112 update: function () {
113 if (!this._map) { return; }
114
115 this._container.style.visibility = 'hidden';
116
117 this._updateContent();
118 this._updateLayout();
119 this._updatePosition();
120
121 this._container.style.visibility = '';
122
123 this._adjustPan();
124 },
125
126 getEvents: function () {
127 var events = {
128 zoom: this._updatePosition,
129 viewreset: this._updatePosition
130 };
131
132 if (this._zoomAnimated) {
133 events.zoomanim = this._animateZoom;
134 }
135 return events;
136 },
137
138 // @method isOpen: Boolean
139 // Returns `true` when the popup is visible on the map.
140 isOpen: function () {
141 return !!this._map && this._map.hasLayer(this);
142 },
143
144 // @method bringToFront: this
145 // Brings this popup in front of other popups (in the same map pane).
146 bringToFront: function () {
147 if (this._map) {
148 DomUtil.toFront(this._container);
149 }
150 return this;
151 },
152
153 // @method bringToBack: this
154 // Brings this popup to the back of other popups (in the same map pane).
155 bringToBack: function () {
156 if (this._map) {
157 DomUtil.toBack(this._container);
158 }
159 return this;
160 },
161
162 _prepareOpen: function (parent, layer, latlng) {
163 if (!(layer instanceof Layer)) {
164 latlng = layer;
165 layer = parent;
166 }
167
168 if (layer instanceof FeatureGroup) {
169 for (var id in parent._layers) {
170 layer = parent._layers[id];
171 break;
172 }
173 }
174
175 if (!latlng) {
176 if (layer.getCenter) {
177 latlng = layer.getCenter();
178 } else if (layer.getLatLng) {
179 latlng = layer.getLatLng();
180 } else {
181 throw new Error('Unable to get source layer LatLng.');
182 }
183 }
184
185 // set overlay source to this layer
186 this._source = layer;
187
188 // update the overlay (content, layout, ect...)
189 this.update();
190
191 return latlng;
192 },
193
194 _updateContent: function () {
195 if (!this._content) { return; }
196
197 var node = this._contentNode;
198 var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
199
200 if (typeof content === 'string') {
201 node.innerHTML = content;
202 } else {
203 while (node.hasChildNodes()) {
204 node.removeChild(node.firstChild);
205 }
206 node.appendChild(content);
207 }
208 this.fire('contentupdate');
209 },
210
211 _updatePosition: function () {
212 if (!this._map) { return; }
213
214 var pos = this._map.latLngToLayerPoint(this._latlng),
215 offset = toPoint(this.options.offset),
216 anchor = this._getAnchor();
217
218 if (this._zoomAnimated) {
219 DomUtil.setPosition(this._container, pos.add(anchor));
220 } else {
221 offset = offset.add(pos).add(anchor);
222 }
223
224 var bottom = this._containerBottom = -offset.y,
225 left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
226
227 // bottom position the popup in case the height of the popup changes (images loading etc)
228 this._container.style.bottom = bottom + 'px';
229 this._container.style.left = left + 'px';
230 },
231
232 _getAnchor: function () {
233 return [0, 0];
234 }
235
236});