1 | import * as Util from '../core/Util';
|
2 | import {Evented} from '../core/Events';
|
3 | import {EPSG3857} from '../geo/crs/CRS.EPSG3857';
|
4 | import {Point, toPoint} from '../geometry/Point';
|
5 | import {Bounds, toBounds} from '../geometry/Bounds';
|
6 | import {LatLng, toLatLng} from '../geo/LatLng';
|
7 | import {LatLngBounds, toLatLngBounds} from '../geo/LatLngBounds';
|
8 | import Browser from '../core/Browser';
|
9 | import * as DomEvent from '../dom/DomEvent';
|
10 | import * as DomUtil from '../dom/DomUtil';
|
11 | import {PosAnimation} from '../dom/PosAnimation';
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | export var Map = Evented.extend({
|
33 |
|
34 | options: {
|
35 |
|
36 |
|
37 |
|
38 |
|
39 | crs: EPSG3857,
|
40 |
|
41 |
|
42 |
|
43 | center: undefined,
|
44 |
|
45 |
|
46 |
|
47 | zoom: undefined,
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | minZoom: undefined,
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | maxZoom: undefined,
|
60 |
|
61 |
|
62 |
|
63 | layers: [],
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 | maxBounds: undefined,
|
71 |
|
72 |
|
73 |
|
74 |
|
75 | renderer: undefined,
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | zoomAnimation: true,
|
83 |
|
84 |
|
85 |
|
86 | zoomAnimationThreshold: 4,
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | fadeAnimation: true,
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | markerZoomAnimation: true,
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | transform3DLimit: 8388608,
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 | zoomSnap: 1,
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | zoomDelta: 1,
|
120 |
|
121 |
|
122 |
|
123 | trackResize: true
|
124 | },
|
125 |
|
126 | initialize: function (id, options) {
|
127 | options = Util.setOptions(this, options);
|
128 |
|
129 |
|
130 |
|
131 | this._handlers = [];
|
132 | this._layers = {};
|
133 | this._zoomBoundLayers = {};
|
134 | this._sizeChanged = true;
|
135 |
|
136 | this._initContainer(id);
|
137 | this._initLayout();
|
138 |
|
139 |
|
140 | this._onResize = Util.bind(this._onResize, this);
|
141 |
|
142 | this._initEvents();
|
143 |
|
144 | if (options.maxBounds) {
|
145 | this.setMaxBounds(options.maxBounds);
|
146 | }
|
147 |
|
148 | if (options.zoom !== undefined) {
|
149 | this._zoom = this._limitZoom(options.zoom);
|
150 | }
|
151 |
|
152 | if (options.center && options.zoom !== undefined) {
|
153 | this.setView(toLatLng(options.center), options.zoom, {reset: true});
|
154 | }
|
155 |
|
156 | this.callInitHooks();
|
157 |
|
158 |
|
159 | this._zoomAnimated = DomUtil.TRANSITION && Browser.any3d && !Browser.mobileOpera &&
|
160 | this.options.zoomAnimation;
|
161 |
|
162 |
|
163 |
|
164 | if (this._zoomAnimated) {
|
165 | this._createAnimProxy();
|
166 | DomEvent.on(this._proxy, DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
|
167 | }
|
168 |
|
169 | this._addLayers(this.options.layers);
|
170 | },
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 | setView: function (center, zoom, options) {
|
179 |
|
180 | zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
|
181 | center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
|
182 | options = options || {};
|
183 |
|
184 | this._stop();
|
185 |
|
186 | if (this._loaded && !options.reset && options !== true) {
|
187 |
|
188 | if (options.animate !== undefined) {
|
189 | options.zoom = Util.extend({animate: options.animate}, options.zoom);
|
190 | options.pan = Util.extend({animate: options.animate, duration: options.duration}, options.pan);
|
191 | }
|
192 |
|
193 |
|
194 | var moved = (this._zoom !== zoom) ?
|
195 | this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
|
196 | this._tryAnimatedPan(center, options.pan);
|
197 |
|
198 | if (moved) {
|
199 |
|
200 | clearTimeout(this._sizeTimer);
|
201 | return this;
|
202 | }
|
203 | }
|
204 |
|
205 |
|
206 | this._resetView(center, zoom);
|
207 |
|
208 | return this;
|
209 | },
|
210 |
|
211 |
|
212 |
|
213 | setZoom: function (zoom, options) {
|
214 | if (!this._loaded) {
|
215 | this._zoom = zoom;
|
216 | return this;
|
217 | }
|
218 | return this.setView(this.getCenter(), zoom, {zoom: options});
|
219 | },
|
220 |
|
221 |
|
222 |
|
223 | zoomIn: function (delta, options) {
|
224 | delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
|
225 | return this.setZoom(this._zoom + delta, options);
|
226 | },
|
227 |
|
228 |
|
229 |
|
230 | zoomOut: function (delta, options) {
|
231 | delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
|
232 | return this.setZoom(this._zoom - delta, options);
|
233 | },
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 | setZoomAround: function (latlng, zoom, options) {
|
242 | var scale = this.getZoomScale(zoom),
|
243 | viewHalf = this.getSize().divideBy(2),
|
244 | containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
|
245 |
|
246 | centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
|
247 | newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
|
248 |
|
249 | return this.setView(newCenter, zoom, {zoom: options});
|
250 | },
|
251 |
|
252 | _getBoundsCenterZoom: function (bounds, options) {
|
253 |
|
254 | options = options || {};
|
255 | bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
|
256 |
|
257 | var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
|
258 | paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
|
259 |
|
260 | zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
|
261 |
|
262 | zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
|
263 |
|
264 | if (zoom === Infinity) {
|
265 | return {
|
266 | center: bounds.getCenter(),
|
267 | zoom: zoom
|
268 | };
|
269 | }
|
270 |
|
271 | var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
|
272 |
|
273 | swPoint = this.project(bounds.getSouthWest(), zoom),
|
274 | nePoint = this.project(bounds.getNorthEast(), zoom),
|
275 | center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
|
276 |
|
277 | return {
|
278 | center: center,
|
279 | zoom: zoom
|
280 | };
|
281 | },
|
282 |
|
283 |
|
284 |
|
285 |
|
286 | fitBounds: function (bounds, options) {
|
287 |
|
288 | bounds = toLatLngBounds(bounds);
|
289 |
|
290 | if (!bounds.isValid()) {
|
291 | throw new Error('Bounds are not valid.');
|
292 | }
|
293 |
|
294 | var target = this._getBoundsCenterZoom(bounds, options);
|
295 | return this.setView(target.center, target.zoom, options);
|
296 | },
|
297 |
|
298 |
|
299 |
|
300 |
|
301 | fitWorld: function (options) {
|
302 | return this.fitBounds([[-90, -180], [90, 180]], options);
|
303 | },
|
304 |
|
305 |
|
306 |
|
307 | panTo: function (center, options) {
|
308 | return this.setView(center, this._zoom, {pan: options});
|
309 | },
|
310 |
|
311 |
|
312 |
|
313 | panBy: function (offset, options) {
|
314 | offset = toPoint(offset).round();
|
315 | options = options || {};
|
316 |
|
317 | if (!offset.x && !offset.y) {
|
318 | return this.fire('moveend');
|
319 | }
|
320 |
|
321 |
|
322 | if (options.animate !== true && !this.getSize().contains(offset)) {
|
323 | this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
|
324 | return this;
|
325 | }
|
326 |
|
327 | if (!this._panAnim) {
|
328 | this._panAnim = new PosAnimation();
|
329 |
|
330 | this._panAnim.on({
|
331 | 'step': this._onPanTransitionStep,
|
332 | 'end': this._onPanTransitionEnd
|
333 | }, this);
|
334 | }
|
335 |
|
336 |
|
337 | if (!options.noMoveStart) {
|
338 | this.fire('movestart');
|
339 | }
|
340 |
|
341 |
|
342 | if (options.animate !== false) {
|
343 | DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
|
344 |
|
345 | var newPos = this._getMapPanePos().subtract(offset).round();
|
346 | this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
|
347 | } else {
|
348 | this._rawPanBy(offset);
|
349 | this.fire('move').fire('moveend');
|
350 | }
|
351 |
|
352 | return this;
|
353 | },
|
354 |
|
355 |
|
356 |
|
357 |
|
358 | flyTo: function (targetCenter, targetZoom, options) {
|
359 |
|
360 | options = options || {};
|
361 | if (options.animate === false || !Browser.any3d) {
|
362 | return this.setView(targetCenter, targetZoom, options);
|
363 | }
|
364 |
|
365 | this._stop();
|
366 |
|
367 | var from = this.project(this.getCenter()),
|
368 | to = this.project(targetCenter),
|
369 | size = this.getSize(),
|
370 | startZoom = this._zoom;
|
371 |
|
372 | targetCenter = toLatLng(targetCenter);
|
373 | targetZoom = targetZoom === undefined ? startZoom : targetZoom;
|
374 |
|
375 | var w0 = Math.max(size.x, size.y),
|
376 | w1 = w0 * this.getZoomScale(startZoom, targetZoom),
|
377 | u1 = (to.distanceTo(from)) || 1,
|
378 | rho = 1.42,
|
379 | rho2 = rho * rho;
|
380 |
|
381 | function r(i) {
|
382 | var s1 = i ? -1 : 1,
|
383 | s2 = i ? w1 : w0,
|
384 | t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
|
385 | b1 = 2 * s2 * rho2 * u1,
|
386 | b = t1 / b1,
|
387 | sq = Math.sqrt(b * b + 1) - b;
|
388 |
|
389 |
|
390 |
|
391 | var log = sq < 0.000000001 ? -18 : Math.log(sq);
|
392 |
|
393 | return log;
|
394 | }
|
395 |
|
396 | function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
|
397 | function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
|
398 | function tanh(n) { return sinh(n) / cosh(n); }
|
399 |
|
400 | var r0 = r(0);
|
401 |
|
402 | function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
|
403 | function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
|
404 |
|
405 | function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
|
406 |
|
407 | var start = Date.now(),
|
408 | S = (r(1) - r0) / rho,
|
409 | duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
|
410 |
|
411 | function frame() {
|
412 | var t = (Date.now() - start) / duration,
|
413 | s = easeOut(t) * S;
|
414 |
|
415 | if (t <= 1) {
|
416 | this._flyToFrame = Util.requestAnimFrame(frame, this);
|
417 |
|
418 | this._move(
|
419 | this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
|
420 | this.getScaleZoom(w0 / w(s), startZoom),
|
421 | {flyTo: true});
|
422 |
|
423 | } else {
|
424 | this
|
425 | ._move(targetCenter, targetZoom)
|
426 | ._moveEnd(true);
|
427 | }
|
428 | }
|
429 |
|
430 | this._moveStart(true, options.noMoveStart);
|
431 |
|
432 | frame.call(this);
|
433 | return this;
|
434 | },
|
435 |
|
436 |
|
437 |
|
438 |
|
439 | flyToBounds: function (bounds, options) {
|
440 | var target = this._getBoundsCenterZoom(bounds, options);
|
441 | return this.flyTo(target.center, target.zoom, options);
|
442 | },
|
443 |
|
444 |
|
445 |
|
446 | setMaxBounds: function (bounds) {
|
447 | bounds = toLatLngBounds(bounds);
|
448 |
|
449 | if (!bounds.isValid()) {
|
450 | this.options.maxBounds = null;
|
451 | return this.off('moveend', this._panInsideMaxBounds);
|
452 | } else if (this.options.maxBounds) {
|
453 | this.off('moveend', this._panInsideMaxBounds);
|
454 | }
|
455 |
|
456 | this.options.maxBounds = bounds;
|
457 |
|
458 | if (this._loaded) {
|
459 | this._panInsideMaxBounds();
|
460 | }
|
461 |
|
462 | return this.on('moveend', this._panInsideMaxBounds);
|
463 | },
|
464 |
|
465 |
|
466 |
|
467 | setMinZoom: function (zoom) {
|
468 | var oldZoom = this.options.minZoom;
|
469 | this.options.minZoom = zoom;
|
470 |
|
471 | if (this._loaded && oldZoom !== zoom) {
|
472 | this.fire('zoomlevelschange');
|
473 |
|
474 | if (this.getZoom() < this.options.minZoom) {
|
475 | return this.setZoom(zoom);
|
476 | }
|
477 | }
|
478 |
|
479 | return this;
|
480 | },
|
481 |
|
482 |
|
483 |
|
484 | setMaxZoom: function (zoom) {
|
485 | var oldZoom = this.options.maxZoom;
|
486 | this.options.maxZoom = zoom;
|
487 |
|
488 | if (this._loaded && oldZoom !== zoom) {
|
489 | this.fire('zoomlevelschange');
|
490 |
|
491 | if (this.getZoom() > this.options.maxZoom) {
|
492 | return this.setZoom(zoom);
|
493 | }
|
494 | }
|
495 |
|
496 | return this;
|
497 | },
|
498 |
|
499 |
|
500 |
|
501 | panInsideBounds: function (bounds, options) {
|
502 | this._enforcingBounds = true;
|
503 | var center = this.getCenter(),
|
504 | newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
|
505 |
|
506 | if (!center.equals(newCenter)) {
|
507 | this.panTo(newCenter, options);
|
508 | }
|
509 |
|
510 | this._enforcingBounds = false;
|
511 | return this;
|
512 | },
|
513 |
|
514 |
|
515 |
|
516 |
|
517 |
|
518 |
|
519 | panInside: function (latlng, options) {
|
520 | options = options || {};
|
521 |
|
522 | var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
|
523 | paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
|
524 | pixelCenter = this.project(this.getCenter()),
|
525 | pixelPoint = this.project(latlng),
|
526 | pixelBounds = this.getPixelBounds(),
|
527 | paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
|
528 | paddedSize = paddedBounds.getSize();
|
529 |
|
530 | if (!paddedBounds.contains(pixelPoint)) {
|
531 | this._enforcingBounds = true;
|
532 | var centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
|
533 | var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
|
534 | pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
|
535 | pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
|
536 | this.panTo(this.unproject(pixelCenter), options);
|
537 | this._enforcingBounds = false;
|
538 | }
|
539 | return this;
|
540 | },
|
541 |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 | invalidateSize: function (options) {
|
556 | if (!this._loaded) { return this; }
|
557 |
|
558 | options = Util.extend({
|
559 | animate: false,
|
560 | pan: true
|
561 | }, options === true ? {animate: true} : options);
|
562 |
|
563 | var oldSize = this.getSize();
|
564 | this._sizeChanged = true;
|
565 | this._lastCenter = null;
|
566 |
|
567 | var newSize = this.getSize(),
|
568 | oldCenter = oldSize.divideBy(2).round(),
|
569 | newCenter = newSize.divideBy(2).round(),
|
570 | offset = oldCenter.subtract(newCenter);
|
571 |
|
572 | if (!offset.x && !offset.y) { return this; }
|
573 |
|
574 | if (options.animate && options.pan) {
|
575 | this.panBy(offset);
|
576 |
|
577 | } else {
|
578 | if (options.pan) {
|
579 | this._rawPanBy(offset);
|
580 | }
|
581 |
|
582 | this.fire('move');
|
583 |
|
584 | if (options.debounceMoveend) {
|
585 | clearTimeout(this._sizeTimer);
|
586 | this._sizeTimer = setTimeout(Util.bind(this.fire, this, 'moveend'), 200);
|
587 | } else {
|
588 | this.fire('moveend');
|
589 | }
|
590 | }
|
591 |
|
592 |
|
593 |
|
594 |
|
595 | return this.fire('resize', {
|
596 | oldSize: oldSize,
|
597 | newSize: newSize
|
598 | });
|
599 | },
|
600 |
|
601 |
|
602 |
|
603 |
|
604 | stop: function () {
|
605 | this.setZoom(this._limitZoom(this._zoom));
|
606 | if (!this.options.zoomSnap) {
|
607 | this.fire('viewreset');
|
608 | }
|
609 | return this._stop();
|
610 | },
|
611 |
|
612 |
|
613 |
|
614 |
|
615 |
|
616 |
|
617 |
|
618 |
|
619 |
|
620 |
|
621 | locate: function (options) {
|
622 |
|
623 | options = this._locateOptions = Util.extend({
|
624 | timeout: 10000,
|
625 | watch: false
|
626 |
|
627 |
|
628 |
|
629 |
|
630 | }, options);
|
631 |
|
632 | if (!('geolocation' in navigator)) {
|
633 | this._handleGeolocationError({
|
634 | code: 0,
|
635 | message: 'Geolocation not supported.'
|
636 | });
|
637 | return this;
|
638 | }
|
639 |
|
640 | var onResponse = Util.bind(this._handleGeolocationResponse, this),
|
641 | onError = Util.bind(this._handleGeolocationError, this);
|
642 |
|
643 | if (options.watch) {
|
644 | this._locationWatchId =
|
645 | navigator.geolocation.watchPosition(onResponse, onError, options);
|
646 | } else {
|
647 | navigator.geolocation.getCurrentPosition(onResponse, onError, options);
|
648 | }
|
649 | return this;
|
650 | },
|
651 |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 | stopLocate: function () {
|
657 | if (navigator.geolocation && navigator.geolocation.clearWatch) {
|
658 | navigator.geolocation.clearWatch(this._locationWatchId);
|
659 | }
|
660 | if (this._locateOptions) {
|
661 | this._locateOptions.setView = false;
|
662 | }
|
663 | return this;
|
664 | },
|
665 |
|
666 | _handleGeolocationError: function (error) {
|
667 | if (!this._container._leaflet_id) { return; }
|
668 |
|
669 | var c = error.code,
|
670 | message = error.message ||
|
671 | (c === 1 ? 'permission denied' :
|
672 | (c === 2 ? 'position unavailable' : 'timeout'));
|
673 |
|
674 | if (this._locateOptions.setView && !this._loaded) {
|
675 | this.fitWorld();
|
676 | }
|
677 |
|
678 |
|
679 |
|
680 |
|
681 | this.fire('locationerror', {
|
682 | code: c,
|
683 | message: 'Geolocation error: ' + message + '.'
|
684 | });
|
685 | },
|
686 |
|
687 | _handleGeolocationResponse: function (pos) {
|
688 | if (!this._container._leaflet_id) { return; }
|
689 |
|
690 | var lat = pos.coords.latitude,
|
691 | lng = pos.coords.longitude,
|
692 | latlng = new LatLng(lat, lng),
|
693 | bounds = latlng.toBounds(pos.coords.accuracy * 2),
|
694 | options = this._locateOptions;
|
695 |
|
696 | if (options.setView) {
|
697 | var zoom = this.getBoundsZoom(bounds);
|
698 | this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
|
699 | }
|
700 |
|
701 | var data = {
|
702 | latlng: latlng,
|
703 | bounds: bounds,
|
704 | timestamp: pos.timestamp
|
705 | };
|
706 |
|
707 | for (var i in pos.coords) {
|
708 | if (typeof pos.coords[i] === 'number') {
|
709 | data[i] = pos.coords[i];
|
710 | }
|
711 | }
|
712 |
|
713 |
|
714 |
|
715 |
|
716 | this.fire('locationfound', data);
|
717 | },
|
718 |
|
719 |
|
720 |
|
721 |
|
722 |
|
723 | addHandler: function (name, HandlerClass) {
|
724 | if (!HandlerClass) { return this; }
|
725 |
|
726 | var handler = this[name] = new HandlerClass(this);
|
727 |
|
728 | this._handlers.push(handler);
|
729 |
|
730 | if (this.options[name]) {
|
731 | handler.enable();
|
732 | }
|
733 |
|
734 | return this;
|
735 | },
|
736 |
|
737 |
|
738 |
|
739 | remove: function () {
|
740 |
|
741 | this._initEvents(true);
|
742 | if (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }
|
743 |
|
744 | if (this._containerId !== this._container._leaflet_id) {
|
745 | throw new Error('Map container is being reused by another instance');
|
746 | }
|
747 |
|
748 | try {
|
749 |
|
750 | delete this._container._leaflet_id;
|
751 | delete this._containerId;
|
752 | } catch (e) {
|
753 |
|
754 | this._container._leaflet_id = undefined;
|
755 |
|
756 | this._containerId = undefined;
|
757 | }
|
758 |
|
759 | if (this._locationWatchId !== undefined) {
|
760 | this.stopLocate();
|
761 | }
|
762 |
|
763 | this._stop();
|
764 |
|
765 | DomUtil.remove(this._mapPane);
|
766 |
|
767 | if (this._clearControlPos) {
|
768 | this._clearControlPos();
|
769 | }
|
770 | if (this._resizeRequest) {
|
771 | Util.cancelAnimFrame(this._resizeRequest);
|
772 | this._resizeRequest = null;
|
773 | }
|
774 |
|
775 | this._clearHandlers();
|
776 |
|
777 | if (this._loaded) {
|
778 |
|
779 |
|
780 |
|
781 | this.fire('unload');
|
782 | }
|
783 |
|
784 | var i;
|
785 | for (i in this._layers) {
|
786 | this._layers[i].remove();
|
787 | }
|
788 | for (i in this._panes) {
|
789 | DomUtil.remove(this._panes[i]);
|
790 | }
|
791 |
|
792 | this._layers = [];
|
793 | this._panes = [];
|
794 | delete this._mapPane;
|
795 | delete this._renderer;
|
796 |
|
797 | return this;
|
798 | },
|
799 |
|
800 |
|
801 |
|
802 |
|
803 |
|
804 |
|
805 | createPane: function (name, container) {
|
806 | var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
|
807 | pane = DomUtil.create('div', className, container || this._mapPane);
|
808 |
|
809 | if (name) {
|
810 | this._panes[name] = pane;
|
811 | }
|
812 | return pane;
|
813 | },
|
814 |
|
815 |
|
816 |
|
817 |
|
818 |
|
819 | getCenter: function () {
|
820 | this._checkIfLoaded();
|
821 |
|
822 | if (this._lastCenter && !this._moved()) {
|
823 | return this._lastCenter;
|
824 | }
|
825 | return this.layerPointToLatLng(this._getCenterLayerPoint());
|
826 | },
|
827 |
|
828 |
|
829 |
|
830 | getZoom: function () {
|
831 | return this._zoom;
|
832 | },
|
833 |
|
834 |
|
835 |
|
836 | getBounds: function () {
|
837 | var bounds = this.getPixelBounds(),
|
838 | sw = this.unproject(bounds.getBottomLeft()),
|
839 | ne = this.unproject(bounds.getTopRight());
|
840 |
|
841 | return new LatLngBounds(sw, ne);
|
842 | },
|
843 |
|
844 |
|
845 |
|
846 | getMinZoom: function () {
|
847 | return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
|
848 | },
|
849 |
|
850 |
|
851 |
|
852 | getMaxZoom: function () {
|
853 | return this.options.maxZoom === undefined ?
|
854 | (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
|
855 | this.options.maxZoom;
|
856 | },
|
857 |
|
858 |
|
859 |
|
860 |
|
861 |
|
862 |
|
863 | getBoundsZoom: function (bounds, inside, padding) {
|
864 | bounds = toLatLngBounds(bounds);
|
865 | padding = toPoint(padding || [0, 0]);
|
866 |
|
867 | var zoom = this.getZoom() || 0,
|
868 | min = this.getMinZoom(),
|
869 | max = this.getMaxZoom(),
|
870 | nw = bounds.getNorthWest(),
|
871 | se = bounds.getSouthEast(),
|
872 | size = this.getSize().subtract(padding),
|
873 | boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
|
874 | snap = Browser.any3d ? this.options.zoomSnap : 1,
|
875 | scalex = size.x / boundsSize.x,
|
876 | scaley = size.y / boundsSize.y,
|
877 | scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
|
878 |
|
879 | zoom = this.getScaleZoom(scale, zoom);
|
880 |
|
881 | if (snap) {
|
882 | zoom = Math.round(zoom / (snap / 100)) * (snap / 100);
|
883 | zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
|
884 | }
|
885 |
|
886 | return Math.max(min, Math.min(max, zoom));
|
887 | },
|
888 |
|
889 |
|
890 |
|
891 | getSize: function () {
|
892 | if (!this._size || this._sizeChanged) {
|
893 | this._size = new Point(
|
894 | this._container.clientWidth || 0,
|
895 | this._container.clientHeight || 0);
|
896 |
|
897 | this._sizeChanged = false;
|
898 | }
|
899 | return this._size.clone();
|
900 | },
|
901 |
|
902 |
|
903 |
|
904 |
|
905 | getPixelBounds: function (center, zoom) {
|
906 | var topLeftPoint = this._getTopLeftPoint(center, zoom);
|
907 | return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
|
908 | },
|
909 |
|
910 |
|
911 |
|
912 |
|
913 |
|
914 |
|
915 |
|
916 | getPixelOrigin: function () {
|
917 | this._checkIfLoaded();
|
918 | return this._pixelOrigin;
|
919 | },
|
920 |
|
921 |
|
922 |
|
923 |
|
924 | getPixelWorldBounds: function (zoom) {
|
925 | return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
|
926 | },
|
927 |
|
928 |
|
929 |
|
930 |
|
931 |
|
932 | getPane: function (pane) {
|
933 | return typeof pane === 'string' ? this._panes[pane] : pane;
|
934 | },
|
935 |
|
936 |
|
937 |
|
938 |
|
939 | getPanes: function () {
|
940 | return this._panes;
|
941 | },
|
942 |
|
943 |
|
944 |
|
945 | getContainer: function () {
|
946 | return this._container;
|
947 | },
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 |
|
955 | getZoomScale: function (toZoom, fromZoom) {
|
956 |
|
957 | var crs = this.options.crs;
|
958 | fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
|
959 | return crs.scale(toZoom) / crs.scale(fromZoom);
|
960 | },
|
961 |
|
962 |
|
963 |
|
964 |
|
965 |
|
966 | getScaleZoom: function (scale, fromZoom) {
|
967 | var crs = this.options.crs;
|
968 | fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
|
969 | var zoom = crs.zoom(scale * crs.scale(fromZoom));
|
970 | return isNaN(zoom) ? Infinity : zoom;
|
971 | },
|
972 |
|
973 |
|
974 |
|
975 |
|
976 |
|
977 |
|
978 | project: function (latlng, zoom) {
|
979 | zoom = zoom === undefined ? this._zoom : zoom;
|
980 | return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
|
981 | },
|
982 |
|
983 |
|
984 |
|
985 | unproject: function (point, zoom) {
|
986 | zoom = zoom === undefined ? this._zoom : zoom;
|
987 | return this.options.crs.pointToLatLng(toPoint(point), zoom);
|
988 | },
|
989 |
|
990 |
|
991 |
|
992 |
|
993 | layerPointToLatLng: function (point) {
|
994 | var projectedPoint = toPoint(point).add(this.getPixelOrigin());
|
995 | return this.unproject(projectedPoint);
|
996 | },
|
997 |
|
998 |
|
999 |
|
1000 |
|
1001 | latLngToLayerPoint: function (latlng) {
|
1002 | var projectedPoint = this.project(toLatLng(latlng))._round();
|
1003 | return projectedPoint._subtract(this.getPixelOrigin());
|
1004 | },
|
1005 |
|
1006 |
|
1007 |
|
1008 |
|
1009 |
|
1010 |
|
1011 |
|
1012 | wrapLatLng: function (latlng) {
|
1013 | return this.options.crs.wrapLatLng(toLatLng(latlng));
|
1014 | },
|
1015 |
|
1016 |
|
1017 |
|
1018 |
|
1019 |
|
1020 |
|
1021 |
|
1022 | wrapLatLngBounds: function (latlng) {
|
1023 | return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
|
1024 | },
|
1025 |
|
1026 |
|
1027 |
|
1028 |
|
1029 | distance: function (latlng1, latlng2) {
|
1030 | return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
|
1031 | },
|
1032 |
|
1033 |
|
1034 |
|
1035 |
|
1036 | containerPointToLayerPoint: function (point) {
|
1037 | return toPoint(point).subtract(this._getMapPanePos());
|
1038 | },
|
1039 |
|
1040 |
|
1041 |
|
1042 |
|
1043 | layerPointToContainerPoint: function (point) {
|
1044 | return toPoint(point).add(this._getMapPanePos());
|
1045 | },
|
1046 |
|
1047 |
|
1048 |
|
1049 |
|
1050 | containerPointToLatLng: function (point) {
|
1051 | var layerPoint = this.containerPointToLayerPoint(toPoint(point));
|
1052 | return this.layerPointToLatLng(layerPoint);
|
1053 | },
|
1054 |
|
1055 |
|
1056 |
|
1057 |
|
1058 | latLngToContainerPoint: function (latlng) {
|
1059 | return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
|
1060 | },
|
1061 |
|
1062 |
|
1063 |
|
1064 |
|
1065 | mouseEventToContainerPoint: function (e) {
|
1066 | return DomEvent.getMousePosition(e, this._container);
|
1067 | },
|
1068 |
|
1069 |
|
1070 |
|
1071 |
|
1072 | mouseEventToLayerPoint: function (e) {
|
1073 | return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
|
1074 | },
|
1075 |
|
1076 |
|
1077 |
|
1078 |
|
1079 | mouseEventToLatLng: function (e) {
|
1080 | return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
|
1081 | },
|
1082 |
|
1083 |
|
1084 |
|
1085 |
|
1086 | _initContainer: function (id) {
|
1087 | var container = this._container = DomUtil.get(id);
|
1088 |
|
1089 | if (!container) {
|
1090 | throw new Error('Map container not found.');
|
1091 | } else if (container._leaflet_id) {
|
1092 | throw new Error('Map container is already initialized.');
|
1093 | }
|
1094 |
|
1095 | DomEvent.on(container, 'scroll', this._onScroll, this);
|
1096 | this._containerId = Util.stamp(container);
|
1097 | },
|
1098 |
|
1099 | _initLayout: function () {
|
1100 | var container = this._container;
|
1101 |
|
1102 | this._fadeAnimated = this.options.fadeAnimation && Browser.any3d;
|
1103 |
|
1104 | DomUtil.addClass(container, 'leaflet-container' +
|
1105 | (Browser.touch ? ' leaflet-touch' : '') +
|
1106 | (Browser.retina ? ' leaflet-retina' : '') +
|
1107 | (Browser.ielt9 ? ' leaflet-oldie' : '') +
|
1108 | (Browser.safari ? ' leaflet-safari' : '') +
|
1109 | (this._fadeAnimated ? ' leaflet-fade-anim' : ''));
|
1110 |
|
1111 | var position = DomUtil.getStyle(container, 'position');
|
1112 |
|
1113 | if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
|
1114 | container.style.position = 'relative';
|
1115 | }
|
1116 |
|
1117 | this._initPanes();
|
1118 |
|
1119 | if (this._initControlPos) {
|
1120 | this._initControlPos();
|
1121 | }
|
1122 | },
|
1123 |
|
1124 | _initPanes: function () {
|
1125 | var panes = this._panes = {};
|
1126 | this._paneRenderers = {};
|
1127 |
|
1128 |
|
1129 |
|
1130 |
|
1131 |
|
1132 |
|
1133 |
|
1134 |
|
1135 |
|
1136 |
|
1137 |
|
1138 |
|
1139 |
|
1140 | this._mapPane = this.createPane('mapPane', this._container);
|
1141 | DomUtil.setPosition(this._mapPane, new Point(0, 0));
|
1142 |
|
1143 |
|
1144 |
|
1145 | this.createPane('tilePane');
|
1146 |
|
1147 |
|
1148 | this.createPane('overlayPane');
|
1149 |
|
1150 |
|
1151 | this.createPane('shadowPane');
|
1152 |
|
1153 |
|
1154 | this.createPane('markerPane');
|
1155 |
|
1156 |
|
1157 | this.createPane('tooltipPane');
|
1158 |
|
1159 |
|
1160 | this.createPane('popupPane');
|
1161 |
|
1162 | if (!this.options.markerZoomAnimation) {
|
1163 | DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
|
1164 | DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
|
1165 | }
|
1166 | },
|
1167 |
|
1168 |
|
1169 |
|
1170 |
|
1171 |
|
1172 | _resetView: function (center, zoom) {
|
1173 | DomUtil.setPosition(this._mapPane, new Point(0, 0));
|
1174 |
|
1175 | var loading = !this._loaded;
|
1176 | this._loaded = true;
|
1177 | zoom = this._limitZoom(zoom);
|
1178 |
|
1179 | this.fire('viewprereset');
|
1180 |
|
1181 | var zoomChanged = this._zoom !== zoom;
|
1182 | this
|
1183 | ._moveStart(zoomChanged, false)
|
1184 | ._move(center, zoom)
|
1185 | ._moveEnd(zoomChanged);
|
1186 |
|
1187 |
|
1188 |
|
1189 |
|
1190 | this.fire('viewreset');
|
1191 |
|
1192 |
|
1193 |
|
1194 |
|
1195 | if (loading) {
|
1196 | this.fire('load');
|
1197 | }
|
1198 | },
|
1199 |
|
1200 | _moveStart: function (zoomChanged, noMoveStart) {
|
1201 |
|
1202 |
|
1203 |
|
1204 |
|
1205 | if (zoomChanged) {
|
1206 | this.fire('zoomstart');
|
1207 | }
|
1208 | if (!noMoveStart) {
|
1209 | this.fire('movestart');
|
1210 | }
|
1211 | return this;
|
1212 | },
|
1213 |
|
1214 | _move: function (center, zoom, data, supressEvent) {
|
1215 | if (zoom === undefined) {
|
1216 | zoom = this._zoom;
|
1217 | }
|
1218 | var zoomChanged = this._zoom !== zoom;
|
1219 |
|
1220 | this._zoom = zoom;
|
1221 | this._lastCenter = center;
|
1222 | this._pixelOrigin = this._getNewPixelOrigin(center);
|
1223 |
|
1224 | if (!supressEvent) {
|
1225 |
|
1226 |
|
1227 |
|
1228 | if (zoomChanged || (data && data.pinch)) {
|
1229 | this.fire('zoom', data);
|
1230 | }
|
1231 |
|
1232 |
|
1233 |
|
1234 |
|
1235 | this.fire('move', data);
|
1236 | } else if (data && data.pinch) {
|
1237 | this.fire('zoom', data);
|
1238 | }
|
1239 | return this;
|
1240 | },
|
1241 |
|
1242 | _moveEnd: function (zoomChanged) {
|
1243 |
|
1244 |
|
1245 | if (zoomChanged) {
|
1246 | this.fire('zoomend');
|
1247 | }
|
1248 |
|
1249 |
|
1250 |
|
1251 |
|
1252 | return this.fire('moveend');
|
1253 | },
|
1254 |
|
1255 | _stop: function () {
|
1256 | Util.cancelAnimFrame(this._flyToFrame);
|
1257 | if (this._panAnim) {
|
1258 | this._panAnim.stop();
|
1259 | }
|
1260 | return this;
|
1261 | },
|
1262 |
|
1263 | _rawPanBy: function (offset) {
|
1264 | DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
|
1265 | },
|
1266 |
|
1267 | _getZoomSpan: function () {
|
1268 | return this.getMaxZoom() - this.getMinZoom();
|
1269 | },
|
1270 |
|
1271 | _panInsideMaxBounds: function () {
|
1272 | if (!this._enforcingBounds) {
|
1273 | this.panInsideBounds(this.options.maxBounds);
|
1274 | }
|
1275 | },
|
1276 |
|
1277 | _checkIfLoaded: function () {
|
1278 | if (!this._loaded) {
|
1279 | throw new Error('Set map center and zoom first.');
|
1280 | }
|
1281 | },
|
1282 |
|
1283 |
|
1284 |
|
1285 |
|
1286 | _initEvents: function (remove) {
|
1287 | this._targets = {};
|
1288 | this._targets[Util.stamp(this._container)] = this;
|
1289 |
|
1290 | var onOff = remove ? DomEvent.off : DomEvent.on;
|
1291 |
|
1292 |
|
1293 |
|
1294 |
|
1295 |
|
1296 |
|
1297 |
|
1298 |
|
1299 |
|
1300 |
|
1301 |
|
1302 |
|
1303 |
|
1304 |
|
1305 |
|
1306 |
|
1307 |
|
1308 |
|
1309 |
|
1310 |
|
1311 |
|
1312 |
|
1313 |
|
1314 |
|
1315 |
|
1316 |
|
1317 |
|
1318 |
|
1319 | onOff(this._container, 'click dblclick mousedown mouseup ' +
|
1320 | 'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);
|
1321 |
|
1322 | if (this.options.trackResize) {
|
1323 | onOff(window, 'resize', this._onResize, this);
|
1324 | }
|
1325 |
|
1326 | if (Browser.any3d && this.options.transform3DLimit) {
|
1327 | (remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
|
1328 | }
|
1329 | },
|
1330 |
|
1331 | _onResize: function () {
|
1332 | Util.cancelAnimFrame(this._resizeRequest);
|
1333 | this._resizeRequest = Util.requestAnimFrame(
|
1334 | function () { this.invalidateSize({debounceMoveend: true}); }, this);
|
1335 | },
|
1336 |
|
1337 | _onScroll: function () {
|
1338 | this._container.scrollTop = 0;
|
1339 | this._container.scrollLeft = 0;
|
1340 | },
|
1341 |
|
1342 | _onMoveEnd: function () {
|
1343 | var pos = this._getMapPanePos();
|
1344 | if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
|
1345 |
|
1346 |
|
1347 | this._resetView(this.getCenter(), this.getZoom());
|
1348 | }
|
1349 | },
|
1350 |
|
1351 | _findEventTargets: function (e, type) {
|
1352 | var targets = [],
|
1353 | target,
|
1354 | isHover = type === 'mouseout' || type === 'mouseover',
|
1355 | src = e.target || e.srcElement,
|
1356 | dragging = false;
|
1357 |
|
1358 | while (src) {
|
1359 | target = this._targets[Util.stamp(src)];
|
1360 | if (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {
|
1361 |
|
1362 | dragging = true;
|
1363 | break;
|
1364 | }
|
1365 | if (target && target.listens(type, true)) {
|
1366 | if (isHover && !DomEvent.isExternalTarget(src, e)) { break; }
|
1367 | targets.push(target);
|
1368 | if (isHover) { break; }
|
1369 | }
|
1370 | if (src === this._container) { break; }
|
1371 | src = src.parentNode;
|
1372 | }
|
1373 | if (!targets.length && !dragging && !isHover && this.listens(type, true)) {
|
1374 | targets = [this];
|
1375 | }
|
1376 | return targets;
|
1377 | },
|
1378 |
|
1379 | _isClickDisabled: function (el) {
|
1380 | while (el !== this._container) {
|
1381 | if (el['_leaflet_disable_click']) { return true; }
|
1382 | el = el.parentNode;
|
1383 | }
|
1384 | },
|
1385 |
|
1386 | _handleDOMEvent: function (e) {
|
1387 | var el = (e.target || e.srcElement);
|
1388 | if (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {
|
1389 | return;
|
1390 | }
|
1391 |
|
1392 | var type = e.type;
|
1393 |
|
1394 | if (type === 'mousedown') {
|
1395 |
|
1396 | DomUtil.preventOutline(el);
|
1397 | }
|
1398 |
|
1399 | this._fireDOMEvent(e, type);
|
1400 | },
|
1401 |
|
1402 | _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
|
1403 |
|
1404 | _fireDOMEvent: function (e, type, canvasTargets) {
|
1405 |
|
1406 | if (e.type === 'click') {
|
1407 |
|
1408 |
|
1409 |
|
1410 |
|
1411 |
|
1412 | var synth = Util.extend({}, e);
|
1413 | synth.type = 'preclick';
|
1414 | this._fireDOMEvent(synth, synth.type, canvasTargets);
|
1415 | }
|
1416 |
|
1417 |
|
1418 | var targets = this._findEventTargets(e, type);
|
1419 |
|
1420 | if (canvasTargets) {
|
1421 | var filtered = [];
|
1422 | for (var i = 0; i < canvasTargets.length; i++) {
|
1423 | if (canvasTargets[i].listens(type, true)) {
|
1424 | filtered.push(canvasTargets[i]);
|
1425 | }
|
1426 | }
|
1427 | targets = filtered.concat(targets);
|
1428 | }
|
1429 |
|
1430 | if (!targets.length) { return; }
|
1431 |
|
1432 | if (type === 'contextmenu') {
|
1433 | DomEvent.preventDefault(e);
|
1434 | }
|
1435 |
|
1436 | var target = targets[0];
|
1437 | var data = {
|
1438 | originalEvent: e
|
1439 | };
|
1440 |
|
1441 | if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {
|
1442 | var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
|
1443 | data.containerPoint = isMarker ?
|
1444 | this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
|
1445 | data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
|
1446 | data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
|
1447 | }
|
1448 |
|
1449 | for (i = 0; i < targets.length; i++) {
|
1450 | targets[i].fire(type, data, true);
|
1451 | if (data.originalEvent._stopped ||
|
1452 | (targets[i].options.bubblingMouseEvents === false && Util.indexOf(this._mouseEvents, type) !== -1)) { return; }
|
1453 | }
|
1454 | },
|
1455 |
|
1456 | _draggableMoved: function (obj) {
|
1457 | obj = obj.dragging && obj.dragging.enabled() ? obj : this;
|
1458 | return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
|
1459 | },
|
1460 |
|
1461 | _clearHandlers: function () {
|
1462 | for (var i = 0, len = this._handlers.length; i < len; i++) {
|
1463 | this._handlers[i].disable();
|
1464 | }
|
1465 | },
|
1466 |
|
1467 |
|
1468 |
|
1469 |
|
1470 |
|
1471 |
|
1472 |
|
1473 | whenReady: function (callback, context) {
|
1474 | if (this._loaded) {
|
1475 | callback.call(context || this, {target: this});
|
1476 | } else {
|
1477 | this.on('load', callback, context);
|
1478 | }
|
1479 | return this;
|
1480 | },
|
1481 |
|
1482 |
|
1483 |
|
1484 |
|
1485 | _getMapPanePos: function () {
|
1486 | return DomUtil.getPosition(this._mapPane) || new Point(0, 0);
|
1487 | },
|
1488 |
|
1489 | _moved: function () {
|
1490 | var pos = this._getMapPanePos();
|
1491 | return pos && !pos.equals([0, 0]);
|
1492 | },
|
1493 |
|
1494 | _getTopLeftPoint: function (center, zoom) {
|
1495 | var pixelOrigin = center && zoom !== undefined ?
|
1496 | this._getNewPixelOrigin(center, zoom) :
|
1497 | this.getPixelOrigin();
|
1498 | return pixelOrigin.subtract(this._getMapPanePos());
|
1499 | },
|
1500 |
|
1501 | _getNewPixelOrigin: function (center, zoom) {
|
1502 | var viewHalf = this.getSize()._divideBy(2);
|
1503 | return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
|
1504 | },
|
1505 |
|
1506 | _latLngToNewLayerPoint: function (latlng, zoom, center) {
|
1507 | var topLeft = this._getNewPixelOrigin(center, zoom);
|
1508 | return this.project(latlng, zoom)._subtract(topLeft);
|
1509 | },
|
1510 |
|
1511 | _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
|
1512 | var topLeft = this._getNewPixelOrigin(center, zoom);
|
1513 | return toBounds([
|
1514 | this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
|
1515 | this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
|
1516 | this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
|
1517 | this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
|
1518 | ]);
|
1519 | },
|
1520 |
|
1521 |
|
1522 | _getCenterLayerPoint: function () {
|
1523 | return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
|
1524 | },
|
1525 |
|
1526 |
|
1527 | _getCenterOffset: function (latlng) {
|
1528 | return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
|
1529 | },
|
1530 |
|
1531 |
|
1532 | _limitCenter: function (center, zoom, bounds) {
|
1533 |
|
1534 | if (!bounds) { return center; }
|
1535 |
|
1536 | var centerPoint = this.project(center, zoom),
|
1537 | viewHalf = this.getSize().divideBy(2),
|
1538 | viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
|
1539 | offset = this._getBoundsOffset(viewBounds, bounds, zoom);
|
1540 |
|
1541 |
|
1542 |
|
1543 |
|
1544 | if (offset.round().equals([0, 0])) {
|
1545 | return center;
|
1546 | }
|
1547 |
|
1548 | return this.unproject(centerPoint.add(offset), zoom);
|
1549 | },
|
1550 |
|
1551 |
|
1552 | _limitOffset: function (offset, bounds) {
|
1553 | if (!bounds) { return offset; }
|
1554 |
|
1555 | var viewBounds = this.getPixelBounds(),
|
1556 | newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
|
1557 |
|
1558 | return offset.add(this._getBoundsOffset(newBounds, bounds));
|
1559 | },
|
1560 |
|
1561 |
|
1562 | _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
|
1563 | var projectedMaxBounds = toBounds(
|
1564 | this.project(maxBounds.getNorthEast(), zoom),
|
1565 | this.project(maxBounds.getSouthWest(), zoom)
|
1566 | ),
|
1567 | minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
|
1568 | maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
|
1569 |
|
1570 | dx = this._rebound(minOffset.x, -maxOffset.x),
|
1571 | dy = this._rebound(minOffset.y, -maxOffset.y);
|
1572 |
|
1573 | return new Point(dx, dy);
|
1574 | },
|
1575 |
|
1576 | _rebound: function (left, right) {
|
1577 | return left + right > 0 ?
|
1578 | Math.round(left - right) / 2 :
|
1579 | Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
|
1580 | },
|
1581 |
|
1582 | _limitZoom: function (zoom) {
|
1583 | var min = this.getMinZoom(),
|
1584 | max = this.getMaxZoom(),
|
1585 | snap = Browser.any3d ? this.options.zoomSnap : 1;
|
1586 | if (snap) {
|
1587 | zoom = Math.round(zoom / snap) * snap;
|
1588 | }
|
1589 | return Math.max(min, Math.min(max, zoom));
|
1590 | },
|
1591 |
|
1592 | _onPanTransitionStep: function () {
|
1593 | this.fire('move');
|
1594 | },
|
1595 |
|
1596 | _onPanTransitionEnd: function () {
|
1597 | DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
|
1598 | this.fire('moveend');
|
1599 | },
|
1600 |
|
1601 | _tryAnimatedPan: function (center, options) {
|
1602 |
|
1603 | var offset = this._getCenterOffset(center)._trunc();
|
1604 |
|
1605 |
|
1606 | if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
|
1607 |
|
1608 | this.panBy(offset, options);
|
1609 |
|
1610 | return true;
|
1611 | },
|
1612 |
|
1613 | _createAnimProxy: function () {
|
1614 |
|
1615 | var proxy = this._proxy = DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');
|
1616 | this._panes.mapPane.appendChild(proxy);
|
1617 |
|
1618 | this.on('zoomanim', function (e) {
|
1619 | var prop = DomUtil.TRANSFORM,
|
1620 | transform = this._proxy.style[prop];
|
1621 |
|
1622 | DomUtil.setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
|
1623 |
|
1624 |
|
1625 | if (transform === this._proxy.style[prop] && this._animatingZoom) {
|
1626 | this._onZoomTransitionEnd();
|
1627 | }
|
1628 | }, this);
|
1629 |
|
1630 | this.on('load moveend', this._animMoveEnd, this);
|
1631 |
|
1632 | this._on('unload', this._destroyAnimProxy, this);
|
1633 | },
|
1634 |
|
1635 | _destroyAnimProxy: function () {
|
1636 | DomUtil.remove(this._proxy);
|
1637 | this.off('load moveend', this._animMoveEnd, this);
|
1638 | delete this._proxy;
|
1639 | },
|
1640 |
|
1641 | _animMoveEnd: function () {
|
1642 | var c = this.getCenter(),
|
1643 | z = this.getZoom();
|
1644 | DomUtil.setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
|
1645 | },
|
1646 |
|
1647 | _catchTransitionEnd: function (e) {
|
1648 | if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
|
1649 | this._onZoomTransitionEnd();
|
1650 | }
|
1651 | },
|
1652 |
|
1653 | _nothingToAnimate: function () {
|
1654 | return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
|
1655 | },
|
1656 |
|
1657 | _tryAnimatedZoom: function (center, zoom, options) {
|
1658 |
|
1659 | if (this._animatingZoom) { return true; }
|
1660 |
|
1661 | options = options || {};
|
1662 |
|
1663 |
|
1664 | if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
|
1665 | Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
|
1666 |
|
1667 |
|
1668 | var scale = this.getZoomScale(zoom),
|
1669 | offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
|
1670 |
|
1671 |
|
1672 | if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
|
1673 |
|
1674 | Util.requestAnimFrame(function () {
|
1675 | this
|
1676 | ._moveStart(true, false)
|
1677 | ._animateZoom(center, zoom, true);
|
1678 | }, this);
|
1679 |
|
1680 | return true;
|
1681 | },
|
1682 |
|
1683 | _animateZoom: function (center, zoom, startAnim, noUpdate) {
|
1684 | if (!this._mapPane) { return; }
|
1685 |
|
1686 | if (startAnim) {
|
1687 | this._animatingZoom = true;
|
1688 |
|
1689 |
|
1690 | this._animateToCenter = center;
|
1691 | this._animateToZoom = zoom;
|
1692 |
|
1693 | DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
|
1694 | }
|
1695 |
|
1696 |
|
1697 |
|
1698 |
|
1699 | this.fire('zoomanim', {
|
1700 | center: center,
|
1701 | zoom: zoom,
|
1702 | noUpdate: noUpdate
|
1703 | });
|
1704 |
|
1705 | if (!this._tempFireZoomEvent) {
|
1706 | this._tempFireZoomEvent = this._zoom !== this._animateToZoom;
|
1707 | }
|
1708 |
|
1709 | this._move(this._animateToCenter, this._animateToZoom, undefined, true);
|
1710 |
|
1711 |
|
1712 | setTimeout(Util.bind(this._onZoomTransitionEnd, this), 250);
|
1713 | },
|
1714 |
|
1715 | _onZoomTransitionEnd: function () {
|
1716 | if (!this._animatingZoom) { return; }
|
1717 |
|
1718 | if (this._mapPane) {
|
1719 | DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
|
1720 | }
|
1721 |
|
1722 | this._animatingZoom = false;
|
1723 |
|
1724 | this._move(this._animateToCenter, this._animateToZoom, undefined, true);
|
1725 |
|
1726 | if (this._tempFireZoomEvent) {
|
1727 | this.fire('zoom');
|
1728 | }
|
1729 | delete this._tempFireZoomEvent;
|
1730 |
|
1731 | this.fire('move');
|
1732 |
|
1733 | this._moveEnd(true);
|
1734 | }
|
1735 | });
|
1736 |
|
1737 |
|
1738 |
|
1739 |
|
1740 |
|
1741 |
|
1742 |
|
1743 |
|
1744 |
|
1745 |
|
1746 |
|
1747 | export function createMap(id, options) {
|
1748 | return new Map(id, options);
|
1749 | }
|