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.
- package/README.md +3 -3
- package/build/rollup.config.js +4 -4
- package/dist/leaflet-rotate-src.js +626 -311
- package/dist/leaflet-rotate-src.js.map +1 -1
- package/dist/leaflet-rotate.js +1660 -1
- package/dist/leaflet-rotate.js.map +1 -1
- package/lib/debug.js +219 -25
- package/lib/debug.min.js +1 -9
- package/package.json +10 -7
- package/src/control/Rotate.js +10 -7
- package/src/dom/DomUtil.js +4 -1
- package/src/dom/Draggable.js +8 -5
- package/src/geometry/Point.js +22 -18
- package/src/index.js +5 -3
- package/src/layer/DivOverlay.js +13 -21
- package/src/layer/Popup.js +30 -10
- package/src/layer/Tooltip.js +10 -7
- package/src/layer/marker/Icon.js +5 -2
- package/src/layer/marker/Marker.js +42 -37
- package/src/layer/tile/GridLayer.js +5 -14
- package/src/layer/vector/Canvas.js +18 -15
- package/src/layer/vector/Renderer.js +21 -30
- package/src/layer/vector/SVG.js +10 -7
- package/src/map/Map.js +363 -93
- package/src/map/handler/CompassBearing.js +7 -11
- package/src/map/handler/ContainerMutation.js +12 -8
- package/src/map/handler/ShiftKeyRotate.js +6 -3
- package/src/map/handler/TouchGestures.js +16 -11
- package/src/map/handler/TouchRotate.js +4 -2
- package/src/map/handler/TouchZoom.js +16 -4
- package/test/index.html +29 -6
- package/build/rollup.config.min.js +0 -2
package/dist/leaflet-rotate.js
CHANGED
|
@@ -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
|