[PLUGINS] ~gis v4.41.1 --> v4.43.1
[lhc/web/www.git] / www / plugins / gis / lib / leaflet / plugins / Control.MiniMap.js
1 // Following https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md
2 (function (factory, window) {
3
4 // define an AMD module that relies on 'leaflet'
5 if (typeof define === 'function' && define.amd) {
6 define(['leaflet'], factory);
7
8 // define a Common JS module that relies on 'leaflet'
9 } else if (typeof exports === 'object') {
10 module.exports = factory(require('leaflet'));
11 }
12
13 // attach your plugin to the global 'L' variable
14 if (typeof window !== 'undefined' && window.L) {
15 window.L.Control.MiniMap = factory(L);
16 window.L.control.minimap = function (layer, options) {
17 return new window.L.Control.MiniMap(layer, options);
18 };
19 }
20 }(function (L) {
21
22 var MiniMap = L.Control.extend({
23 options: {
24 position: 'bottomright',
25 toggleDisplay: false,
26 zoomLevelOffset: -5,
27 zoomLevelFixed: false,
28 centerFixed: false,
29 zoomAnimation: false,
30 autoToggleDisplay: false,
31 minimized: false,
32 width: 150,
33 height: 150,
34 collapsedWidth: 19,
35 collapsedHeight: 19,
36 aimingRectOptions: {color: '#ff7800', weight: 1, clickable: false},
37 shadowRectOptions: {color: '#000000', weight: 1, clickable: false, opacity: 0, fillOpacity: 0},
38 strings: {hideText: 'Hide MiniMap', showText: 'Show MiniMap'},
39 mapOptions: {} // Allows definition / override of Leaflet map options.
40 },
41
42 // layer is the map layer to be shown in the minimap
43 initialize: function (layer, options) {
44 L.Util.setOptions(this, options);
45 // Make sure the aiming rects are non-clickable even if the user tries to set them clickable (most likely by forgetting to specify them false)
46 this.options.aimingRectOptions.clickable = false;
47 this.options.shadowRectOptions.clickable = false;
48 this._layer = layer;
49 },
50
51 onAdd: function (map) {
52
53 this._mainMap = map;
54
55 // Creating the container and stopping events from spilling through to the main map.
56 this._container = L.DomUtil.create('div', 'leaflet-control-minimap');
57 this._container.style.width = this.options.width + 'px';
58 this._container.style.height = this.options.height + 'px';
59 L.DomEvent.disableClickPropagation(this._container);
60 L.DomEvent.on(this._container, 'mousewheel', L.DomEvent.stopPropagation);
61
62 var mapOptions = {
63 attributionControl: false,
64 dragging: !this.options.centerFixed,
65 zoomControl: false,
66 zoomAnimation: this.options.zoomAnimation,
67 autoToggleDisplay: this.options.autoToggleDisplay,
68 touchZoom: this.options.centerFixed ? 'center' : !this._isZoomLevelFixed(),
69 scrollWheelZoom: this.options.centerFixed ? 'center' : !this._isZoomLevelFixed(),
70 doubleClickZoom: this.options.centerFixed ? 'center' : !this._isZoomLevelFixed(),
71 boxZoom: !this._isZoomLevelFixed(),
72 crs: map.options.crs
73 };
74 mapOptions = L.Util.extend(this.options.mapOptions, mapOptions); // merge with priority of the local mapOptions object.
75
76 this._miniMap = new L.Map(this._container, mapOptions);
77
78 this._miniMap.addLayer(this._layer);
79
80 // These bools are used to prevent infinite loops of the two maps notifying each other that they've moved.
81 this._mainMapMoving = false;
82 this._miniMapMoving = false;
83
84 // Keep a record of this to prevent auto toggling when the user explicitly doesn't want it.
85 this._userToggledDisplay = false;
86 this._minimized = false;
87
88 if (this.options.toggleDisplay) {
89 this._addToggleButton();
90 }
91
92 this._miniMap.whenReady(L.Util.bind(function () {
93 this._aimingRect = L.rectangle(this._mainMap.getBounds(), this.options.aimingRectOptions).addTo(this._miniMap);
94 this._shadowRect = L.rectangle(this._mainMap.getBounds(), this.options.shadowRectOptions).addTo(this._miniMap);
95 this._mainMap.on('moveend', this._onMainMapMoved, this);
96 this._mainMap.on('move', this._onMainMapMoving, this);
97 this._miniMap.on('movestart', this._onMiniMapMoveStarted, this);
98 this._miniMap.on('move', this._onMiniMapMoving, this);
99 this._miniMap.on('moveend', this._onMiniMapMoved, this);
100 }, this));
101
102 return this._container;
103 },
104
105 addTo: function (map) {
106 L.Control.prototype.addTo.call(this, map);
107
108 var center = this.options.centerFixed || this._mainMap.getCenter();
109 this._miniMap.setView(center, this._decideZoom(true));
110 this._setDisplay(this.options.minimized);
111 return this;
112 },
113
114 onRemove: function (map) {
115 this._mainMap.off('moveend', this._onMainMapMoved, this);
116 this._mainMap.off('move', this._onMainMapMoving, this);
117 this._miniMap.off('moveend', this._onMiniMapMoved, this);
118
119 this._miniMap.removeLayer(this._layer);
120 },
121
122 changeLayer: function (layer) {
123 this._miniMap.removeLayer(this._layer);
124 this._layer = layer;
125 this._miniMap.addLayer(this._layer);
126 },
127
128 _addToggleButton: function () {
129 this._toggleDisplayButton = this.options.toggleDisplay ? this._createButton(
130 '', this._toggleButtonInitialTitleText(), ('leaflet-control-minimap-toggle-display leaflet-control-minimap-toggle-display-' +
131 this.options.position), this._container, this._toggleDisplayButtonClicked, this) : undefined;
132
133 this._toggleDisplayButton.style.width = this.options.collapsedWidth + 'px';
134 this._toggleDisplayButton.style.height = this.options.collapsedHeight + 'px';
135 },
136
137 _toggleButtonInitialTitleText: function () {
138 if (this.options.minimized) {
139 return this.options.strings.showText;
140 } else {
141 return this.options.strings.hideText;
142 }
143 },
144
145 _createButton: function (html, title, className, container, fn, context) {
146 var link = L.DomUtil.create('a', className, container);
147 link.innerHTML = html;
148 link.href = '#';
149 link.title = title;
150
151 var stop = L.DomEvent.stopPropagation;
152
153 L.DomEvent
154 .on(link, 'click', stop)
155 .on(link, 'mousedown', stop)
156 .on(link, 'dblclick', stop)
157 .on(link, 'click', L.DomEvent.preventDefault)
158 .on(link, 'click', fn, context);
159
160 return link;
161 },
162
163 _toggleDisplayButtonClicked: function () {
164 this._userToggledDisplay = true;
165 if (!this._minimized) {
166 this._minimize();
167 } else {
168 this._restore();
169 }
170 },
171
172 _setDisplay: function (minimize) {
173 if (minimize !== this._minimized) {
174 if (!this._minimized) {
175 this._minimize();
176 } else {
177 this._restore();
178 }
179 }
180 },
181
182 _minimize: function () {
183 // hide the minimap
184 if (this.options.toggleDisplay) {
185 this._container.style.width = this.options.collapsedWidth + 'px';
186 this._container.style.height = this.options.collapsedHeight + 'px';
187 this._toggleDisplayButton.className += (' minimized-' + this.options.position);
188 this._toggleDisplayButton.title = this.options.strings.showText;
189 } else {
190 this._container.style.display = 'none';
191 }
192 this._minimized = true;
193 },
194
195 _restore: function () {
196 if (this.options.toggleDisplay) {
197 this._container.style.width = this.options.width + 'px';
198 this._container.style.height = this.options.height + 'px';
199 this._toggleDisplayButton.className = this._toggleDisplayButton.className
200 .replace('minimized-' + this.options.position, '');
201 this._toggleDisplayButton.title = this.options.strings.hideText;
202 } else {
203 this._container.style.display = 'block';
204 }
205 this._minimized = false;
206 },
207
208 _onMainMapMoved: function (e) {
209 if (!this._miniMapMoving) {
210 var center = this.options.centerFixed || this._mainMap.getCenter();
211
212 this._mainMapMoving = true;
213 this._miniMap.setView(center, this._decideZoom(true));
214 this._setDisplay(this._decideMinimized());
215 } else {
216 this._miniMapMoving = false;
217 }
218 this._aimingRect.setBounds(this._mainMap.getBounds());
219 },
220
221 _onMainMapMoving: function (e) {
222 this._aimingRect.setBounds(this._mainMap.getBounds());
223 },
224
225 _onMiniMapMoveStarted: function (e) {
226 if (!this.options.centerFixed) {
227 var lastAimingRect = this._aimingRect.getBounds();
228 var sw = this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest());
229 var ne = this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast());
230 this._lastAimingRectPosition = {sw: sw, ne: ne};
231 }
232 },
233
234 _onMiniMapMoving: function (e) {
235 if (!this.options.centerFixed) {
236 if (!this._mainMapMoving && this._lastAimingRectPosition) {
237 this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw), this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne)));
238 this._shadowRect.setStyle({opacity: 1, fillOpacity: 0.3});
239 }
240 }
241 },
242
243 _onMiniMapMoved: function (e) {
244 if (!this._mainMapMoving) {
245 this._miniMapMoving = true;
246 this._mainMap.setView(this._miniMap.getCenter(), this._decideZoom(false));
247 this._shadowRect.setStyle({opacity: 0, fillOpacity: 0});
248 } else {
249 this._mainMapMoving = false;
250 }
251 },
252
253 _isZoomLevelFixed: function () {
254 var zoomLevelFixed = this.options.zoomLevelFixed;
255 return this._isDefined(zoomLevelFixed) && this._isInteger(zoomLevelFixed);
256 },
257
258 _decideZoom: function (fromMaintoMini) {
259 if (!this._isZoomLevelFixed()) {
260 if (fromMaintoMini) {
261 return this._mainMap.getZoom() + this.options.zoomLevelOffset;
262 } else {
263 var currentDiff = this._miniMap.getZoom() - this._mainMap.getZoom();
264 var proposedZoom = this._miniMap.getZoom() - this.options.zoomLevelOffset;
265 var toRet;
266
267 if (currentDiff > this.options.zoomLevelOffset && this._mainMap.getZoom() < this._miniMap.getMinZoom() - this.options.zoomLevelOffset) {
268 // This means the miniMap is zoomed out to the minimum zoom level and can't zoom any more.
269 if (this._miniMap.getZoom() > this._lastMiniMapZoom) {
270 // This means the user is trying to zoom in by using the minimap, zoom the main map.
271 toRet = this._mainMap.getZoom() + 1;
272 // Also we cheat and zoom the minimap out again to keep it visually consistent.
273 this._miniMap.setZoom(this._miniMap.getZoom() - 1);
274 } else {
275 // Either the user is trying to zoom out past the mini map's min zoom or has just panned using it, we can't tell the difference.
276 // Therefore, we ignore it!
277 toRet = this._mainMap.getZoom();
278 }
279 } else {
280 // This is what happens in the majority of cases, and always if you configure the min levels + offset in a sane fashion.
281 toRet = proposedZoom;
282 }
283 this._lastMiniMapZoom = this._miniMap.getZoom();
284 return toRet;
285 }
286 } else {
287 if (fromMaintoMini) {
288 return this.options.zoomLevelFixed;
289 } else {
290 return this._mainMap.getZoom();
291 }
292 }
293 },
294
295 _decideMinimized: function () {
296 if (this._userToggledDisplay) {
297 return this._minimized;
298 }
299
300 if (this.options.autoToggleDisplay) {
301 if (this._mainMap.getBounds().contains(this._miniMap.getBounds())) {
302 return true;
303 }
304 return false;
305 }
306
307 return this._minimized;
308 },
309
310 _isInteger: function (value) {
311 return typeof value === 'number';
312 },
313
314 _isDefined: function (value) {
315 return typeof value !== 'undefined';
316 }
317 });
318
319 L.Map.mergeOptions({
320 miniMapControl: false
321 });
322
323 L.Map.addInitHook(function () {
324 if (this.options.miniMapControl) {
325 this.miniMapControl = (new MiniMap()).addTo(this);
326 }
327 });
328
329 return MiniMap;
330
331 }, window));