leaflet-rotate 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,1661 @@
1
- !function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){"use strict";const t=L.extend({},L.DomUtil);L.extend(L.DomUtil,{setTransform:function(o,e,i,n,a){var s=e||new L.Point(0,0);if(!n)return e=s._round(),t.setTransform.call(this,o,e,i);s=s.rotateFrom(n,a),o.style[L.DomUtil.TRANSFORM]="translate3d("+s.x+"px,"+s.y+"px,0)"+(i?" scale("+i+")":"")+" rotate("+n+"rad)"},setPosition:function(o,e,i,n){if(!i)return t.setPosition.call(this,o,e);o._leaflet_pos=e,L.Browser.any3d?L.DomUtil.setTransform(o,e,void 0,i,n):(o.style.left=e.x+"px",o.style.top=e.y+"px")},DEG_TO_RAD:Math.PI/180,RAD_TO_DEG:180/Math.PI}),L.Draggable.include({updateMapBearing:function(t){this._mapBearing=t}}),L.extend(L.Point.prototype,{rotate:function(t){if(!t)return this;var o=Math.sin(t),e=Math.cos(t);return new L.Point(this.x*e-this.y*o,this.x*o+this.y*e)},rotateFrom:function(t,o){if(!t)return this;var e=Math.sin(t),i=Math.cos(t),n=o.x,a=o.y,s=this.x-n,r=this.y-a;return new L.Point(s*i-r*e+n,s*e+r*i+a)}});const o=L.extend({},L.DivOverlay.prototype);L.DivOverlay.include({getEvents:function(){return L.extend(o.getEvents.call(this),{rotate:this._updatePosition})},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),o=L.point(this.options.offset),e=this._getAnchor();this._zoomAnimated?(this._map._rotate&&(t=this._map.rotatedPointToMapPanePoint(t)),L.DomUtil.setPosition(this._container,t.add(e))):o=o.add(t).add(e);var i=this._containerBottom=-o.y,n=this._containerLeft=-Math.round(this._containerWidth/2)+o.x;this._container.style.bottom=i+"px",this._container.style.left=n+"px"}}});const e=L.extend({},L.Popup.prototype);L.Popup.include({_animateZoom:function(t){this._map._rotate||e._animateZoom.call(this,t);var o=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),i=this._getAnchor();o=this._map.rotatedPointToMapPanePoint(o),L.DomUtil.setPosition(this._container,o.add(i))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,o=parseInt(L.DomUtil.getStyle(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+o,i=this._containerWidth,n=new L.Point(this._containerLeft,-e-this._containerBottom);n._add(L.DomUtil.getPosition(this._container));var a=n._add(this._map._getMapPanePos()),s=L.point(this.options.autoPanPadding),r=L.point(this.options.autoPanPaddingTopLeft||s),h=L.point(this.options.autoPanPaddingBottomRight||s),_=t.getSize(),l=0,c=0;a.x+i+h.x>_.x&&(l=a.x+i-_.x+h.x),a.x-l-r.x<0&&(l=a.x-r.x),a.y+e+h.y>_.y&&(c=a.y+e-_.y+h.y),a.y-c-r.y<0&&(c=a.y-r.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}}});const i=L.extend({},L.Tooltip.prototype);L.Tooltip.include({_updatePosition:function(){if(!this._map._rotate)return i._updatePosition.call(this);var t=this._map.latLngToLayerPoint(this._latlng);t=this._map.rotatedPointToMapPanePoint(t),this._setPosition(t)},_animateZoom:function(t){if(!this._map._rotate)return i._animateZoom.call(this,t);var o=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);o=this._map.rotatedPointToMapPanePoint(o),this._setPosition(o)}});L.extend({},L.Icon.prototype);var n;L.Icon.include({_setIconStyles:function(t,o){var e=this.options,i=e[o+"Size"];"number"==typeof i&&(i=[i,i]);var n=L.point(i),a=L.point("shadow"===o&&e.shadowAnchor||e.iconAnchor||n&&n.divideBy(2,!0));t.className="leaflet-marker-"+o+" "+(e.className||""),a&&(t.style.marginLeft=-a.x+"px",t.style.marginTop=-a.y+"px",t.style[L.DomUtil.TRANSFORM+"Origin"]=a.x+"px "+a.y+"px 0px"),n&&(t.style.width=n.x+"px",t.style.height=n.y+"px")}});var a={_onDragStart:function(){if(!this._marker._map._rotate)return n._onDragStart.call(this);this._draggable.updateMapBearing(this._marker._map._bearing)},_onDrag:function(t){var o=this._marker,e=o.options.rotation||o.options.rotateWithView,i=o._shadow,n=L.DomUtil.getPosition(o._icon);!e&&i&&L.DomUtil.setPosition(i,n),o._map._rotate&&(n=o._map.mapPanePointToRotatedPoint(n));var a=o._map.layerPointToLatLng(n);o._latlng=a,t.latlng=a,t.oldLatLng=this._oldLatLng,e?o.setLatLng(a):o.fire("move",t),o.fire("drag",t)},_onDragEnd:function(t){this._marker._map._rotate&&this._marker.update(),n._onDragEnd.call(this,t)}};const s=L.extend({},L.Marker.prototype);L.Marker.mergeOptions({rotation:0,rotateWithView:!1}),L.Marker.include({getEvents:function(){return L.extend(s.getEvents.call(this),{rotate:this.update})},onAdd:function(t){s.onAdd.call(this,t),t.on("rotate",this.update,this)},_initInteraction:function(){var t=s._initInteraction.call(this);return this.dragging&&this.dragging.enabled()&&this._map&&this._map._rotate&&(n=n||Object.getPrototypeOf(this.dragging),this.dragging._onDragStart=a._onDragStart.bind(this.dragging),this.dragging._onDrag=a._onDrag.bind(this.dragging),this.dragging._onDragEnd=a._onDragEnd.bind(this.dragging),this.dragging.disable(),this.dragging.enable()),t},_setPos:function(t){this._map._rotate&&(t=this._map.rotatedPointToMapPanePoint(t));var o=this.options.rotation||0;this.options.rotateWithView&&(o+=this._map._bearing),L.DomUtil.setPosition(this._icon,t,o,t),this._shadow&&L.DomUtil.setPosition(this._shadow,t,o,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){if(!this._map._rotate)return s._updateZIndex.call(this,t);this._icon.style.zIndex=Math.round(this._zIndex+t)},setRotation:function(t){this.options.rotation=t,this.update()}});const r=L.extend({},L.GridLayer.prototype);L.GridLayer.include({getEvents:function(){var t=r.getEvents.call(this);return this._map._rotate&&!this.options.updateWhenIdle&&(this._onRotate||(this._onRotate=L.Util.throttle(this._onMoveEnd,this.options.updateInterval,this)),t.rotate=this._onRotate),t},_getTiledPixelBounds:function(t){if(!this._map._rotate)return r._getTiledPixelBounds.call(this,t);var o=this._map,e=o._animatingZoom?Math.max(o._animateToZoom,o.getZoom()):o.getZoom(),i=o.getZoomScale(e,this._tileZoom),n=o.project(t,this._tileZoom).floor(),a=o.getSize(),s=new L.Bounds([o.containerPointToLayerPoint([0,0]).floor(),o.containerPointToLayerPoint([a.x,0]).floor(),o.containerPointToLayerPoint([0,a.y]).floor(),o.containerPointToLayerPoint([a.x,a.y]).floor()]).getSize().divideBy(2*i);return new L.Bounds(n.subtract(s),n.add(s))}});const h=L.extend({},L.Canvas.prototype);L.Canvas.include({onAdd:function(){h.onAdd.call(this),this._map.on("rotate",this._redraw,this)},onRemove:function(){h.onRemove.call(this),this._map.off("rotate",this._redraw,this)},_update:function(){h._update.call(this),this.fire("update")}});const _=L.extend({},L.Renderer.prototype);L.Renderer.include({onAdd:function(){_.onAdd.call(this)},onRemove:function(){_.onRemove.call(this)},_updateTransform:function(t,o){if(!this._map._rotate)return _._updateTransform.call(this,t,o);var e=this._map.getZoomScale(o,this._zoom),i=this._map._latLngToNewLayerPoint(this._topLeft,o,t);L.Browser.any3d?L.DomUtil.setTransform(this._container,i,e):L.DomUtil.setPosition(this._container,i)},_update:function(){if(!this._map._rotate)return _._update.call(this);var t=this.options.padding,o=this._map,e=this._map.getSize(),i=e.multiplyBy(-t),n=e.multiplyBy(1+t),a=new L.Bounds([o.containerPointToLayerPoint([i.x,i.y]).floor(),o.containerPointToLayerPoint([i.x,n.y]).floor(),o.containerPointToLayerPoint([n.x,i.y]).floor(),o.containerPointToLayerPoint([n.x,n.y]).floor()]);this._bounds=a,this._topLeft=this._map.layerPointToLatLng(a.min),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}});const l=L.extend({},L.SVG.prototype);L.SVG.include({_update:function(){l._update.call(this),this._map._rotate&&this.fire("update")}});const c=L.extend({},L.Map.prototype);L.Map.mergeOptions({rotate:!1,bearing:0}),L.Map.include({initialize:function(t,o){o.rotate&&(this._rotate=!0,this._bearing=0),c.initialize.call(this,t,o),this.options.rotate&&this.setBearing(this.options.bearing)},containerPointToLayerPoint:function(t){return this._rotate?L.point(t).subtract(this._getMapPanePos()).rotateFrom(-this._bearing,this._getRotatePanePos()).subtract(this._getRotatePanePos()):c.containerPointToLayerPoint.call(this,t)},getBounds:function(){if(!this._rotate)return c.getBounds.call(this);var t=this.getSize(),o=this.layerPointToLatLng(this.containerPointToLayerPoint([0,0])),e=this.layerPointToLatLng(this.containerPointToLayerPoint([t.x,0])),i=this.layerPointToLatLng(this.containerPointToLayerPoint([t.x,t.y])),n=this.layerPointToLatLng(this.containerPointToLayerPoint([0,t.y]));return new L.LatLngBounds([o,e,i,n])},layerPointToContainerPoint:function(t){return this._rotate?L.point(t).add(this._getRotatePanePos()).rotateFrom(this._bearing,this._getRotatePanePos()).add(this._getMapPanePos()):c.layerPointToContainerPoint.call(this,t)},setBearing:function(t){if(L.Browser.any3d&&this._rotate){var o=this._getRotatePanePos(),e=this.getSize().divideBy(2);this._pivot=this._getMapPanePos().clone().multiplyBy(-1).add(e),o=o.rotateFrom(-this._bearing,this._pivot),this._bearing=t*L.DomUtil.DEG_TO_RAD,this._rotatePanePos=o.rotateFrom(this._bearing,this._pivot),L.DomUtil.setPosition(this._rotatePane,o,this._bearing,this._pivot),this.fire("rotate")}},getBearing:function(){return this._bearing*L.DomUtil.RAD_TO_DEG},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),L.DomUtil.setPosition(this._mapPane,new L.Point(0,0)),this._rotate?(this._rotatePane=this.createPane("rotatePane",this._mapPane),this._norotatePane=this.createPane("norotatePane",this._mapPane),this.createPane("tilePane",this._rotatePane),this.createPane("overlayPane",this._rotatePane),this.createPane("shadowPane",this._norotatePane),this.createPane("markerPane",this._norotatePane),this.createPane("tooltipPane",this._norotatePane),this.createPane("popupPane",this._norotatePane)):(this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane")),this.options.markerZoomAnimation||(L.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),L.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"))},rotatedPointToMapPanePoint:function(t){return L.point(t).rotate(this._bearing)._add(this._getRotatePanePos())},mapPanePointToRotatedPoint:function(t){return L.point(t)._subtract(this._getRotatePanePos()).rotate(-this._bearing)},_getCenterOffset:function(t){var o=c._getCenterOffset.call(this,t);return this._rotate&&(o=o.rotate(this._bearing)),o},_getRotatePanePos:function(){return this._rotatePanePos||new L.Point(0,0)},_getNewPixelOrigin:function(t,o){var e=this.getSize()._divideBy(2);return this._rotate||c._getNewPixelOrigin.call(this,t,o),this.project(t,o).rotate(this._bearing)._subtract(e)._add(this._getMapPanePos())._add(this._getRotatePanePos()).rotate(-this._bearing)._round()},_handleGeolocationResponse:function(t){var o=t.coords.latitude,e=t.coords.longitude,i=t.coords.heading,n=new L.LatLng(o,e),a=n.toBounds(t.coords.accuracy),s=this._locateOptions;if(s.setView){var r=this.getBoundsZoom(a);this.setView(n,s.maxZoom?Math.min(r,s.maxZoom):r)}var h={latlng:n,bounds:a,timestamp:t.timestamp,heading:i};for(var _ in t.coords)"number"==typeof t.coords[_]&&(h[_]=t.coords[_]);this.fire("locationfound",h)}}),L.Map.CompassBearing=L.Handler.extend({initialize:function(t){window.DeviceOrientationEvent?(this._capable=!0,this._map=t,this._throttled=L.Util.throttle(this._onDeviceOrientation,1e3,this)):this._capable=!1},addHooks:function(){this._capable&&this._map._rotate&&L.DomEvent.on(window,"deviceorientation",this._throttled,this)},removeHooks:function(){this._capable&&this._map._rotate&&L.DomEvent.off(window,"deviceorientation",this._throttled,this)},_onDeviceOrientation:function(t){null!==t.alpha&&this._map.setBearing(t.alpha-window.orientation)}}),L.Map.addInitHook("addHandler","compassBearing",L.Map.CompassBearing),L.Map.mergeOptions({trackContainerMutation:!1}),L.Map.ContainerMutation=L.Handler.extend({addHooks:function(){L.Browser.mutation&&(this._observer||(this._observer=new MutationObserver(L.Util.bind(this._onMutation,this))),this._observer.observe(this._map.getContainer(),{childList:!1,attributes:!0,characterData:!1,subtree:!1,attributeFilter:["style"]}))},removeHooks:function(){L.Browser.mutation&&this._observer.disconnect()},_onMutation:function(){this._map.invalidateSize()}}),L.Map.addInitHook("addHandler","trackContainerMutation",L.Map.ContainerMutation),L.Map.mergeOptions({bounceAtZoomLimits:!0}),L.Map.TouchGestures=L.Handler.extend({initialize:function(t){this._map=t,this.rotate=!!this._map.options.touchRotate,this.zoom=!!this._map.options.touchZoom},addHooks:function(){L.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){L.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var o=this._map;if(t.touches&&2===t.touches.length&&!o._animatingZoom&&!this._zooming&&!this._rotating){var e=o.mouseEventToContainerPoint(t.touches[0]),i=o.mouseEventToContainerPoint(t.touches[1]),n=e.subtract(i);this._centerPoint=o.getSize()._divideBy(2),this._startLatLng=o.containerPointToLatLng(this._centerPoint),this.zoom?("center"!==o.options.touchZoom&&(this._pinchStartLatLng=o.containerPointToLatLng(e.add(i)._divideBy(2))),this._startDist=e.distanceTo(i),this._startZoom=o.getZoom(),this._zooming=!0):this._zooming=!1,this.rotate?(this._startTheta=Math.atan(n.x/n.y),this._startBearing=o.getBearing(),n.y<0&&(this._startBearing+=180),this._rotating=!0):this._rotating=!1,this._moved=!1,o.stop(),L.DomEvent.on(document,"touchmove",this._onTouchMove,this).on(document,"touchend",this._onTouchEnd,this),L.DomEvent.preventDefault(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&(this._zooming||this._rotating)){var o,e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),a=i.subtract(n),s=i.distanceTo(n)/this._startDist;if(this._rotating){var r=(Math.atan(a.x/a.y)-this._startTheta)*L.DomUtil.RAD_TO_DEG;a.y<0&&(r+=180),r&&e.setBearing(this._startBearing-r)}if(this._zooming)if(this._zoom=e.getScaleZoom(s,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoom<e.getMinZoom()&&s<1||this._zoom>e.getMaxZoom()&&s>1)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{if(o=i._add(n)._divideBy(2)._subtract(this._centerPoint),1===s&&0===o.x&&0===o.y)return;var h=-e.getBearing()*L.DomUtil.DEG_TO_RAD;this._center=e.unproject(e.project(this._pinchStartLatLng).subtract(o.rotate(h)))}this._moved||(e._moveStart(!0),this._moved=!0),L.Util.cancelAnimFrame(this._animRequest);var _=L.bind(e._move,e,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=L.Util.requestAnimFrame(_,this,!0),L.DomEvent.preventDefault(t)}},_onTouchEnd:function(){this._moved&&this._zooming?(this._zooming=!1,this._rotating=!1,L.Util.cancelAnimFrame(this._animRequest),L.DomEvent.off(document,"touchmove",this._onTouchMove).off(document,"touchend",this._onTouchEnd),this.zoom&&(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.snapZoom):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):this._zooming=!1}}),L.Map.addInitHook("addHandler","touchGestures",L.Map.TouchGestures),L.Map.mergeOptions({touchRotate:!1}),L.Map.TouchRotate=L.Handler.extend({addHooks:function(){this._map.touchGestures.enable(),this._map.touchGestures.rotate=!0},removeHooks:function(){this._map.touchGestures.rotate=!1}}),L.Map.addInitHook("addHandler","touchRotate",L.Map.TouchRotate),L.Map.mergeOptions({shiftKeyRotate:!0}),L.Map.ShiftKeyRotate=L.Handler.extend({addHooks:function(){L.DomEvent.on(this._map._container,"wheel",this._handleShiftScroll,this),this._map.shiftKeyRotate.rotate=!0},removeHooks:function(){L.DomEvent.off(this._map._container,"wheel",this._handleShiftScroll,this),this._map.shiftKeyRotate.rotate=!1},_handleShiftScroll:function(t){t.shiftKey?(t.preventDefault(),this._map.scrollWheelZoom.disable(),this._map.setBearing(this._map._bearing*L.DomUtil.RAD_TO_DEG+t.deltaY)):this._map.scrollWheelZoom.enable()}}),L.Map.addInitHook("addHandler","shiftKeyRotate",L.Map.ShiftKeyRotate),L.Map.addInitHook((function(){this.scrollWheelZoom.enabled()&&this.shiftKeyRotate.enabled()&&(this.scrollWheelZoom.disable(),this.scrollWheelZoom.enable())})),L.Map.mergeOptions({touchZoom:L.Browser.touch&&!L.Browser.android23,bounceAtZoomLimits:!1}),L.Map.TouchZoom=L.Handler.extend({addHooks:function(){L.DomUtil.addClass(this._map._container,"leaflet-touch-zoom"),this._map.touchGestures.enable(),this._map.touchGestures.zoom=!0},removeHooks:function(){L.DomUtil.removeClass(this._map._container,"leaflet-touch-zoom"),this._map.touchGestures.zoom=!1}}),L.Map.addInitHook("addHandler","touchZoom",L.Map.TouchZoom),L.Control.Rotate=L.Control.extend({options:{position:"topleft",closeOnZeroBearing:!0},onAdd:function(t){this._onDeviceOrientation=L.Util.throttle(this._unthrottledOnDeviceOrientation,100,this);var o=this._container=L.DomUtil.create("div","leaflet-control-rotate leaflet-bar"),e=this._arrow=L.DomUtil.create("span","leaflet-control-rotate-arrow");e.style.backgroundImage="url(\"data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E\")",e.style.cursor="grab",e.style.display="block",e.style.width="100%",e.style.height="100%",e.style.backgroundRepeat="no-repeat",e.style.backgroundPosition="50%";var i=this._link=L.DomUtil.create("a","leaflet-control-rotate-toggle",o);return i.appendChild(e),i.href="#",i.title="Rotate map",L.DomEvent.on(i,"dblclick",L.DomEvent.stopPropagation).on(i,"mousedown",this._handleMouseDown,this).on(i,"click",L.DomEvent.stop).on(i,"click",this._cycleState,this).on(i,"click",this._refocusOnMap,this),L.Browser.any3d||L.DomUtil.addClass(i,"leaflet-disabled"),this._restyle(),t.on("rotate",this._restyle.bind(this)),this._follow=!1,this._canFollow=!1,this.options.closeOnZeroBearing&&0===t.getBearing()&&(o.style.display="none"),o},_handleMouseDown:function(t){L.DomEvent.stopPropagation(t),this.dragging=!0,this.dragstartX=t.pageX,this.dragstartY=t.pageY,L.DomEvent.on(document,"mousemove",this._handleMouseDrag,this).on(document,"mouseup",this._handleMouseUp,this)},_handleMouseUp:function(t){L.DomEvent.stopPropagation(t),this.dragging=!1,L.DomEvent.off(document,"mousemove",this._handleMouseDrag,this).off(document,"mouseup",this._handleMouseUp,this)},_handleMouseDrag:function(t){if(this.dragging){var o=t.clientX-this.dragstartX;this._map.setBearing(o)}},_cycleState:function(t){var o=this._map;o&&(o.touchRotate.enabled()||o.compassBearing.enabled()?o.compassBearing.enabled()?(o.compassBearing.disable(),o.setBearing(0),this.options.closeOnZeroBearing&&o.touchRotate.enable()):(o.touchRotate.disable(),o.compassBearing.enable()):o.touchRotate.enable(),this._restyle())},_restyle:function(){if(this._map.options.rotate){var t=this._map,o=t.getBearing();this.options.closeOnZeroBearing&&o&&(this._container.style.display="block");var e="rotate("+o+"deg)";this._arrow.style.transform=e,t.compassBearing.enabled()?this._link.style.backgroundColor="orange":t.touchRotate.enabled()?this._link.style.backgroundColor=null:(this._link.style.backgroundColor="grey",this.options.closeOnZeroBearing&&0===t.getBearing()&&(this._container.style.display="none"))}else L.DomUtil.addClass(this._link,"leaflet-disabled")}}),L.control.rotate=function(t){return new L.Control.Rotate(t)},L.Map.mergeOptions({rotateControl:!0}),L.Map.addInitHook((function(){if(this.options.rotateControl){var t="object"==typeof this.options.rotateControl?this.options.rotateControl:{};this.rotateControl=L.control.rotate(t),this.addControl(this.rotateControl)}}))}));
1
+ (function (factory) {
2
+ typeof define === 'function' && define.amd ? define(factory) :
3
+ factory();
4
+ })((function () { 'use strict';
5
+
6
+ /**
7
+ * @external L.DomUtil
8
+ *
9
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/DomUtil.js
10
+ */
11
+
12
+ const domUtilProto = L.extend({}, L.DomUtil);
13
+
14
+ L.extend(L.DomUtil, {
15
+
16
+ setTransform: function(el, offset, scale, bearing, pivot) {
17
+ var pos = offset || new L.Point(0, 0);
18
+
19
+ if (!bearing) {
20
+ offset = pos._round();
21
+ return domUtilProto.setTransform.call(this, el, offset, scale);
22
+ }
23
+
24
+ pos = pos.rotateFrom(bearing, pivot);
25
+
26
+ el.style[L.DomUtil.TRANSFORM] =
27
+ 'translate3d(' + pos.x + 'px,' + pos.y + 'px' + ',0)' +
28
+ (scale ? ' scale(' + scale + ')' : '') +
29
+ ' rotate(' + bearing + 'rad)';
30
+ },
31
+
32
+ setPosition: function(el, point, bearing, pivot) { // (HTMLElement, Point[, Boolean])
33
+ if (!bearing) {
34
+ return domUtilProto.setPosition.call(this, el, point);
35
+ }
36
+
37
+ /*eslint-disable */
38
+ el._leaflet_pos = point;
39
+ /*eslint-enable */
40
+
41
+ if (L.Browser.any3d) {
42
+ L.DomUtil.setTransform(el, point, undefined, bearing, pivot);
43
+ } else {
44
+ el.style.left = point.x + 'px';
45
+ el.style.top = point.y + 'px';
46
+ }
47
+ },
48
+
49
+ // Constants for rotation
50
+ DEG_TO_RAD: Math.PI / 180,
51
+ RAD_TO_DEG: 180 / Math.PI,
52
+
53
+ });
54
+
55
+ /**
56
+ * @external L.Draggable
57
+ *
58
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/dom/Draggable.js
59
+ */
60
+
61
+ L.Draggable.include({
62
+
63
+ // updateMapBearing: function(mapBearing) {
64
+ // this._mapBearing = mapBearing;
65
+ // },
66
+
67
+ });
68
+
69
+ /**
70
+ * @external L.Point
71
+ *
72
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/geometry/Point.js
73
+ */
74
+
75
+ L.extend(L.Point.prototype, {
76
+
77
+ /**
78
+ * Rotate around (0,0) by applying the 2D rotation matrix:
79
+ *
80
+ * ⎡ x' ⎤ = ⎡ cos θ -sin θ ⎤ ⎡ x ⎤
81
+ * ⎣ y' ⎦ ⎣ sin θ cos θ ⎦ ⎣ y ⎦
82
+ *
83
+ * @param theta must be given in radians.
84
+ */
85
+ rotate: function(theta) {
86
+ return this.rotateFrom(theta, new L.Point(0,0))
87
+ },
88
+
89
+ /**
90
+ * Rotate around (pivot.x, pivot.y) by:
91
+ *
92
+ * 1. subtract (pivot.x, pivot.y)
93
+ * 2. rotate around (0, 0)
94
+ * 3. add (pivot.x, pivot.y) back
95
+ *
96
+ * same as `this.subtract(pivot).rotate(theta).add(pivot)`
97
+ */
98
+ rotateFrom: function(theta, pivot) {
99
+ if (!theta) { return this; }
100
+ var sinTheta = Math.sin(theta);
101
+ var cosTheta = Math.cos(theta);
102
+ var cx = pivot.x,
103
+ cy = pivot.y;
104
+ var x = this.x - cx,
105
+ y = this.y - cy;
106
+
107
+ return new L.Point(
108
+ x * cosTheta - y * sinTheta + cx,
109
+ x * sinTheta + y * cosTheta + cy
110
+ );
111
+ },
112
+
113
+ });
114
+
115
+ /**
116
+ * @external L.DivOverlay
117
+ *
118
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/DivOverlay.js
119
+ */
120
+
121
+ const divOverlayProto = L.extend({}, L.DivOverlay.prototype);
122
+
123
+ L.DivOverlay.include({
124
+
125
+ getEvents: function() {
126
+ return L.extend(divOverlayProto.getEvents.call(this), { rotate: this._updatePosition });
127
+ },
128
+
129
+ _updatePosition: function() {
130
+ // 0. update anchor (leaflet v1.9.3)
131
+ divOverlayProto._updatePosition.call(this);
132
+ // 1. subtract anchor
133
+ // 2. rotate element
134
+ // 3. restore anchor
135
+ if (this._map && this._map._rotate && this._zoomAnimated) {
136
+ var anchor = this._getAnchor();
137
+ var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
138
+ L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
139
+ }
140
+
141
+ },
142
+
143
+ });
144
+
145
+ /**
146
+ * @external L.Popup
147
+ *
148
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/Popup.js
149
+ */
150
+
151
+ const popupProto = L.extend({}, L.Popup.prototype);
152
+
153
+ L.Popup.include({
154
+
155
+ _animateZoom: function(e) {
156
+ // 0. update anchor (leaflet v1.9.3)
157
+ popupProto._animateZoom.call(this, e);
158
+ // 1. subtract anchor
159
+ // 2. rotate element
160
+ // 3. restore anchor
161
+ if (this._map && this._map._rotate) {
162
+ var anchor = this._getAnchor();
163
+ var pos = L.DomUtil.getPosition(this._container).subtract(anchor);
164
+ L.DomUtil.setPosition(this._container, this._map.rotatedPointToMapPanePoint(pos).add(anchor));
165
+ }
166
+ },
167
+
168
+ /**
169
+ * Hot fix for L.Popup.mergeOptions({ keepInView: true, });
170
+ *
171
+ * @see https://github.com/fnicollet/Leaflet/pull/21
172
+ */
173
+ _adjustPan: function() {
174
+ if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
175
+
176
+ // We can endlessly recurse if keepInView is set and the view resets.
177
+ // Let's guard against that by exiting early if we're responding to our own autopan.
178
+ if (this._autopanning) {
179
+ this._autopanning = false;
180
+ return;
181
+ }
182
+
183
+ var map = this._map,
184
+ marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
185
+ containerHeight = this._container.offsetHeight + marginBottom,
186
+ containerWidth = this._containerWidth,
187
+ layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
188
+
189
+ layerPos._add(L.DomUtil.getPosition(this._container));
190
+
191
+ // var containerPos = map.layerPointToContainerPoint(layerPos);
192
+ /** @TODO use popupProto._adjustPan */
193
+ var containerPos = layerPos._add(this._map._getMapPanePos()),
194
+ padding = L.point(this.options.autoPanPadding),
195
+ paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
196
+ paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
197
+ size = map.getSize(),
198
+ dx = 0,
199
+ dy = 0;
200
+
201
+ if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
202
+ dx = containerPos.x + containerWidth - size.x + paddingBR.x;
203
+ }
204
+ if (containerPos.x - dx - paddingTL.x < 0) { // left
205
+ dx = containerPos.x - paddingTL.x;
206
+ }
207
+ if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
208
+ dy = containerPos.y + containerHeight - size.y + paddingBR.y;
209
+ }
210
+ if (containerPos.y - dy - paddingTL.y < 0) { // top
211
+ dy = containerPos.y - paddingTL.y;
212
+ }
213
+
214
+ // @namespace Map
215
+ // @section Popup events
216
+ // @event autopanstart: Event
217
+ // Fired when the map starts autopanning when opening a popup.
218
+ if (dx || dy) {
219
+ // Track that we're autopanning, as this function will be re-ran on moveend
220
+ if (this.options.keepInView) {
221
+ this._autopanning = true;
222
+ }
223
+ map
224
+ .fire('autopanstart')
225
+ .panBy([dx, dy]);
226
+ }
227
+ },
228
+
229
+ });
230
+
231
+ /**
232
+ * @external L.Tooltip
233
+ *
234
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/Tooltip.js
235
+ */
236
+
237
+ const tooltipProto = L.extend({}, L.Tooltip.prototype);
238
+
239
+ L.Tooltip.include({
240
+
241
+ _animateZoom: function(e) {
242
+ if (!this._map._rotate) {
243
+ return tooltipProto._animateZoom.call(this, e);
244
+ }
245
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
246
+
247
+ pos = this._map.rotatedPointToMapPanePoint(pos);
248
+ this._setPosition(pos);
249
+ },
250
+
251
+ _updatePosition: function() {
252
+ if (!this._map._rotate) {
253
+ return tooltipProto._updatePosition.call(this);
254
+ }
255
+ var pos = this._map.latLngToLayerPoint(this._latlng);
256
+
257
+ pos = this._map.rotatedPointToMapPanePoint(pos);
258
+ this._setPosition(pos);
259
+ },
260
+
261
+ });
262
+
263
+ /**
264
+ * @external L.Icon
265
+ *
266
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Icon.js
267
+ */
268
+
269
+ L.extend({}, L.Icon.prototype);
270
+
271
+ L.Icon.include({
272
+
273
+ _setIconStyles: function(img, name) {
274
+ var options = this.options;
275
+ var sizeOption = options[name + 'Size'];
276
+
277
+ if (typeof sizeOption === 'number') {
278
+ sizeOption = [sizeOption, sizeOption];
279
+ }
280
+
281
+ var size = L.point(sizeOption),
282
+ anchor = L.point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
283
+ size && size.divideBy(2, true));
284
+
285
+ img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
286
+
287
+ if (anchor) {
288
+ img.style.marginLeft = (-anchor.x) + 'px';
289
+ img.style.marginTop = (-anchor.y) + 'px';
290
+ /** @TODO use iconProto._setIconStyles */
291
+ img.style[L.DomUtil.TRANSFORM + "Origin"] = anchor.x + "px " + anchor.y + "px 0px";
292
+ }
293
+
294
+ if (size) {
295
+ img.style.width = size.x + 'px';
296
+ img.style.height = size.y + 'px';
297
+ }
298
+ },
299
+
300
+ });
301
+
302
+ /**
303
+ * @external L.Marker
304
+ * @external L.Handler.MarkerDrag
305
+ *
306
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/marker/Marker.js
307
+ */
308
+
309
+ const markerProto = L.extend({}, L.Marker.prototype);
310
+
311
+ L.Marker.mergeOptions({
312
+
313
+ // @option rotation: Number = 0
314
+ // Rotation of this marker in rad
315
+ rotation: 0,
316
+
317
+ // @option rotateWithView: Boolean = false
318
+ // Rotate this marker when map rotates
319
+ rotateWithView: false,
320
+
321
+ });
322
+
323
+ var markerDragProto; // retrived at runtime (see below: L.Marker::_initInteraction())
324
+
325
+ var MarkerDrag = {
326
+
327
+ // _onDragStart: function() {
328
+ // if (!this._marker._map._rotate) {
329
+ // return markerDragProto._onDragStart.call(this)
330
+ // }
331
+ // this._draggable.updateMapBearing(this._marker._map._bearing);
332
+ // },
333
+
334
+ _onDrag: function(e) {
335
+ var marker = this._marker,
336
+ /** @TODO use markerDragProto._onDrag */
337
+ rotated_marker = marker.options.rotation || marker.options.rotateWithView,
338
+ shadow = marker._shadow,
339
+ iconPos = L.DomUtil.getPosition(marker._icon);
340
+
341
+ /** @TODO use markerDragProto._onDrag */
342
+ // update shadow position
343
+ if (!rotated_marker && shadow) {
344
+ L.DomUtil.setPosition(shadow, iconPos);
345
+ }
346
+
347
+ /** @TODO use markerDragProto._onDrag */
348
+ if (marker._map._rotate) {
349
+ // Reverse calculation from mapPane coordinates to rotatePane coordinates
350
+ iconPos = marker._map.mapPanePointToRotatedPoint(iconPos);
351
+ }
352
+ var latlng = marker._map.layerPointToLatLng(iconPos);
353
+
354
+ marker._latlng = latlng;
355
+ e.latlng = latlng;
356
+ e.oldLatLng = this._oldLatLng;
357
+
358
+ /** @TODO use markerDragProto._onDrag */
359
+ if (rotated_marker) marker.setLatLng(latlng); // use `setLatLng` to presisit rotation. low efficiency
360
+ else marker.fire('move', e); // `setLatLng` will trig 'move' event. we imitate here.
361
+
362
+ // @event drag: Event
363
+ // Fired repeatedly while the user drags the marker.
364
+ marker
365
+ .fire('drag', e);
366
+ },
367
+
368
+ _onDragEnd: function(e) {
369
+ if (this._marker._map._rotate) {
370
+ this._marker.update();
371
+ }
372
+ markerDragProto._onDragEnd.call(this, e);
373
+ },
374
+
375
+ };
376
+
377
+ L.Marker.include({
378
+
379
+ getEvents: function() {
380
+ return L.extend(markerProto.getEvents.call(this), { rotate: this.update });
381
+ },
382
+
383
+ onAdd: function(map) {
384
+ markerProto.onAdd.call(this, map);
385
+ map.on('rotate', this.update, this);
386
+ },
387
+
388
+ _initInteraction: function() {
389
+ var ret = markerProto._initInteraction.call(this);
390
+ if (this.dragging && this.dragging.enabled() && this._map && this._map._rotate) {
391
+ // L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable
392
+ markerDragProto = markerDragProto || Object.getPrototypeOf(this.dragging);
393
+ Object.assign(this.dragging, {
394
+ // _onDragStart: MarkerDrag._onDragStart.bind(this.dragging),
395
+ _onDrag: MarkerDrag._onDrag.bind(this.dragging),
396
+ _onDragEnd: MarkerDrag._onDragEnd.bind(this.dragging),
397
+ });
398
+ this.dragging.disable();
399
+ this.dragging.enable();
400
+ }
401
+ return ret;
402
+ },
403
+
404
+ _setPos: function(pos) {
405
+
406
+ /** @TODO use markerProto._setPos */
407
+ if (this._map._rotate) {
408
+ pos = this._map.rotatedPointToMapPanePoint(pos);
409
+ }
410
+
411
+ /** @TODO use markerProto._setPos */
412
+ var bearing = this.options.rotation || 0;
413
+ if (this.options.rotateWithView) {
414
+ bearing += this._map._bearing;
415
+ }
416
+
417
+ /** @TODO use markerProto._setPos */
418
+ if (this._icon) {
419
+ L.DomUtil.setPosition(this._icon, pos, bearing, pos);
420
+ }
421
+
422
+ /** @TODO use markerProto._setPos */
423
+ if (this._shadow) {
424
+ L.DomUtil.setPosition(this._shadow, pos, bearing, pos);
425
+ }
426
+
427
+ this._zIndex = pos.y + this.options.zIndexOffset;
428
+
429
+ this._resetZIndex();
430
+ },
431
+
432
+ _updateZIndex: function(offset) {
433
+ if (!this._map._rotate) {
434
+ return markerProto._updateZIndex.call(this, offset)
435
+ }
436
+ this._icon.style.zIndex = Math.round(this._zIndex + offset);
437
+ },
438
+
439
+ setRotation: function(rotation) {
440
+ this.options.rotation = rotation;
441
+ this.update();
442
+ },
443
+
444
+ });
445
+
446
+ /**
447
+ * @external L.GridLayer
448
+ *
449
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/tile/GridLayer.js
450
+ */
451
+
452
+ const gridLayerProto = L.extend({}, L.GridLayer.prototype);
453
+
454
+ L.GridLayer.include({
455
+
456
+ getEvents: function() {
457
+ var events = gridLayerProto.getEvents.call(this);
458
+ if (this._map._rotate && !this.options.updateWhenIdle) {
459
+ if (!this._onRotate) {
460
+ this._onRotate = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
461
+ }
462
+ events.rotate = this._onRotate;
463
+ }
464
+ return events;
465
+ },
466
+
467
+ _getTiledPixelBounds: function(center) {
468
+ if (!this._map._rotate) {
469
+ return gridLayerProto._getTiledPixelBounds.call(this, center);
470
+ }
471
+
472
+ return this._map._getNewPixelBounds(center, this._tileZoom);
473
+ },
474
+
475
+ });
476
+
477
+ /**
478
+ * @external L.Canvas
479
+ *
480
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Canvas.js
481
+ */
482
+
483
+ L.extend({}, L.Canvas.prototype);
484
+
485
+ L.Canvas.include({
486
+
487
+ // onAdd: function() {
488
+ // canvasProto.onAdd.call(this);
489
+ // // When rotating the canvas itself, it is cleared by some weird reason, so redraw.
490
+ // this._map.on('rotate', this._redraw, this);
491
+ // },
492
+
493
+ // onRemove: function() {
494
+ // canvasProto.onRemove.call(this);
495
+ // this._map.off('rotate', this._redraw, this);
496
+ // },
497
+
498
+ // _update: function() {
499
+ // canvasProto._update.call(this);
500
+ // // Tell paths to redraw themselves
501
+ // this.fire('update')
502
+ // },
503
+
504
+ });
505
+
506
+ /**
507
+ * @external L.Renderer
508
+ *
509
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/Renderer.js
510
+ */
511
+
512
+ const rendererProto = L.extend({}, L.Renderer.prototype);
513
+
514
+ L.Renderer.include({
515
+
516
+ // onAdd: function() {
517
+ // rendererProto.onAdd.call(this);
518
+ // // this._map.on('rotate', this._update, this);
519
+ // },
520
+
521
+ // onRemove: function() {
522
+ // rendererProto.onRemove.call(this);
523
+ // // this._map.off('rotate', this._update, this);
524
+ // },
525
+
526
+ /**
527
+ * @TODO rechek this changes from leaflet@v1.9.3
528
+ *
529
+ * @see https://github.com/Leaflet/Leaflet/compare/v1.7.0...v1.9.3
530
+ */
531
+ _updateTransform: function(center, zoom) {
532
+ if (!this._map._rotate) {
533
+ return rendererProto._updateTransform.call(this, center, zoom);
534
+ }
535
+ var scale = this._map.getZoomScale(zoom, this._zoom),
536
+ offset = this._map._latLngToNewLayerPoint(this._topLeft, zoom, center);
537
+ if (L.Browser.any3d) {
538
+ L.DomUtil.setTransform(this._container, offset, scale);
539
+ } else {
540
+ L.DomUtil.setPosition(this._container, offset);
541
+ }
542
+ },
543
+
544
+ _update: function() {
545
+ if (!this._map._rotate) {
546
+ return rendererProto._update.call(this);
547
+ }
548
+ // Update pixel bounds of renderer container (for positioning/sizing/clipping later)
549
+ // Subclasses are responsible of firing the 'update' event.
550
+ this._bounds = this._map._getPaddedPixelBounds(this.options.padding);
551
+ this._topLeft = this._map.layerPointToLatLng(this._bounds.min);
552
+ this._center = this._map.getCenter();
553
+ this._zoom = this._map.getZoom();
554
+ },
555
+
556
+ });
557
+
558
+ /**
559
+ * @external L.SVG
560
+ *
561
+ * @see https://github.com/Leaflet/Leaflet/tree/v1.9.3/src/layer/vector/SVG.js
562
+ */
563
+
564
+ L.extend({}, L.SVG.prototype);
565
+
566
+ L.SVG.include({
567
+
568
+ // _update: function() {
569
+ // svgProto._update.call(this);
570
+ // if (this._map._rotate) {
571
+ // this.fire('update');
572
+ // }
573
+ // },
574
+
575
+ });
576
+
577
+ /**
578
+ * @external L.Map
579
+ *
580
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/Map.js
581
+ */
582
+
583
+ const mapProto = L.extend({}, L.Map.prototype);
584
+
585
+ L.Map.mergeOptions({ rotate: false, bearing: 0, });
586
+
587
+ L.Map.include({
588
+
589
+ /**
590
+ * @param {(HTMLElement|String)} id html selector
591
+ * @param {Object} [options={}] leaflet map options
592
+ */
593
+ initialize: function(id, options) {
594
+ if (options.rotate) {
595
+ this._rotate = true;
596
+ this._bearing = 0;
597
+ }
598
+ mapProto.initialize.call(this, id, options);
599
+ if(this.options.rotate){
600
+ this.setBearing(this.options.bearing);
601
+ }
602
+ },
603
+
604
+ /**
605
+ * Given a pixel coordinate relative to the map container,
606
+ * returns the corresponding pixel coordinate relative to
607
+ * the [origin pixel](#map-getpixelorigin).
608
+ *
609
+ * @param {L.Point} point pixel screen coordinates
610
+ * @returns {L.Point} transformed pixel point
611
+ */
612
+ containerPointToLayerPoint: function(point) {
613
+ if (!this._rotate) {
614
+ return mapProto.containerPointToLayerPoint.call(this, point);
615
+ }
616
+ return L.point(point)
617
+ .subtract(this._getMapPanePos())
618
+ .rotateFrom(-this._bearing, this._getRotatePanePos())
619
+ .subtract(this._getRotatePanePos());
620
+ },
621
+
622
+ /**
623
+ * Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
624
+ * returns the corresponding pixel coordinate relative to the map container.
625
+ *
626
+ * @param {L.Point} point pixel screen coordinates
627
+ * @returns {L.Point} transformed pixel point
628
+ */
629
+ layerPointToContainerPoint: function(point) { // (Point)
630
+ if (!this._rotate) {
631
+ return mapProto.layerPointToContainerPoint.call(this, point);
632
+ }
633
+ return L.point(point)
634
+ .add(this._getRotatePanePos())
635
+ .rotateFrom(this._bearing, this._getRotatePanePos())
636
+ .add(this._getMapPanePos());
637
+ },
638
+
639
+ /**
640
+ * Converts a coordinate from the rotated pane reference system
641
+ * to the reference system of the not rotated map pane.
642
+ *
643
+ * (rotatePane) --> (mapPane)
644
+ * (rotatePane) --> (norotatePane)
645
+ *
646
+ * @param {L.Point} point pixel screen coordinates
647
+ * @returns {L.Point}
648
+ */
649
+ rotatedPointToMapPanePoint: function(point) {
650
+ return L.point(point)
651
+ .rotate(this._bearing)
652
+ ._add(this._getRotatePanePos());
653
+ },
654
+
655
+ /**
656
+ * Converts a coordinate from the not rotated map pane reference system
657
+ * to the reference system of the rotated pane.
658
+ *
659
+ * (mapPane) --> (rotatePane)
660
+ * (norotatePane) --> (rotatePane)
661
+ *
662
+ * @param {L.Point} point pixel screen coordinates
663
+ */
664
+ mapPanePointToRotatedPoint: function(point) {
665
+ return L.point(point)
666
+ ._subtract(this._getRotatePanePos())
667
+ .rotate(-this._bearing);
668
+ },
669
+
670
+ /**
671
+ * Returns geographical bounds visible in the current map view
672
+ *
673
+ * @TODO find out if map bounds calculated by `L.Map::getBounds()`
674
+ * function should match the `rotatePane` or `norotatePane` bounds
675
+ *
676
+ * @see https://github.com/fnicollet/Leaflet/issues/7
677
+ *
678
+ * @returns {L.LatLngBounds}
679
+ */
680
+ getBounds: function() {
681
+ if (!this._rotate) {
682
+ return mapProto.getBounds.call(this);
683
+ }
684
+
685
+ // SEE: https://github.com/fnicollet/Leaflet/pull/22
686
+ //
687
+ // var bounds = this.getPixelBounds(),
688
+ // sw = this.unproject(bounds.getBottomLeft()),
689
+ // ne = this.unproject(bounds.getTopRight());
690
+ // return new LatLngBounds(sw, ne);
691
+ //
692
+
693
+ // LatLngBounds' constructor automatically
694
+ // extends the bounds to fit the passed points
695
+ var size = this.getSize();
696
+ return new L.LatLngBounds([
697
+ this.containerPointToLatLng([0, 0]), // topleft
698
+ this.containerPointToLatLng([size.x, 0]), // topright
699
+ this.containerPointToLatLng([size.x, size.y]), // bottomright
700
+ this.containerPointToLatLng([0, size.y]), // bottomleft
701
+ ]);
702
+ },
703
+
704
+ /**
705
+ * Returns the bounds of the current map view in projected pixel
706
+ * coordinates (sometimes useful in layer and overlay implementations).
707
+ *
708
+ * @TODO find out if map bounds calculated by `L.Map::getPixelBounds()`
709
+ * function should match the `rotatePane` or `norotatePane` bounds
710
+ *
711
+ * @see https://github.com/fnicollet/Leaflet/issues/7
712
+ *
713
+ * @returns {L.Bounds}
714
+ */
715
+ // getPixelBounds(center, zoom) {
716
+ // // const topLeftPoint = map.containerPointToLayerPoint(this._getTopLeftPoint());
717
+ // const topLeftPoint = this._getTopLeftPoint(center, zoom);
718
+ // return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
719
+ // },
720
+
721
+ /**
722
+ * Change map rotation
723
+ *
724
+ * @param {number} theta map degrees
725
+ */
726
+ setBearing: function(theta) {
727
+ if (!L.Browser.any3d || !this._rotate) { return; }
728
+
729
+ var bearing = L.Util.wrapNum(theta, [0, 360]) * L.DomUtil.DEG_TO_RAD,
730
+ center = this._getPixelCenter(),
731
+ oldPos = this._getRotatePanePos().rotateFrom(-this._bearing, center),
732
+ newPos = oldPos.rotateFrom(bearing, center);
733
+
734
+ // CSS transform
735
+ L.DomUtil.setPosition(this._rotatePane, oldPos, bearing, center);
736
+
737
+ this._pivot = center;
738
+ this._bearing = bearing;
739
+ this._rotatePanePos = newPos;
740
+
741
+ this.fire('rotate');
742
+ },
743
+
744
+ /**
745
+ * Get current map rotation
746
+ *
747
+ * @returns {number} theta map degrees
748
+ */
749
+ getBearing: function() {
750
+ return this._bearing * L.DomUtil.RAD_TO_DEG;
751
+ },
752
+
753
+ /**
754
+ * Creates a new [map pane](#map-pane) with the given name if it doesn't
755
+ * exist already, then returns it. The pane is created as a child of
756
+ * `container`, or as a child of the main map pane if not set.
757
+ *
758
+ * @param {String} name leaflet pane
759
+ * @param {HTMLElement} [container] parent element
760
+ * @returns {HTMLElement} pane container
761
+ */
762
+ // createPane: function(name, container) {
763
+ // if (!this._rotate || name == 'mapPane') {
764
+ // return mapProto.createPane.call(this, name, container);
765
+ // }
766
+ // // init "rotatePane"
767
+ // if (!this._rotatePane) {
768
+ // // this._pivot = this.getSize().divideBy(2);
769
+ // this._rotatePane = mapProto.createPane.call(this, 'rotatePane', this._mapPane);
770
+ // L.DomUtil.setPosition(this._rotatePane, new L.Point(0, 0), this._bearing, this._pivot);
771
+ // }
772
+ // return mapProto.createPane.call(this, name, container || this._rotatePane);
773
+ // },
774
+
775
+ /**
776
+ * Panes are DOM elements used to control the ordering of layers on
777
+ * the map. You can access panes with [`map.getPane`](#map-getpane)
778
+ * or [`map.getPanes`](#map-getpanes) methods. New panes can be created
779
+ * with the [`map.createPane`](#map-createpane) method.
780
+ *
781
+ * Every map has the following default panes that differ only in zIndex:
782
+ *
783
+ * - mapPane [HTMLElement = 'auto'] - Pane that contains all other map panes
784
+ * - tilePane [HTMLElement = 2] - Pane for tile layers
785
+ * - overlayPane [HTMLElement = 4] - Pane for overlays like polylines and polygons
786
+ * - shadowPane [HTMLElement = 5] - Pane for overlay shadows (e.g. marker shadows)
787
+ * - markerPane [HTMLElement = 6] - Pane for marker icons
788
+ * - tooltipPane [HTMLElement = 650] - Pane for tooltips.
789
+ * - popupPane [HTMLElement = 700] - Pane for popups.
790
+ */
791
+ _initPanes: function() {
792
+ var panes = this._panes = {};
793
+ this._paneRenderers = {};
794
+
795
+ this._mapPane = this.createPane('mapPane', this._container);
796
+ L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
797
+
798
+ if (this._rotate) {
799
+ this._rotatePane = this.createPane('rotatePane', this._mapPane);
800
+ this._norotatePane = this.createPane('norotatePane', this._mapPane);
801
+ // rotatePane
802
+ this.createPane('tilePane', this._rotatePane);
803
+ this.createPane('overlayPane', this._rotatePane);
804
+ // norotatePane
805
+ this.createPane('shadowPane', this._norotatePane);
806
+ this.createPane('markerPane', this._norotatePane);
807
+ this.createPane('tooltipPane', this._norotatePane);
808
+ this.createPane('popupPane', this._norotatePane);
809
+ } else {
810
+ this.createPane('tilePane');
811
+ this.createPane('overlayPane');
812
+ this.createPane('shadowPane');
813
+ this.createPane('markerPane');
814
+ this.createPane('tooltipPane');
815
+ this.createPane('popupPane');
816
+ }
817
+
818
+ if (!this.options.markerZoomAnimation) {
819
+ L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
820
+ L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
821
+ }
822
+ },
823
+
824
+ /**
825
+ * Pans the map the minimum amount to make the `latlng` visible. Use
826
+ * padding options to fit the display to more restricted bounds.
827
+ * If `latlng` is already within the (optionally padded) display bounds,
828
+ * the map will not be panned.
829
+ *
830
+ * @see https://github.com/Raruto/leaflet-rotate/issues/18
831
+ *
832
+ * @param {L.LatLng} latlng coordinates
833
+ * @param {Object} [options={}] padding options
834
+ *
835
+ * @returns {L.Map} current map instance
836
+ */
837
+ panInside(latlng, options) {
838
+ options = options || {};
839
+
840
+ const paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
841
+ paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
842
+ /** @TODO use mapProto.panInside */
843
+ // pixelPoint = this.project(latlng),
844
+ // pixelBounds = this.getPixelBounds(),
845
+ // pixelCenter = this.project(this.getCenter()),
846
+ rect = this._container.getBoundingClientRect(),
847
+ pixelPoint = this.latLngToContainerPoint(latlng),
848
+ pixelBounds = L.bounds([ L.point(rect), L.point(rect).add(this.getSize()) ]),
849
+ pixelCenter = pixelBounds.getCenter(),
850
+ //
851
+ paddedBounds = L.bounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
852
+ paddedSize = paddedBounds.getSize();
853
+
854
+ if (!paddedBounds.contains(pixelPoint)) {
855
+ this._enforcingBounds = true;
856
+ const centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
857
+ const offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
858
+ pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
859
+ pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
860
+ /** @TODO use mapProto.panInside */
861
+ // this.panTo(this.unproject(pixelCenter), options);
862
+ this.panTo(this.containerPointToLatLng(pixelCenter), options);
863
+ //
864
+ this._enforcingBounds = false;
865
+ }
866
+ return this;
867
+ },
868
+
869
+ /**
870
+ * Pans the map to the closest view that would lie inside the given bounds
871
+ * (if it's not already), controlling the animation using the options specific,
872
+ * if any.
873
+ *
874
+ * @TODO check if map bounds calculated by `L.Map::panInsideBounds()`
875
+ * function should match the `rotatePane` or `norotatePane` bounds
876
+ *
877
+ * @see https://github.com/fnicollet/Leaflet/issues/7
878
+ *
879
+ * @param {L.LatLngBounds} bounds coordinates
880
+ * @param {Object} [options] pan options
881
+ * @returns {L.Map} current map instance
882
+ */
883
+ // panInsideBounds: function (bounds, options) {
884
+ // this._enforcingBounds = true;
885
+ // var center = this.getCenter(),
886
+ // newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
887
+
888
+ // if (!center.equals(newCenter)) {
889
+ // this.panTo(newCenter, options);
890
+ // }
891
+
892
+ // this._enforcingBounds = false;
893
+ // return this;
894
+ // },
895
+
896
+ /**
897
+ * Layer point of the current center
898
+ *
899
+ * @returns {L.Point} layer center
900
+ */
901
+ // _getCenterLayerPoint: function () {
902
+ // return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
903
+ // },
904
+
905
+ /**
906
+ * Offset of the specified place to the current center in pixels
907
+ *
908
+ * @param {L.LatLng} latlng map coordinates
909
+ */
910
+ _getCenterOffset: function(latlng) {
911
+ var centerOffset = mapProto._getCenterOffset.call(this, latlng);
912
+ if (this._rotate) {
913
+ centerOffset = centerOffset.rotate(this._bearing);
914
+ }
915
+ return centerOffset;
916
+ },
917
+
918
+ _getRotatePanePos: function() {
919
+ return this._rotatePanePos || new L.Point(0, 0);
920
+ // return L.DomUtil.getPosition(this._rotatePane) || new L.Point(0, 0);
921
+ },
922
+
923
+ _getNewPixelOrigin: function(center, zoom) {
924
+ var viewHalf = this.getSize()._divideBy(2);
925
+ if (!this._rotate) {
926
+ return mapProto._getNewPixelOrigin.call(this, center, zoom);
927
+ }
928
+ return this.project(center, zoom)
929
+ .rotate(this._bearing)
930
+ ._subtract(viewHalf)
931
+ ._add(this._getMapPanePos())
932
+ ._add(this._getRotatePanePos())
933
+ .rotate(-this._bearing)
934
+ ._round();
935
+ },
936
+
937
+ /**
938
+ * @since leaflet-rotate (v0.2)
939
+ *
940
+ * @see src\layer\tile\GridLayer::_getTiledPixelBounds()
941
+ */
942
+ _getNewPixelBounds: function(center, zoom) {
943
+ center = center || this.getCenter();
944
+ zoom = zoom || this.getZoom();
945
+ if (!this._rotate && mapProto._getNewPixelBounds) {
946
+ return mapProto._getNewPixelBounds.apply(this, arguments);
947
+ }
948
+ var mapZoom = this._animatingZoom ? Math.max(this._animateToZoom, this.getZoom()) : this.getZoom(),
949
+ scale = this.getZoomScale(mapZoom, zoom),
950
+ pixelCenter = this.project(center, zoom).floor(),
951
+ size = this.getSize(),
952
+ halfSize = new L.Bounds([
953
+ this.containerPointToLayerPoint([0, 0]).floor(),
954
+ this.containerPointToLayerPoint([size.x, 0]).floor(),
955
+ this.containerPointToLayerPoint([0, size.y]).floor(),
956
+ this.containerPointToLayerPoint([size.x, size.y]).floor()
957
+ ]).getSize().divideBy(scale * 2);
958
+
959
+ return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
960
+ },
961
+
962
+ /**
963
+ * @since leaflet-rotate (v0.2)
964
+ *
965
+ * @return {L.Point} map pivot point (center)
966
+ */
967
+ _getPixelCenter: function() {
968
+ if (!this._rotate && mapProto._getPixelCenter) {
969
+ return mapProto._getPixelCenter.apply(this, arguments);
970
+ }
971
+ return this.getSize()._divideBy(2)._subtract(this._getMapPanePos());
972
+ },
973
+
974
+ /**
975
+ * @since leaflet-rotate (v0.2)
976
+ *
977
+ * @see src\layer\vector\Renderer::_update()
978
+ */
979
+ _getPaddedPixelBounds: function(padding) {
980
+ if (!this._rotate && mapProto._getPaddedPixelBounds) {
981
+ return mapProto._getPaddedPixelBounds.apply(this, arguments);
982
+ }
983
+ var p = padding,
984
+ size = this.getSize(),
985
+ padMin = size.multiplyBy(-p),
986
+ padMax = size.multiplyBy(1 + p);
987
+ //min = this.containerPointToLayerPoint(size.multiplyBy(-p)).round();
988
+
989
+ return new L.Bounds([
990
+ this.containerPointToLayerPoint([padMin.x, padMin.y]).floor(),
991
+ this.containerPointToLayerPoint([padMin.x, padMax.y]).floor(),
992
+ this.containerPointToLayerPoint([padMax.x, padMin.y]).floor(),
993
+ this.containerPointToLayerPoint([padMax.x, padMax.y]).floor()
994
+ ]);
995
+ },
996
+
997
+ _handleGeolocationResponse: function(pos) {
998
+ if (!this._container._leaflet_id) { return; }
999
+
1000
+ var lat = pos.coords.latitude,
1001
+ lng = pos.coords.longitude,
1002
+ /** @TODO use mapProto._handleGeolocationResponse */
1003
+ hdg = pos.coords.heading,
1004
+ latlng = new L.LatLng(lat, lng),
1005
+ bounds = latlng.toBounds(pos.coords.accuracy),
1006
+ options = this._locateOptions;
1007
+
1008
+ if (options.setView) {
1009
+ var zoom = this.getBoundsZoom(bounds);
1010
+ this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
1011
+ }
1012
+
1013
+ var data = {
1014
+ latlng: latlng,
1015
+ bounds: bounds,
1016
+ timestamp: pos.timestamp,
1017
+ /** @TODO use mapProto._handleGeolocationResponse */
1018
+ heading: hdg
1019
+ };
1020
+
1021
+ for (var i in pos.coords) {
1022
+ if (typeof pos.coords[i] === 'number') {
1023
+ data[i] = pos.coords[i];
1024
+ }
1025
+ }
1026
+
1027
+ // @event locationfound: LocationEvent
1028
+ // Fired when geolocation (using the [`locate`](#map-locate) method)
1029
+ // went successfully.
1030
+ this.fire('locationfound', data);
1031
+ },
1032
+
1033
+ /**
1034
+ * Given latlng bounds, returns the bounds in projected pixel
1035
+ * relative to the map container.
1036
+ *
1037
+ * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/map/Map.js#L1114-L1135
1038
+ *
1039
+ * @param {L.LatLngBounds} bounds
1040
+ * @returns {L.Bounds}
1041
+ */
1042
+ // boundsToContainerBounds: function (bounds) {
1043
+ // if (this._rotate) {
1044
+ // var northWest = this.latLngToContainerPoint(bounds.getNorthWest());
1045
+ // var northEast = this.latLngToContainerPoint(bounds.getNorthEast());
1046
+ // var southWest = this.latLngToContainerPoint(bounds.getSouthWest());
1047
+ // var southEast = this.latLngToContainerPoint(bounds.getSouthEast());
1048
+ //
1049
+ // var minX = Math.min(northWest.x, northEast.x, southEast.x, southWest.x);
1050
+ // var maxX = Math.max(northWest.x, northEast.x, southEast.x, southWest.x);
1051
+ // var minY = Math.min(northWest.y, northEast.y, southEast.y, southWest.y);
1052
+ // var maxY = Math.max(northWest.y, northEast.y, southEast.y, southWest.y);
1053
+ //
1054
+ // return L.bounds(
1055
+ // L.point(minX, minY).multiplyBy(-1),
1056
+ // L.point(maxX, maxY).multiplyBy(-1).add(this.getSize())
1057
+ // );
1058
+ // } else {
1059
+ // return L.Bounds(
1060
+ // this.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
1061
+ // this.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1).add(this.getSize())
1062
+ // );
1063
+ // }
1064
+ // },
1065
+
1066
+ /**
1067
+ * @see https://github.com/ronikar/Leaflet/blob/5c480ef959b947c3beed7065425a5a36c486262b/src/geo/LatLngBounds.js#L253-L264
1068
+ *
1069
+ * @param {L.Bounds} points
1070
+ * @returns {L.Bounds}
1071
+ */
1072
+ // toCircumscribedBounds(points) {
1073
+ // var minX = points.reduce(function (pv, v) { return Math.min(pv, v.x); }, points[0].x),
1074
+ // maxX = points.reduce(function (pv, v) { return Math.max(pv, v.x); }, points[0].x),
1075
+ // minY = points.reduce(function (pv, v) { return Math.min(pv, v.y); }, points[0].y),
1076
+ // maxY = points.reduce(function (pv, v) { return Math.max(pv, v.y); }, points[0].y);
1077
+ //
1078
+ // return L.bounds(L.point(minX, minY), L.point(maxX, maxY));
1079
+ // },
1080
+
1081
+ });
1082
+
1083
+ /**
1084
+ * Rotates the map according to a smartphone's compass.
1085
+ *
1086
+ * @typedef L.Map.CompassBearing
1087
+ */
1088
+
1089
+ L.Map.CompassBearing = L.Handler.extend({
1090
+
1091
+ initialize: function(map) {
1092
+ this._map = map;
1093
+ this._throttled = L.Util.throttle(this._onDeviceOrientation, 1000, this);
1094
+ },
1095
+
1096
+ addHooks: function() {
1097
+ if (this._map._rotate && window.DeviceOrientationEvent) {
1098
+ L.DomEvent.on(window, 'deviceorientation', this._throttled, this);
1099
+ }
1100
+ },
1101
+
1102
+ removeHooks: function() {
1103
+ if (this._map._rotate && window.DeviceOrientationEvent) {
1104
+ L.DomEvent.off(window, 'deviceorientation', this._throttled, this);
1105
+ }
1106
+ },
1107
+
1108
+ _onDeviceOrientation: function(event) {
1109
+ if (event.alpha !== null && window.orientation !== undefined) {
1110
+ this._map.setBearing(event.alpha - window.orientation);
1111
+ }
1112
+ },
1113
+
1114
+ });
1115
+
1116
+ // @section Handlers
1117
+ // @property compassBearing: Handler
1118
+ // Compass bearing handler.
1119
+ L.Map.addInitHook('addHandler', 'compassBearing', L.Map.CompassBearing);
1120
+
1121
+ /**
1122
+ * Triggers `invalidateResize` when the map's DOM container mutates.
1123
+ *
1124
+ * @typedef L.Map.ContainerMutation
1125
+ */
1126
+
1127
+ // @namespace Map
1128
+ // @section Interaction Options
1129
+ L.Map.mergeOptions({
1130
+
1131
+ // @option trackContainerMutation: Boolean = false
1132
+ // Whether the map uses [mutation observers](https://developer.mozilla.org/docs/Web/API/MutationObserver)
1133
+ // to detect changes in its container and trigger `invalidateSize`. Disabled
1134
+ // by default due to support not being available in all web browsers.
1135
+ trackContainerMutation: false
1136
+
1137
+ });
1138
+
1139
+ L.Map.ContainerMutation = L.Handler.extend({
1140
+
1141
+ addHooks: function() {
1142
+ /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1143
+ // if (!L.Browser.mutation) {
1144
+ // return;
1145
+ // }
1146
+
1147
+ if (!this._observer) {
1148
+ this._observer = new MutationObserver(L.Util.bind(this._onMutation, this));
1149
+ }
1150
+
1151
+ this._observer.observe(this._map.getContainer(), {
1152
+ childList: false,
1153
+ attributes: true,
1154
+ characterData: false,
1155
+ subtree: false,
1156
+ attributeFilter: ['style']
1157
+ });
1158
+ },
1159
+
1160
+ removeHooks: function() {
1161
+ /** @TODO check again this property. Will likely be added in future releases (leaflet > v1.9.3) */
1162
+ // if (!L.Browser.mutation) {
1163
+ // return;
1164
+ // }
1165
+ this._observer.disconnect();
1166
+ },
1167
+
1168
+ _onMutation: function() {
1169
+ this._map.invalidateSize();
1170
+ },
1171
+
1172
+ });
1173
+
1174
+ // @section Handlers
1175
+ // @property containerMutation: Handler
1176
+ // Container mutation handler (disabled unless [`trackContainerMutation`](#map-trackcontainermutation) is set).
1177
+ L.Map.addInitHook('addHandler', 'trackContainerMutation', L.Map.ContainerMutation);
1178
+
1179
+ /**
1180
+ * TouchGestures is both TouchZoom plus TouchRotate
1181
+ *
1182
+ * @see https://github.com/fnicollet/Leaflet/commit/a77af51a6b10f308d1b9a16552091d1d0aee8834
1183
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/handler/Map.TouchZoom.js
1184
+ *
1185
+ * @typedef L.Map.TouchGestures
1186
+ */
1187
+
1188
+ // @namespace Map
1189
+ // @section Interaction Options
1190
+ L.Map.mergeOptions({
1191
+
1192
+ // @option bounceAtZoomLimits: Boolean = true
1193
+ // Set it to false if you don't want the map to zoom beyond min/max zoom
1194
+ // and then bounce back when pinch-zooming.
1195
+ bounceAtZoomLimits: true,
1196
+
1197
+ });
1198
+
1199
+ L.Map.TouchGestures = L.Handler.extend({
1200
+
1201
+ initialize: function(map) {
1202
+ this._map = map;
1203
+ this.rotate = !!this._map.options.touchRotate;
1204
+ this.zoom = !!this._map.options.touchZoom;
1205
+ },
1206
+
1207
+ addHooks: function() {
1208
+ L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
1209
+ },
1210
+
1211
+ removeHooks: function() {
1212
+ L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
1213
+ },
1214
+
1215
+ _onTouchStart: function(e) {
1216
+ var map = this._map;
1217
+
1218
+ if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming || this._rotating) { return; }
1219
+
1220
+ var p1 = map.mouseEventToContainerPoint(e.touches[0]),
1221
+ p2 = map.mouseEventToContainerPoint(e.touches[1]),
1222
+ vector = p1.subtract(p2);
1223
+
1224
+ this._centerPoint = map.getSize()._divideBy(2);
1225
+ this._startLatLng = map.containerPointToLatLng(this._centerPoint);
1226
+
1227
+ if (this.zoom) {
1228
+ if (map.options.touchZoom !== 'center') {
1229
+ this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
1230
+ }
1231
+ this._startDist = p1.distanceTo(p2);
1232
+ this._startZoom = map.getZoom();
1233
+ this._zooming = true;
1234
+ } else {
1235
+ this._zooming = false;
1236
+ }
1237
+
1238
+ if (this.rotate) {
1239
+ this._startTheta = Math.atan(vector.x / vector.y);
1240
+ this._startBearing = map.getBearing();
1241
+ if (vector.y < 0) { this._startBearing += 180; }
1242
+ this._rotating = true;
1243
+ } else {
1244
+ this._rotating = false;
1245
+ }
1246
+
1247
+ this._moved = false;
1248
+
1249
+ map._stop();
1250
+
1251
+ L.DomEvent
1252
+ .on(document, 'touchmove', this._onTouchMove, this)
1253
+ .on(document, 'touchend touchcancel', this._onTouchEnd, this);
1254
+
1255
+ L.DomEvent.preventDefault(e);
1256
+ },
1257
+
1258
+ _onTouchMove: function(e) {
1259
+ if (!e.touches || e.touches.length !== 2 || !(this._zooming || this._rotating)) { return; }
1260
+
1261
+ var map = this._map,
1262
+ p1 = map.mouseEventToContainerPoint(e.touches[0]),
1263
+ p2 = map.mouseEventToContainerPoint(e.touches[1]),
1264
+ vector = p1.subtract(p2),
1265
+ scale = p1.distanceTo(p2) / this._startDist,
1266
+ delta;
1267
+
1268
+ if (this._rotating) {
1269
+ var theta = Math.atan(vector.x / vector.y);
1270
+ var bearingDelta = (theta - this._startTheta) * L.DomUtil.RAD_TO_DEG;
1271
+ if (vector.y < 0) { bearingDelta += 180; }
1272
+ if (bearingDelta) {
1273
+ /// TODO: The pivot should be the last touch point, but zoomAnimation manages to
1274
+ /// overwrite the rotate pane position. Maybe related to #3529.
1275
+ map.setBearing(this._startBearing - bearingDelta);
1276
+ }
1277
+ }
1278
+
1279
+ if (this._zooming) {
1280
+ this._zoom = map.getScaleZoom(scale, this._startZoom);
1281
+
1282
+ if (!map.options.bounceAtZoomLimits && (
1283
+ (this._zoom < map.getMinZoom() && scale < 1) ||
1284
+ (this._zoom > map.getMaxZoom() && scale > 1))) {
1285
+ this._zoom = map._limitZoom(this._zoom);
1286
+ }
1287
+
1288
+ if (map.options.touchZoom === 'center') {
1289
+ this._center = this._startLatLng;
1290
+ if (scale === 1) { return; }
1291
+ } else {
1292
+ // Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
1293
+ delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
1294
+ if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
1295
+
1296
+ var alpha = -map.getBearing() * L.DomUtil.DEG_TO_RAD;
1297
+
1298
+ this._center = map.unproject(map.project(this._pinchStartLatLng).subtract(delta.rotate(alpha)));
1299
+ }
1300
+
1301
+ }
1302
+
1303
+ if (!this._moved) {
1304
+ map._moveStart(true, false);
1305
+ this._moved = true;
1306
+ }
1307
+
1308
+ L.Util.cancelAnimFrame(this._animRequest);
1309
+
1310
+ var moveFn = map._move.bind(map, this._center, this._zoom, { pinch: true, round: false }, undefined);
1311
+ this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
1312
+
1313
+ L.DomEvent.preventDefault(e);
1314
+ },
1315
+
1316
+ _onTouchEnd: function() {
1317
+ if (!this._moved || !(this._zooming || this._rotating)) {
1318
+ this._zooming = false;
1319
+ return;
1320
+ }
1321
+
1322
+ this._zooming = false;
1323
+ this._rotating = false;
1324
+ L.Util.cancelAnimFrame(this._animRequest);
1325
+
1326
+ L.DomEvent
1327
+ .off(document, 'touchmove', this._onTouchMove, this)
1328
+ .off(document, 'touchend touchcancel', this._onTouchEnd, this);
1329
+
1330
+ if (this.zoom) {
1331
+ // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
1332
+ if (this._map.options.zoomAnimation) {
1333
+ this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
1334
+ } else {
1335
+ this._map._resetView(this._center, this._map._limitZoom(this._zoom));
1336
+ }
1337
+ }
1338
+ },
1339
+
1340
+ });
1341
+
1342
+ // @section Handlers
1343
+ // @property touchGestures: Handler
1344
+ // Touch gestures handler.
1345
+ L.Map.addInitHook('addHandler', 'touchGestures', L.Map.TouchGestures);
1346
+
1347
+ /**
1348
+ * Rotates the map on two-finger (touch devices).
1349
+ *
1350
+ * @typedef L.Map.TouchRotate
1351
+ */
1352
+
1353
+ // @namespace Map
1354
+ // @section Interaction Options
1355
+ L.Map.mergeOptions({
1356
+
1357
+ // @section Touch interaction options
1358
+ // @option touchRotate: Boolean|String = *
1359
+ // Whether the map can be rotated with a two-finger rotation gesture
1360
+ touchRotate: false,
1361
+
1362
+ });
1363
+
1364
+ L.Map.TouchRotate = L.Handler.extend({
1365
+
1366
+ addHooks: function() {
1367
+ this._map.touchGestures.enable();
1368
+ this._map.touchGestures.rotate = true;
1369
+ },
1370
+
1371
+ removeHooks: function() {
1372
+ this._map.touchGestures.rotate = false;
1373
+ },
1374
+
1375
+ });
1376
+
1377
+ // @section Handlers
1378
+ // @property touchZoom: Handler
1379
+ // Touch rotate handler.
1380
+ L.Map.addInitHook('addHandler', 'touchRotate', L.Map.TouchRotate);
1381
+
1382
+ /**
1383
+ * Rotates the map on shift key + mouseheel scrolling (desktop).
1384
+ *
1385
+ * @typedef L.Map.ShiftKeyRotate
1386
+ */
1387
+
1388
+ // @namespace Map
1389
+ // @section Interaction Options
1390
+ L.Map.mergeOptions({
1391
+
1392
+ // @section ShiftKey interaction options
1393
+ // @option shiftKeyRotate: Boolean|String = *
1394
+ // Whether the map can be rotated with a shit-wheel rotation
1395
+ shiftKeyRotate: true,
1396
+
1397
+ });
1398
+
1399
+ L.Map.ShiftKeyRotate = L.Handler.extend({
1400
+
1401
+ addHooks: function() {
1402
+ L.DomEvent.on(this._map._container, "wheel", this._handleShiftScroll, this);
1403
+ // this._map.shiftKeyRotate.enable();
1404
+ this._map.shiftKeyRotate.rotate = true;
1405
+ },
1406
+
1407
+ removeHooks: function() {
1408
+ L.DomEvent.off(this._map._container, "wheel", this._handleShiftScroll, this);
1409
+ this._map.shiftKeyRotate.rotate = false;
1410
+ },
1411
+
1412
+ _handleShiftScroll: function(e) {
1413
+ if (e.shiftKey) {
1414
+ e.preventDefault();
1415
+ this._map.scrollWheelZoom.disable();
1416
+ this._map.setBearing((this._map._bearing * L.DomUtil.RAD_TO_DEG) + Math.sign(e.deltaY) * 5);
1417
+ } else {
1418
+ this._map.scrollWheelZoom.enable();
1419
+ }
1420
+ },
1421
+
1422
+ });
1423
+
1424
+ // @section Handlers
1425
+ // @property touchZoom: Handler
1426
+ // Touch rotate handler.
1427
+ L.Map.addInitHook('addHandler', 'shiftKeyRotate', L.Map.ShiftKeyRotate);
1428
+
1429
+ // decrease "scrollWheelZoom" handler priority over "shiftKeyRotate" handler
1430
+ L.Map.addInitHook(function() {
1431
+ if (this.scrollWheelZoom.enabled() && this.shiftKeyRotate.enabled()) {
1432
+ this.scrollWheelZoom.disable();
1433
+ this.scrollWheelZoom.enable();
1434
+ }
1435
+ });
1436
+
1437
+ /**
1438
+ * Adds pinch zoom rotation on mobile browsers
1439
+ *
1440
+ * @see https://github.com/Leaflet/Leaflet/blob/v1.9.3/src/map/handler/Map.TouchZoom.js
1441
+ *
1442
+ * @external L.Map.TouchZoom
1443
+ */
1444
+
1445
+ // @namespace Map
1446
+ // @section Interaction Options
1447
+ L.Map.mergeOptions({
1448
+
1449
+ // @section Touch interaction options
1450
+ // @option touchZoom: Boolean|String = *
1451
+ // Whether the map can be zoomed by touch-dragging with two fingers. If
1452
+ // passed `'center'`, it will zoom to the center of the view regardless of
1453
+ // where the touch events (fingers) were. Enabled for touch-capable web
1454
+ // browsers.
1455
+ touchZoom: L.Browser.touch,
1456
+
1457
+ /**
1458
+ * @TODO check if this is a duplicate of `L.Map.TouchGestures::bounceAtZoomLimits`
1459
+ */
1460
+
1461
+ // @option bounceAtZoomLimits: Boolean = true
1462
+ // Set it to false if you don't want the map to zoom beyond min/max zoom
1463
+ // and then bounce back when pinch-zooming.
1464
+ bounceAtZoomLimits: false,
1465
+
1466
+ });
1467
+
1468
+ L.Map.TouchZoom = L.Handler.extend({
1469
+
1470
+ addHooks: function() {
1471
+ L.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');
1472
+ this._map.touchGestures.enable();
1473
+ this._map.touchGestures.zoom = true;
1474
+ },
1475
+
1476
+ removeHooks: function() {
1477
+ L.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');
1478
+ this._map.touchGestures.zoom = false;
1479
+ },
1480
+
1481
+ });
1482
+
1483
+ // @section Handlers
1484
+ // @property touchZoom: Handler
1485
+ // Touch zoom handler.
1486
+ L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
1487
+
1488
+ /**
1489
+ * A tri-state control for map rotation, states are:
1490
+ *
1491
+ * - Locked (default)
1492
+ * - Unlocked (user can pinch-rotate)
1493
+ * - Follow (rotation follows device orientation, if available)
1494
+ *
1495
+ * @typedef L.Control.Rotate
1496
+ */
1497
+
1498
+ L.Control.Rotate = L.Control.extend({
1499
+
1500
+ options: {
1501
+ position: 'topleft',
1502
+ closeOnZeroBearing: true
1503
+ },
1504
+
1505
+ onAdd: function(map) {
1506
+ this._onDeviceOrientation = L.Util.throttle(this._unthrottledOnDeviceOrientation, 100, this);
1507
+
1508
+ var container = this._container = L.DomUtil.create('div', 'leaflet-control-rotate leaflet-bar');
1509
+
1510
+ // this.button = L.Control.Zoom.prototype._createButton.call(this, 'R', 'leaflet-control-rotate', 'leaflet-control-rotate', container, this._toggleLock);
1511
+
1512
+ var arrow = this._arrow = L.DomUtil.create('span', 'leaflet-control-rotate-arrow');
1513
+
1514
+ arrow.style.backgroundImage = `url("data:image/svg+xml;charset=utf-8,%3Csvg width='29' height='29' viewBox='0 0 29 29' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23ccc'/%3E%3C/svg%3E")`;
1515
+ arrow.style.cursor = 'grab';
1516
+ arrow.style.display = 'block';
1517
+ arrow.style.width = '100%';
1518
+ arrow.style.height = '100%';
1519
+ arrow.style.backgroundRepeat = 'no-repeat';
1520
+ arrow.style.backgroundPosition = '50%';
1521
+
1522
+ // Copy-pasted from L.Control.Zoom
1523
+ var link = this._link = L.DomUtil.create('a', 'leaflet-control-rotate-toggle', container);
1524
+ link.appendChild(arrow);
1525
+ link.href = '#';
1526
+ link.title = 'Rotate map';
1527
+ // link.draggable = false;
1528
+
1529
+ L.DomEvent
1530
+ .on(link, 'dblclick', L.DomEvent.stopPropagation)
1531
+ .on(link, 'mousedown', this._handleMouseDown, this)
1532
+ .on(link, 'click', L.DomEvent.stop)
1533
+ .on(link, 'click', this._cycleState, this)
1534
+ .on(link, 'click', this._refocusOnMap, this);
1535
+
1536
+ if (!L.Browser.any3d) {
1537
+ L.DomUtil.addClass(link, 'leaflet-disabled');
1538
+ }
1539
+
1540
+ this._restyle();
1541
+
1542
+ map.on('rotate', this._restyle.bind(this));
1543
+
1544
+ // State flag
1545
+ this._follow = false;
1546
+ this._canFollow = false;
1547
+
1548
+ if (this.options.closeOnZeroBearing && map.getBearing() === 0) {
1549
+ container.style.display = 'none';
1550
+ }
1551
+
1552
+ return container;
1553
+ },
1554
+
1555
+ _handleMouseDown: function(e) {
1556
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1557
+ this.dragging = true;
1558
+ this.dragstartX = e.pageX;
1559
+ this.dragstartY = e.pageY;
1560
+ L.DomEvent
1561
+ .on(document, 'mousemove', this._handleMouseDrag, this)
1562
+ .on(document, 'mouseup', this._handleMouseUp, this);
1563
+ },
1564
+
1565
+ _handleMouseUp: function(e) {
1566
+ L.DomEvent.stop(e); // L.DomEvent.stopPropagation(e);
1567
+ this.dragging = false;
1568
+
1569
+ L.DomEvent
1570
+ .off(document, 'mousemove', this._handleMouseDrag, this)
1571
+ .off(document, 'mouseup', this._handleMouseUp, this);
1572
+ },
1573
+
1574
+ _handleMouseDrag: function(e) {
1575
+ if (!this.dragging) { return; }
1576
+ var deltaX = e.clientX - this.dragstartX;
1577
+ this._map.setBearing(deltaX);
1578
+ },
1579
+
1580
+ _cycleState: function(ev) {
1581
+ var map = this._map;
1582
+
1583
+ if (!map) { return; }
1584
+
1585
+ if (!map.touchRotate.enabled() && !map.compassBearing.enabled()) {
1586
+ // Go from disabled to touch
1587
+ map.touchRotate.enable();
1588
+
1589
+ // console.log('state is now: touch rotate');
1590
+ } else {
1591
+
1592
+ if (!map.compassBearing.enabled()) {
1593
+ // Go from touch to compass
1594
+ map.touchRotate.disable();
1595
+ map.compassBearing.enable();
1596
+
1597
+ // console.log('state is now: compass');
1598
+
1599
+ // It is possible that compass is not supported. If so,
1600
+ // the hangler will automatically go from compass to disabled.
1601
+ } else {
1602
+ // Go from compass to disabled
1603
+ map.compassBearing.disable();
1604
+
1605
+ // console.log('state is now: locked');
1606
+
1607
+ map.setBearing(0);
1608
+ if (this.options.closeOnZeroBearing) {
1609
+ map.touchRotate.enable();
1610
+ }
1611
+ }
1612
+ }
1613
+ this._restyle();
1614
+ },
1615
+
1616
+ _restyle: function() {
1617
+ if (this._map.options.rotate) {
1618
+ var map = this._map;
1619
+ var bearing = map.getBearing();
1620
+ if (this.options.closeOnZeroBearing && bearing) {
1621
+ this._container.style.display = 'block';
1622
+ }
1623
+
1624
+ var cssTransform = 'rotate(' + bearing + 'deg)';
1625
+ this._arrow.style.transform = cssTransform;
1626
+
1627
+ if (map.compassBearing.enabled()) {
1628
+ this._link.style.backgroundColor = 'orange';
1629
+ } else if (map.touchRotate.enabled()) {
1630
+ this._link.style.backgroundColor = null;
1631
+ } else {
1632
+ this._link.style.backgroundColor = 'grey';
1633
+ if (this.options.closeOnZeroBearing && map.getBearing() === 0) {
1634
+ this._container.style.display = 'none';
1635
+ }
1636
+ }
1637
+ } else {
1638
+ L.DomUtil.addClass(this._link, 'leaflet-disabled');
1639
+ }
1640
+ },
1641
+
1642
+ });
1643
+
1644
+ L.control.rotate = function(options) {
1645
+ return new L.Control.Rotate(options);
1646
+ };
1647
+
1648
+ L.Map.mergeOptions({
1649
+ rotateControl: true,
1650
+ });
1651
+
1652
+ L.Map.addInitHook(function() {
1653
+ if (this.options.rotateControl) {
1654
+ var options = typeof this.options.rotateControl === 'object' ? this.options.rotateControl : {};
1655
+ this.rotateControl = L.control.rotate(options);
1656
+ this.addControl(this.rotateControl);
1657
+ }
1658
+ });
1659
+
1660
+ }));
2
1661
  //# sourceMappingURL=leaflet-rotate.js.map