;(function (window, document, undefined) { window.map23DVersion = '2.1.16' if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map23DVersion; } else if (typeof define === 'function' && define.amd) { define(map23DVersion); } }(window, document)); /* Leaflet 1.0.2+4bbb16c, a JS library for interactive maps. http://leafletjs.com (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ !function(t,e,i){function n(){var e=t.L;o.noConflict=function(){return t.L=e,this},t.L=o}var o={version:"1.0.2+4bbb16c"};"object"==typeof module&&"object"==typeof module.exports?module.exports=o:"function"==typeof define&&define.amd&&define(o),"undefined"!=typeof t&&n(),o.Util={extend:function(t){var e,i,n,o;for(i=1,n=arguments.length;i1}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new o.Point(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new o.Point(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:"object"==typeof t&&"x"in t&&"y"in t?new o.Point(t.x,t.y):new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>=e.x&&n.x<=i.x,a=s.y>=e.y&&n.y<=i.y;return r&&a},overlaps:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>e.x&&n.xe.y&&n.y0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(n)},addClass:function(t,e){if(t.classList!==i)for(var n=o.Util.splitWords(e),s=0,r=n.length;s=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>=e.lat&&n.lat<=i.lat,a=s.lng>=e.lng&&n.lng<=i.lng;return r&&a},overlaps:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>e.lat&&n.late.lng&&n.lngthis.options.maxZoom?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),n=this._limitCenter(i,this._zoom,o.latLngBounds(t));return i.equals(n)||this.panTo(n,e),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=o.extend({animate:!1,pan:!0},t===!0?{animate:!0}:t);var e=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var i=this.getSize(),n=e.divideBy(2).round(),s=i.divideBy(2).round(),r=n.subtract(s);return r.x||r.y?(t.animate&&t.pan?this.panBy(r):(t.pan&&this._rawPanBy(r),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=o.extend({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+i+"."})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=n.toBounds(t.coords.accuracy),r=this._locateOptions;if(r.setView){var a=this.getBoundsZoom(s);this.setView(n,r.maxZoom?Math.min(a,r.maxZoom):a)}var h={latlng:n,bounds:s,timestamp:t.timestamp};for(var l in t.coords)"number"==typeof t.coords[l]&&(h[l]=t.coords[l]);this.fire("locationfound",h)},addHandler:function(t,e){if(!e)return this;var i=this[t]=new e(this);return this._handlers.push(i),this.options[t]&&i.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=i,this._containerId=i}o.DomUtil.remove(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire("unload");for(var t in this._layers)this._layers[t].remove();return this},createPane:function(t,e){var i="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=o.DomUtil.create("div",i,e||this._mapPane);return t&&(this._panes[t]=n),n},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i)},getMinZoom:function(){return this.options.minZoom===i?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=o.latLngBounds(t),i=o.point(i||[0,0]);var n=this.getZoom()||0,s=this.getMinZoom(),r=this.getMaxZoom(),a=t.getNorthWest(),h=t.getSouthEast(),l=this.getSize().subtract(i),u=this.project(h,n).subtract(this.project(a,n)),c=o.Browser.any3d?this.options.zoomSnap:1,d=Math.min(l.x/u.x,l.y/u.y);return n=this.getScaleZoom(d,n),c&&(n=Math.round(n/(c/100))*(c/100),n=e?Math.ceil(n/c)*c:Math.floor(n/c)*c),Math.max(s,Math.min(r,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new o.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){var i=this._getTopLeftPoint(t,e);return new o.Bounds(i,i.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(t===i?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var n=this.options.crs;return e=e===i?this._zoom:e,n.scale(t)/n.scale(e)},getScaleZoom:function(t,e){var n=this.options.crs;e=e===i?this._zoom:e;var o=n.zoom(t*n.scale(e));return isNaN(o)?1/0:o},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(o.latLng(t))},distance:function(t,e){return this.options.crs.distance(o.latLng(t),o.latLng(e))},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet_id)throw new Error("Map container is already initialized.");o.DomEvent.addListener(e,"scroll",this._onScroll,this),this._containerId=o.Util.stamp(e)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&o.Browser.any3d,o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(o.Browser.ielt9?" leaflet-oldie":"")+(o.Browser.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(), this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),o.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e){o.DomUtil.setPosition(this._mapPane,new o.Point(0,0));var i=!this._loaded;this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset");var n=this._zoom!==e;this._moveStart(n)._move(t,e)._moveEnd(n),this.fire("viewreset"),i&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,e,n){e===i&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(o||n&&n.pinch)&&this.fire("zoom",n),this.fire("move",n)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return o.Util.cancelAnimFrame(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){this._targets={},this._targets[o.stamp(this._container)]=this;var i=e?"off":"on";o.DomEvent[i](this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&o.DomEvent[i](t,"resize",this._onResize,this),o.Browser.any3d&&this.options.transform3DLimit&&this[i]("moveend",this._onMoveEnd)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],s="mouseout"===e||"mouseover"===e,r=t.target||t.srcElement,a=!1;r;){if(i=this._targets[o.stamp(r)],i&&("click"===e||"preclick"===e)&&!t._simulated&&this._draggableMoved(i)){a=!0;break}if(i&&i.listens(e,!0)){if(s&&!o.DomEvent._isExternalTarget(r,t))break;if(n.push(i),s)break}if(r===this._container)break;r=r.parentNode}return n.length||a||s||!o.DomEvent._isExternalTarget(r,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e="keypress"===t.type&&13===t.keyCode?"click":t.type;"mousedown"===e&&o.DomUtil.preventOutline(t.target||t.srcElement),this._fireDOMEvent(t,e)}},_fireDOMEvent:function(t,e,i){if("click"===t.type){var n=o.Util.extend({},t);n.type="preclick",this._fireDOMEvent(n,n.type,i)}if(!t._stopped&&(i=(i||[]).concat(this._findEventTargets(t,e)),i.length)){var s=i[0];"contextmenu"===e&&s.listens(e,!0)&&o.DomEvent.preventDefault(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s instanceof o.Marker;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom(),n=o.Browser.any3d?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(e,Math.min(i,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return!((e&&e.animate)!==!0&&!this.getSize().contains(i))&&(this.panBy(i,e),!0)},_createAnimProxy:function(){var t=this._proxy=o.DomUtil.create("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(e){var i=o.DomUtil.TRANSFORM,n=t.style[i];o.DomUtil.setTransform(t,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),n===t.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var e=this.getCenter(),i=this.getZoom();o.DomUtil.setTransform(t,this.project(e,i),this.getZoomScale(i,1))},this)},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n);return!(i.animate!==!0&&!this.getSize().contains(s))&&(o.Util.requestAnimFrame(function(){this._moveStart(!0)._animateZoom(t,e,!0)},this),!0)},_animateZoom:function(t,e,i,n){i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),setTimeout(o.bind(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),o.Util.requestAnimFrame(function(){this._moveEnd(!0)},this))}}),o.map=function(t,e){return new o.Map(t,e)},o.Layer=o.Evented.extend({options:{pane:"overlayPane",nonBubblingEvents:[],attribution:null},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[o.stamp(t)]=this,this},removeInteractiveTarget:function(t){return delete this._map._targets[o.stamp(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var e=t.target;if(e.hasLayer(this)){if(this._map=e,this._zoomAnimated=e._zoomAnimated,this.getEvents){var i=this.getEvents();e.on(i,this),this.once("remove",function(){e.off(i,this)},this)}this.onAdd(e),this.getAttribution&&this._map.attributionControl&&this._map.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),e.fire("layeradd",{layer:this})}}}),o.Map.include({addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&o.stamp(t)in this._layers},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;ethis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===i&&this._layersMinZoom&&this.getZoom()100&&n<500||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,void e(t))}},o.DomEvent.addListener=o.DomEvent.on,o.DomEvent.removeListener=o.DomEvent.off,o.PosAnimation=o.Evented.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(t){var e=+new Date-this._startTime,i=1e3*this._duration;e1e-7;l++)e=r*Math.sin(h),e=Math.pow((1-e)/(1+e),r/2),u=Math.PI/2-2*Math.atan(a*e)-h,h+=u;return new o.LatLng(h*i,t.x*i/n)}},o.CRS.EPSG3395=o.extend({},o.CRS.Earth,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=.5/(Math.PI*o.Projection.Mercator.R);return new o.Transformation(t,.5,-t,.5)}()}),o.GridLayer=o.Layer.extend({options:{tileSize:256,opacity:1,updateWhenIdle:o.Browser.mobile,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:i,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){o.setOptions(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),o.DomUtil.remove(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=null},bringToFront:function(){return this._map&&(o.DomUtil.toFront(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(o.DomUtil.toBack(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o.Util.throttle(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return e.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof o.Point?t:new o.Point(t,t)},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var e,i=this.getPane().children,n=-t(-(1/0),1/0),o=0,s=i.length;othis.options.maxZoom||in&&this._retainParent(s,r,a,n))},_retainChildren:function(t,e,i,n){for(var s=2*t;s<2*t+2;s++)for(var r=2*e;r<2*e+2;r++){var a=new o.Point(s,r);a.z=i+1;var h=this._tileCoordsToKey(a),l=this._tiles[h];l&&l.active?l.retain=!0:(l&&l.loaded&&(l.retain=!0),i+1this.options.maxZoom||this.options.minZoom!==i&&s1)return void this._setView(t,s);for(var m=a.min.y;m<=a.max.y;m++)for(var p=a.min.x;p<=a.max.x;p++){var f=new o.Point(p,m);if(f.z=this._tileZoom,this._isValidTile(f)){var g=this._tiles[this._tileCoordsToKey(f)];g?g.current=!0:l.push(f)}}if(l.sort(function(t,e){return t.distanceTo(h)-e.distanceTo(h)}),0!==l.length){this._loading||(this._loading=!0,this.fire("loading"));var v=e.createDocumentFragment();for(p=0;pi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return o.latLngBounds(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),s=n.add(i),r=e.unproject(n,t.z),a=e.unproject(s,t.z);return this.options.noWrap||(r=e.wrapLatLng(r),a=e.wrapLatLng(a)),new o.LatLngBounds(r,a)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var e=t.split(":"),i=new o.Point(+e[0],+e[1]);return i.z=+e[2],i},_removeTile:function(t){var e=this._tiles[t];e&&(o.DomUtil.remove(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){o.DomUtil.addClass(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity<1&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.android&&!o.Browser.android23&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),o.bind(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&o.Util.requestAnimFrame(o.bind(this._tileReady,this,t,null,s)),o.DomUtil.setPosition(s,i),this._tiles[n]={el:s,coords:t,current:!0},e.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,e,i){if(this._map){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);i=this._tiles[n],i&&(i.loaded=+new Date,this._map._fadeAnimated?(o.DomUtil.setOpacity(i.el,0),o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(o.DomUtil.addClass(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),o.Browser.ielt9||!this._map._fadeAnimated?o.Util.requestAnimFrame(this._pruneTiles,this):setTimeout(o.bind(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new o.Point(this._wrapX?o.Util.wrapNum(t.x,this._wrapX):t.x,this._wrapY?o.Util.wrapNum(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new o.Bounds(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),o.gridLayer=function(t){return new o.GridLayer(t)},o.TileLayer=o.GridLayer.extend({options:{minZoom:0,maxZoom:18,maxNativeZoom:null,minNativeZoom:null,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,e){this._url=t,e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomReverse?(e.zoomOffset--,e.minZoom++):(e.zoomOffset++,e.maxZoom--),e.minZoom=Math.max(0,e.minZoom)),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),o.Browser.android||this.on("tileunload",this._onTileRemove)},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},createTile:function(t,i){var n=e.createElement("img");return o.DomEvent.on(n,"load",o.bind(this._tileOnLoad,this,i,n)),o.DomEvent.on(n,"error",o.bind(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:o.Browser.retina?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var i=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=i),e["-y"]=i}return o.Util.template(this._url,o.extend(e,this.options))},_tileOnLoad:function(t,e){o.Browser.ielt9?setTimeout(o.bind(t,this,null,e),0):t(null,e)},_tileOnError:function(t,e,i){var n=this.options.errorTileUrl;n&&(e.src=n),t(i,e)},getTileSize:function(){var t=this._map,e=o.GridLayer.prototype.getTileSize.call(this),i=this._tileZoom+this.options.zoomOffset,n=this.options.minNativeZoom,s=this.options.maxNativeZoom;return null!==n&&is?e.divideBy(t.getZoomScale(s,i)).round():e},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,e=this.options.maxZoom,i=this.options.zoomReverse,n=this.options.zoomOffset,o=this.options.minNativeZoom,s=this.options.maxNativeZoom;return i&&(t=e-t),t+=n,null!==o&&ts?s:t},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_abortLoading:function(){var t,e;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(e=this._tiles[t].el,e.onload=o.Util.falseFn,e.onerror=o.Util.falseFn,e.complete||(e.src=o.Util.emptyImageUrl,o.DomUtil.remove(e)))}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams);for(var n in e)n in this.options||(i[n]=e[n]);e=o.setOptions(this,e),i.width=i.height=e.tileSize*(e.detectRetina&&o.Browser.retina?2:1),this.wmsParams=i},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._tileCoordsToBounds(t),i=this._crs.project(e.getNorthWest()),n=this._crs.project(e.getSouthEast()),s=(this._wmsVersion>=1.3&&this._crs===o.CRS.EPSG4326?[n.y,i.x,i.y,n.x]:[i.x,n.y,n.x,i.y]).join(","),r=o.TileLayer.prototype.getTileUrl.call(this,t);return r+o.Util.getParamString(this.wmsParams,r,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+s},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.ImageOverlay=o.Layer.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(o.DomUtil.addClass(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){o.DomUtil.remove(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._image),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=t,this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t=this._image=o.DomUtil.create("img","leaflet-image-layer "+(this._zoomAnimated?"leaflet-zoom-animated":""));t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,t.onload=o.bind(this.fire,this,"load"),this.options.crossOrigin&&(t.crossOrigin=""),t.src=this._url,t.alt=this.options.alt},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),i=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;o.DomUtil.setTransform(this._image,i,e)},_reset:function(){var t=this._image,e=new o.Bounds(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),i=e.getSize();o.DomUtil.setPosition(t,e.min),t.style.width=i.x+"px",t.style.height=i.y+"px"},_updateOpacity:function(){ o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(i,e&&"IMG"===e.tagName?e:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i=this.options,n=i[e+"Size"];"number"==typeof n&&(n=[n,n]);var s=o.point(n),r=o.point("shadow"===e&&i.shadowAnchor||i.iconAnchor||s&&s.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),r&&(t.style.marginLeft=-r.x+"px",t.style.marginTop=-r.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return i=i||e.createElement("img"),i.src=t,i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return o.Icon.Default.imagePath||(o.Icon.Default.imagePath=this._detectIconPath()),(this.options.imagePath||o.Icon.Default.imagePath)+o.Icon.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=o.DomUtil.create("div","leaflet-default-icon-path",e.body),i=o.DomUtil.getStyle(t,"background-image")||o.DomUtil.getStyle(t,"backgroundImage");return e.body.removeChild(t),0===i.indexOf("url")?i.replace(/^url\([\"\']?/,"").replace(/marker-icon\.png[\"\']?\)$/,""):""}}),o.Marker=o.Layer.extend({options:{icon:new o.Icon.Default,interactive:!0,draggable:!1,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",nonBubblingEvents:["click","dblclick","mouseover","mouseout","contextmenu"]},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var e=this._latlng;return this._latlng=o.latLng(t),this.update(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1;i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),t.alt&&(i.alt=t.alt)),o.DomUtil.addClass(i,e),t.keyboard&&(i.tabIndex="0"),this._icon=i,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var s=t.icon.createShadow(this._shadow),r=!1;s!==this._shadow&&(this._removeShadow(),r=!0),s&&o.DomUtil.addClass(s,e),this._shadow=s,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),s&&r&&this.getPane("shadowPane").appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),o.DomUtil.remove(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&o.DomUtil.remove(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e)},_initInteraction:function(){if(this.options.interactive&&(o.DomUtil.addClass(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),o.Handler.MarkerDrag)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new o.Handler.MarkerDrag(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;o.DomUtil.setOpacity(this._icon,t),this._shadow&&o.DomUtil.setOpacity(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor||[0,0]},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor||[0,0]}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:e.createElement("div"),n=this.options;if(i.innerHTML=n.html!==!1?n.html:"",n.bgPos){var s=o.point(n.bgPos);i.style.backgroundPosition=-s.x+"px "+-s.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.DivOverlay=o.Layer.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,e){o.setOptions(this,t),this._source=e},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(o.DomUtil.setOpacity(this._container,0),this._removeTimeout=setTimeout(o.bind(o.DomUtil.remove,o.DomUtil,this._container),200)):o.DomUtil.remove(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._container),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._container),this},_updateContent:function(){if(this._content){var t=this._contentNode,e="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof e)t.innerHTML=e;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(e)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=o.point(this.options.offset),i=this._getAnchor();this._zoomAnimated?o.DomUtil.setPosition(this._container,t.add(i)):e=e.add(t).add(i);var n=this._containerBottom=-e.y,s=this._containerLeft=-Math.round(this._containerWidth/2)+e.x;this._container.style.bottom=n+"px",this._container.style.left=s+"px"}},_getAnchor:function(){return[0,0]}}),o.Popup=o.DivOverlay.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof o.Path||this._source.on("preclick",o.DomEvent.stopPropagation))},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof o.Path||this._source.off("preclick",o.DomEvent.stopPropagation))},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return("closeOnClick"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",e=this._container=o.DomUtil.create("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated");if(this.options.closeButton){var i=this._closeButton=o.DomUtil.create("a",t+"-close-button",e);i.href="#close",i.innerHTML="×",o.DomEvent.on(i,"click",this._onCloseButtonClick,this)}var n=this._wrapper=o.DomUtil.create("div",t+"-content-wrapper",e);this._contentNode=o.DomUtil.create("div",t+"-content",n),o.DomEvent.disableClickPropagation(n).disableScrollPropagation(this._contentNode).on(n,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",t+"-tip-container",e),this._tip=o.DomUtil.create("div",t+"-tip",this._tipContainer)},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,r="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,r)):o.DomUtil.removeClass(t,r),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),i=this._getAnchor();o.DomUtil.setPosition(this._container,e.add(i))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,e=parseInt(o.DomUtil.getStyle(this._container,"marginBottom"),10)||0,i=this._container.offsetHeight+e,n=this._containerWidth,s=new o.Point(this._containerLeft,-i-this._containerBottom);s._add(o.DomUtil.getPosition(this._container));var r=t.layerPointToContainerPoint(s),a=o.point(this.options.autoPanPadding),h=o.point(this.options.autoPanPaddingTopLeft||a),l=o.point(this.options.autoPanPaddingBottomRight||a),u=t.getSize(),c=0,d=0;r.x+n+l.x>u.x&&(c=r.x+n-u.x+l.x),r.x-c-h.x<0&&(c=r.x-h.x),r.y+i+l.y>u.y&&(d=r.y+i-u.y+l.y),r.y-d-h.y<0&&(d=r.y-h.y),(c||d)&&t.fire("autopanstart").panBy([c,d])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)},_getAnchor:function(){return o.point(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Map.include({openPopup:function(t,e,i){return t instanceof o.Popup||(t=new o.Popup(i).setContent(t)),e&&t.setLatLng(e),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),o.Layer.include({bindPopup:function(t,e){return t instanceof o.Popup?(o.setOptions(t,e),this._popup=t,t._source=this):(this._popup&&!e||(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,e){if(t instanceof o.Layer||(e=t,t=this),t instanceof o.FeatureGroup)for(var i in this._layers){t=this._layers[i];break}return e||(e=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,e)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e=t.layer||t.target;if(this._popup&&this._map)return o.DomEvent.stop(t),e instanceof o.Path?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===e?this.closePopup():this.openPopup(e,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.Tooltip=o.DivOverlay.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return o.Browser.touch&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip",e=t+" "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=o.DomUtil.create("div",e)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e=this._map,i=this._container,n=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=i.offsetWidth,h=i.offsetHeight,l=o.point(this.options.offset),u=this._getAnchor();"top"===r?t=t.add(o.point(-a/2+l.x,-h+l.y+u.y,!0)):"bottom"===r?t=t.subtract(o.point(a/2-l.x,-l.y,!0)):"center"===r?t=t.subtract(o.point(a/2+l.x,h/2-u.y+l.y,!0)):"right"===r||"auto"===r&&s.xh&&(s=r,h=a);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;ne&&(i.push(t[n]),o=n);return oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,r=e.x,a=e.y,h=i.x-r,l=i.y-a,u=h*h+l*l;return u>0&&(s=((t.x-r)*h+(t.y-a)*l)/u,s>1?(r=i.x,a=i.y):s>0&&(r+=h*s,a+=l*s)),h=t.x-r,l=t.y-a,n?h*h+l*l:new o.Point(r,a)}},o.Polyline=o.Path.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,e){o.setOptions(this,e),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var e,i,n=1/0,s=null,r=o.LineUtil._sqClosestPointOnSegment,a=0,h=this._parts.length;ae)return r=(n-e)/i,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,e){return e=e||this._defaultShape(),t=o.latLng(t),e.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new o.LatLngBounds,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return o.Polyline._flat(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var e=[],i=o.Polyline._flat(t),n=0,s=t.length;n=2&&e[0]instanceof o.LatLng&&e[0].equals(e[i-1])&&e.pop(),e},_setLatLngs:function(t){o.Polyline.prototype._setLatLngs.call(this,t),o.Polyline._flat(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return o.Polyline._flat(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,e=this.options.weight,i=new o.Point(e,e);if(t=new o.Bounds(t.min.subtract(i),t.max.add(i)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,s=0,r=this._rings.length;s';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}(),o.SVG.include(o.Browser.vml?{_initContainer:function(){this._container=o.DomUtil.create("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(o.Renderer.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=o.SVG.create("shape");o.DomUtil.addClass(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=o.SVG.create("path"),e.appendChild(t._path),this._updateStyle(t)},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;o.DomUtil.remove(e),t.removeInteractiveTarget(e)},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,s=t._container;s.stroked=!!n.stroke,s.filled=!!n.fill,n.stroke?(e||(e=t._stroke=o.SVG.create("stroke")),s.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=o.Util.isArray(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(s.removeChild(e),t._stroke=null),n.fill?(i||(i=t._fill=o.SVG.create("fill")),s.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(s.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){o.DomUtil.toFront(t._container)},_bringToBack:function(t){o.DomUtil.toBack(t._container)}}:{}),o.Browser.vml&&(o.SVG.create=function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()),o.Canvas=o.Renderer.extend({onAdd:function(){o.Renderer.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=e.createElement("canvas");o.DomEvent.on(t,"mousemove",o.Util.throttle(this._onMouseMove,32,this),this).on(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this).on(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_updatePaths:function(){var t;this._redrawBounds=null;for(var e in this._layers)t=this._layers[e],t._update();this._redraw()},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},o.Renderer.prototype._update.call(this);var t=this._bounds,e=this._container,i=t.getSize(),n=o.Browser.retina?2:1;o.DomUtil.setPosition(e,t.min),e.width=n*i.x,e.height=n*i.y,e.style.width=i.x+"px",e.style.height=i.y+"px",o.Browser.retina&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_initPath:function(t){this._updateDashArray(t),this._layers[o.stamp(t)]=t;var e=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=e),this._drawLast=e,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var e=t._order,i=e.next,n=e.prev;i?i.prev=n:this._drawLast=n,n?n.next=i:this._drawFirst=i,delete t._order,delete this._layers[o.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var e,i=t.options.dashArray.split(","),n=[];for(e=0;et.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u||o.Polyline.prototype._containsPoint.call(this,t,!0)},o.CircleMarker.prototype._containsPoint=function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()},o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;e1)return void(this._moved=!0);var n=i.touches&&1===i.touches.length?i.touches[0]:i,s=new o.Point(n.clientX,n.clientY),r=s.subtract(this._startPoint);(r.x||r.y)&&(Math.abs(r.x)+Math.abs(r.y)50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,e){return t-(t-e)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),e=this._offsetLimit;t.xe.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,r=Math.abs(o+i)0?s:-s))-e;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(e+r):t.setZoomAround(this._lastMousePos,e+r))}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend:o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener:function(t,e,i){function n(t){var e;if(e=o.Browser.pointer?o.DomEvent._pointersCount:t.touches.length,!(e>1)){var i=Date.now(),n=i-(r||i);a=t.touches?t.touches[0]:t,h=n>0&&n<=l,r=i}}function s(){if(h&&!a.cancelBubble){if(o.Browser.pointer){var t,i,n={};for(i in a)t=a[i],n[i]=t&&t.bind?t.bind(a):t;a=n}a.type="dblclick",e(a),r=null}}var r,a,h=!1,l=250,u="_leaflet_",c=this._touchstart,d=this._touchend;return t[u+c+i]=n,t[u+d+i]=s,t[u+"dblclick"+i]=e,t.addEventListener(c,n,!1),t.addEventListener(d,s,!1),o.Browser.edge||t.addEventListener("dblclick",e,!1),this},removeDoubleTapListener:function(t,e){var i="_leaflet_",n=t[i+this._touchstart+e],s=t[i+this._touchend+e],r=t[i+"dblclick"+e];return t.removeEventListener(this._touchstart,n,!1),t.removeEventListener(this._touchend,s,!1),o.Browser.edge||t.removeEventListener("dblclick",r,!1),this}}),o.extend(o.DomEvent,{POINTER_DOWN:o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE:o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP:o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL:o.Browser.msPointer?"MSPointerCancel":"pointercancel",TAG_WHITE_LIST:["INPUT","SELECT","OPTION"],_pointers:{},_pointersCount:0,addPointerListener:function(t,e,i,n){return"touchstart"===e?this._addPointerStart(t,i,n):"touchmove"===e?this._addPointerMove(t,i,n):"touchend"===e&&this._addPointerEnd(t,i,n),this},removePointerListener:function(t,e,i){var n=t["_leaflet_"+e+i];return"touchstart"===e?t.removeEventListener(this.POINTER_DOWN,n,!1):"touchmove"===e?t.removeEventListener(this.POINTER_MOVE,n,!1):"touchend"===e&&(t.removeEventListener(this.POINTER_UP,n,!1),t.removeEventListener(this.POINTER_CANCEL,n,!1)),this},_addPointerStart:function(t,i,n){var s=o.bind(function(t){if("mouse"!==t.pointerType&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(this.TAG_WHITE_LIST.indexOf(t.target.tagName)<0))return;o.DomEvent.preventDefault(t)}this._handlePointer(t,i)},this);if(t["_leaflet_touchstart"+n]=s,t.addEventListener(this.POINTER_DOWN,s,!1),!this._pointerDocListener){var r=o.bind(this._globalPointerUp,this);e.documentElement.addEventListener(this.POINTER_DOWN,o.bind(this._globalPointerDown,this),!0),e.documentElement.addEventListener(this.POINTER_MOVE,o.bind(this._globalPointerMove,this),!0),e.documentElement.addEventListener(this.POINTER_UP,r,!0),e.documentElement.addEventListener(this.POINTER_CANCEL,r,!0),this._pointerDocListener=!0}},_globalPointerDown:function(t){this._pointers[t.pointerId]=t,this._pointersCount++},_globalPointerMove:function(t){this._pointers[t.pointerId]&&(this._pointers[t.pointerId]=t)},_globalPointerUp:function(t){delete this._pointers[t.pointerId],this._pointersCount--},_handlePointer:function(t,e){t.touches=[];for(var i in this._pointers)t.touches.push(this._pointers[i]);t.changedTouches=[t],e(t)},_addPointerMove:function(t,e,i){var n=o.bind(function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&this._handlePointer(t,e)},this);t["_leaflet_touchmove"+i]=n,t.addEventListener(this.POINTER_MOVE,n,!1)},_addPointerEnd:function(t,e,i){var n=o.bind(function(t){this._handlePointer(t,e)},this);t["_leaflet_touchend"+i]=n,t.addEventListener(this.POINTER_UP,n,!1),t.addEventListener(this.POINTER_CANCEL,n,!1)}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits:!0}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomUtil.addClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){o.DomUtil.removeClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToContainerPoint(t.touches[0]),s=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(n.add(s)._divideBy(2))),this._startDist=n.distanceTo(s),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),s=i.distanceTo(n)/this._startDist;if(this._zoom=e.getScaleZoom(s,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoome.getMaxZoom()&&s>1)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=i._add(n)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=e.unproject(e.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(e._moveStart(!0),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest);var a=o.bind(e._move,e,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=o.Util.requestAnimFrame(a,this,!0),o.DomEvent.preventDefault(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),o.DomEvent.on(e,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY),this._simulateEvent("mousemove",e)},_simulateEvent:function(i,n){var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_resetState:function(){ this._moved=!1},_onMouseDown:function(t){return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._resetState(),o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startPoint=this._map.mouseEventToContainerPoint(t),void o.DomEvent.on(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=o.DomUtil.create("div","leaflet-zoom-box",this._container),o.DomUtil.addClass(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var e=new o.Bounds(this._point,this._startPoint),i=e.getSize();o.DomUtil.setPosition(this._box,e.min),this._box.style.width=i.x+"px",this._box.style.height=i.y+"px"},_finish:function(){this._moved&&(o.DomUtil.remove(this._box),o.DomUtil.removeClass(this._container,"leaflet-crosshair")),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){setTimeout(o.bind(this._resetState,this),0);var e=new o.LatLngBounds(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(e).fire("boxzoomend",{boxZoomBounds:e})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanDelta:80}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),o.DomEvent.on(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),o.DomEvent.off(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;e0&&t.screenY>0&&this._map.getContainer().focus()}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,s){var r=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",r,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){o.DomUtil.remove(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"-",zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,s){var r=o.DomUtil.create("a",i,n);return r.innerHTML=t,r.href="#",r.title=e,r.setAttribute("role","button"),r.setAttribute("aria-label",e),o.DomEvent.on(r,"mousedown dblclick",o.DomEvent.stopPropagation).on(r,"click",o.DomEvent.stop).on(r,"click",s,this).on(r,"click",this._refocusOnMap,this),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMinZoom())&&o.DomUtil.addClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMaxZoom())&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'Leaflet'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent&&o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(new o.Control.Attribution).addTo(this)}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e,i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,i=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(i)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t),i=e<1e3?e+" m":e/1e3+" km";this._updateScale(this._mScale,i,e/t)},_updateImperial:function(t){var e,i,n,o=3.2808399*t;o>5280?(e=o/5280,i=this._getRoundNum(e),this._updateScale(this._iScale,i+" mi",i/e)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,e,i){t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,e,i,n){return i1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=e&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var e=this._getLayer(o.stamp(t.target)),i=e.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;i&&this._map.fire(i,e)},_createRadioElement:function(t,i){var n='",o=e.createElement("div");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var r=e.createElement("span");r.innerHTML=" "+t.name;var a=e.createElement("div");n.appendChild(a),a.appendChild(i),a.appendChild(r);var h=t.overlay?this._overlaysList:this._baseLayersList;return h.appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName("input"),o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],e=this._getLayer(t.layerId).layer,i=this._map.hasLayer(e),t.checked&&!i?o.push(e):!t.checked&&i&&s.push(e);for(r=0;r=0;s--)t=n[s],e=this._getLayer(t.layerId).layer,t.disabled=e.options.minZoom!==i&&oe.options.maxZoom},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)}}(window,document); /** * 经纬度转墨卡托 */ L.Util.transformMercator =function(lonLat){ var mercator = {}; var x = lonLat.x * 20037508.34 / 180; var y = Math.log(Math.tan((90 + lonLat.y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.x = x; mercator.y = y; return mercator; }; /** * 墨卡托转经纬度 */ L.Util.transformMercator =function(lonLat){ var mercator = {}; var x = lonLat.x * 20037508.34 / 180; var y = Math.log(Math.tan((90 + lonLat.y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.x = x; mercator.y = y; return mercator; }; /** * 航向量算 */ L.Util.getAngleByLatLng = function(startLong,startLat,endLong,endLat){ startLong = parseFloat(startLong); startLat = parseFloat(startLat); endLong = parseFloat(endLong); endLat = parseFloat(endLat); var stsrtP = { x:startLong, y:startLat }; var endP = {}; endP.x=endLong; endP.y=endLat; var startPX_LatLongCoords = startLong; var startPY_LatLongCoords = startLat; var endPX_LatLongCoords = endLong; var endPY_LatLongCoords = endLat; var zhongjianX; var zhongjianY; zhongjianX = startPX_LatLongCoords > endPX_LatLongCoords ? startPX_LatLongCoords : endPX_LatLongCoords; zhongjianY = startPX_LatLongCoords > endPX_LatLongCoords ? startPY_LatLongCoords : endPY_LatLongCoords; var thirdX = zhongjianX; var thirdY = zhongjianY + 0.001; var prjParaPointC = {}; prjParaPointC.x=thirdX; prjParaPointC.y=thirdY; stsrtP = L.Util.transformMercator(stsrtP); endP = L.Util.transformMercator(endP); var startPX = stsrtP.x; var startPY = stsrtP.y; var endPX = endP.x; var endPY = endP.y; prjParaPointC = L.Util.transformMercator(prjParaPointC); var objChangeCx = prjParaPointC.x; var objChangeCy = prjParaPointC.y; //有三点计算角度,使用向量方法 var mx, my, ax, ay, bx, by, ma_x, ma_y, mb_x, mb_y; mx = startPX_LatLongCoords > endPX_LatLongCoords ? startPX : endPX; my = startPX_LatLongCoords > endPX_LatLongCoords ? startPY : endPY; if (mx == startPX && my == startPY) { ax = endPX; ay = endPY; } else { ax = startPX; ay = startPY; } bx = objChangeCx; by = objChangeCy; ma_x = ax - mx; ma_y = ay - my; mb_x = bx - mx; mb_y = by - my; var v1 = (ma_x * mb_x) + (ma_y * mb_y); var ma_val = Math.sqrt(ma_x * ma_x + ma_y * ma_y); var mb_val = Math.sqrt(mb_x * mb_x + mb_y * mb_y); var cosM = v1 / (ma_val * mb_val); var angleAMB = Math.acos(cosM) * 180 / Math.PI; var xiangxian = 0; // 定义象限变量 var lastAngle = 0; if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) == 0) { lastAngle = 0; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) == 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { lastAngle = 90; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) == 0) { lastAngle = 180; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) == 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { lastAngle = 270; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { xiangxian = 1; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { xiangxian = 2; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { xiangxian = 3; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { xiangxian = 4; }; switch (xiangxian) { case 1: lastAngle = 180 - angleAMB; break; case 2: lastAngle = 360 - angleAMB; break; case 3: lastAngle = 360 - angleAMB; break; case 4: lastAngle = 180 - angleAMB; break; default: //alert("none"); } return parseInt(Math.round(lastAngle)); } /** * 判断是否是合法的经纬度 * @param {[type]} lat [纬度] * @param {[type]} lng [经度] * @return {[type]} [布尔值] */ L.Util.verifyLatLng = function(lat, lng) { if (parseFloat(lat) >= -90 && parseFloat(lat) <= 90 && parseFloat(lng) >= -180 && parseFloat(lng) <= 180) { return true; } else { return false; } }; /** * 地球坐标纠正 * @param {[type]} latlng [description] * @return {[type]} [description] */ L.Util.formatEarthLatLng = function(latlng){ var lat = latlng.hasOwnProperty('lat') ? latlng.lat : latlng[0]; var lng = latlng.hasOwnProperty('lng') ? latlng.lng : latlng[1]; lng = lng%360; if(lng>180){ lng = (lng%180)-180; }else if(lng<-180){ lng = 180+(lng%180); } return new L.LatLng(lat,lng); }; /** * 十进制经纬度转度分秒 * @param {[type]} latlng [对象或数组] * @return {[type]} [度分秒] */ L.Util.formatHMS = function(latlng) { var lat = latlng.hasOwnProperty('lat') ? latlng.lat : latlng[0]; var lng = latlng.hasOwnProperty('lng') ? latlng.lng : latlng[1]; lng = lng%360; if(lng>180){ lng = (lng%180)-180; }else if(lng<-180){ lng = 180+(lng%180); } function setHMS(f) { f = parseInt(f * 3600); var h = parseInt(f / 3600); var m = parseInt((f - h * 3600) / 60); var s = parseInt((f - h * 3600 - m * 60)); if (m.toString().length == 1) { m = '0' + m.toString(); } if (s.toString().length == 1) { s = '0' + s.toString(); } return h + '\u00b0' + m + '\u2032' + s + '\u2033'; } var nLat = ''; var nLng = ''; if (lat < 0) { nLat = setHMS(lat * -1)+'S'; } else { nLat = setHMS(lat)+'N'; } if (lng < 0) { nLng = setHMS(lng * -1)+'W'; } else { nLng = setHMS(lng)+'E'; } return { lat: nLat, lng: nLng }; }; /** * 度分秒转经纬度 * @param {[type]} p [方位] * @param {[type]} d [度] * @param {[type]} f [分] * @param {[type]} m [秒] */ L.Util.HMStoLatLng = function(p, d, f, m) { var dfm = parseFloat(d) + parseFloat(f) / 60 + parseFloat(m) / 3600; if (p.toLowerCase() === 'w' || p.toLowerCase() === 's') { dfm = -1 * dfm; } return dfm; }; /** * 获取弧线的节点坐标数组 * @type {Function} * @param points * @returns {Array} * @private */ L.Util.getCurvePoints = function(points){ var getCurve = function(start,finish,segments){ var startlat = start.lat; var startlon = start.lng; var finishlat = finish.lat; var finishlon = finish.lng; var segments = segments; var curveAry = []; var lat1 = startlat * (Math.PI / 180); var lon1 = startlon * (Math.PI / 180); var lat2 = finishlat * (Math.PI / 180); var lon2 = finishlon * (Math.PI / 180); var d = 2 * Math.asin(Math.sqrt(Math.pow((Math.sin((lat1-lat2)/2)),2)+Math.cos(lat1)*Math.cos(lat2)*Math.pow((Math.sin((lon1-lon2)/2)),2))); for(var n= 0; n 0){ curvePoints = curvePoints.concat(p); } } } return curvePoints; }, /** * 画大圆标绘坐标转换 */ L.Util.circleDrawLatlng = function(poly){ var distance = []; var lineDistance; if(poly._latlngs.length ===1){ poly._latlngs = poly._latlngs[0]; for(i=0,l=poly._latlngs.length;i= minZoom){ this.options.minZoom = minZoom; this.options.maxZoom = maxZoom; this.fire('zoomlevelschange'); } } }); L.Control.include({ addTo: function (map) { this.remove(); this._map = map; var container = this._container = this.onAdd(map), pos = this.getPosition(), corner = map._controlCorners[pos]; L.DomUtil.addClass(container, 'leaflet-control'); if (pos.indexOf('bottom') !== -1) { corner.insertBefore(container, corner.firstChild); } else { corner.appendChild(container); } if(this._callBack){ this._callBack(); } return this; } }); L.Map.include({ _initControlPos: function () { var corners = this._controlCorners = {}, l = 'leaflet-', container = this._controlContainer = L.DomUtil.create('div', l + 'control-container', this._container); function createCorner(vSide, hSide) { var className = l + vSide + ' ' + l + hSide; corners[vSide + hSide] = L.DomUtil.create('div', className, container); } createCorner('top', 'left'); createCorner('top', 'center'); createCorner('top', 'right'); createCorner('bottom', 'left'); createCorner('bottom', 'center'); createCorner('bottom', 'right'); } }); /*! * Copyright (c) 2012, Smartrak, David Leaver * Leaflet.utfgrid is an open-source JavaScript library that provides utfgrid interaction on leaflet powered maps. * https://github.com/danzel/Leaflet.utfgrid * * @license MIT */ (function (window, undefined) { L.Util.utfgridAjax = function (url, success, error) { // the following is from JavaScript: The Definitive Guide // and https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest_in_IE6 if (window.XMLHttpRequest === undefined) { window.XMLHttpRequest = function () { /*global ActiveXObject:true */ try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { throw new Error("XMLHttpRequest is not supported"); } }; } var response, request = new XMLHttpRequest(); request.open("GET", url); request.onreadystatechange = function () { /*jshint evil: true */ if (request.readyState === 4) { if (request.status === 200) { if (window.JSON) { response = JSON.parse(request.responseText); } else { response = eval("(" + request.responseText + ")"); } success(response); } else if (request.status !== 0 && error !== undefined) { error(request.status); } } }; request.ontimeout = function () { error('timeout'); }; request.send(); return request; }; L.UtfGrid = (L.Layer || L.Class).extend({ includes: L.Mixin.Events, options: { subdomains: map23DConfig.tileSubdomains||'', minZoom: 0, maxZoom: 18, tileSize: 256, resolution: 4, useJsonP: true, pointerCursor: true, maxRequests: 4, requestTimeout: 60000 }, //The thing the mouse is currently on _mouseOn: null, initialize: function (url, options) { L.Util.setOptions(this, options); // The requests this._requests = {}; this._request_queue = []; this._requests_in_process = []; this._url = url; this._cache = {}; //Find a unique id in window we can use for our callbacks //Required for jsonP var i = 0; while (window['lu' + i]) { i++; } this._windowKey = 'lu' + i; window[this._windowKey] = {}; var subdomains = this.options.subdomains; if (typeof this.options.subdomains === 'string') { this.options.subdomains = subdomains.split(''); } }, onAdd: function (map) { this._map = map; this._container = this._map._container; this._update(); var zoom = Math.round(this._map.getZoom()); if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { return; } map.on('click', this._click, this); map.on('mousemove', this._move, this); map.on('moveend', this._update, this); }, onRemove: function () { var map = this._map; map.off('click', this._click, this); map.off('mousemove', this._move, this); map.off('moveend', this._update, this); if (this.options.pointerCursor) { this._container.style.cursor = ''; } }, setUrl: function (url, noRedraw) { this._url = url; if (!noRedraw) { this.redraw(); } return this; }, redraw: function () { // Clear cache to force all tiles to reload this._request_queue = []; for (var req_key in this._requests) { if (this._requests.hasOwnProperty(req_key)) { this._abort_request(req_key); } } this._cache = {}; this._update(); }, _click: function (e) { this.fire('click', this._objectForEvent(e)); }, _move: function (e) { var on = this._objectForEvent(e); if (on.data !== this._mouseOn) { if (this._mouseOn) { this.fire('mouseout', { latlng: e.latlng, data: this._mouseOn }); if (this.options.pointerCursor) { this._container.style.cursor = ''; } } if (on.data) { this.fire('mouseover', on); if (this.options.pointerCursor) { this._container.style.cursor = 'pointer'; } } this._mouseOn = on.data; } else if (on.data) { this.fire('mousemove', on); } }, _objectForEvent: function (e) { var map = this._map, point = map.project(e.latlng), tileSize = this.options.tileSize, resolution = this.options.resolution, x = Math.floor(point.x / tileSize), y = Math.floor(point.y / tileSize), gridX = Math.floor((point.x - (x * tileSize)) / resolution), gridY = Math.floor((point.y - (y * tileSize)) / resolution), max = map.options.crs.scale(map.getZoom()) / tileSize; x = (x + max) % max; y = (y + max) % max; var data = this._cache[map.getZoom() + '_' + x + '_' + y]; var result = null; if (data && data.grid) { var idx = this._utfDecode(data.grid[gridY].charCodeAt(gridX)), key = data.keys[idx]; if (data.data.hasOwnProperty(key)) { result = data.data[key]; } } return L.extend({ latlng: e.latlng, data: result }, e); }, //Load up all required json grid files //TODO: Load from center etc _update: function () { var bounds = this._map.getPixelBounds(), zoom = Math.round(this._map.getZoom()), tileSize = this.options.tileSize; if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { return; } var nwTilePoint = new L.Point( Math.floor(bounds.min.x / tileSize), Math.floor(bounds.min.y / tileSize)), seTilePoint = new L.Point( Math.floor(bounds.max.x / tileSize), Math.floor(bounds.max.y / tileSize)), max = this._map.options.crs.scale(zoom) / tileSize; //Load all required ones var visible_tiles = []; for (var x = nwTilePoint.x; x <= seTilePoint.x; x++) { for (var y = nwTilePoint.y; y <= seTilePoint.y; y++) { var xw = (x + max) % max, yw = (y + max) % max; var key = zoom + '_' + xw + '_' + yw; visible_tiles.push(key); if (!this._cache.hasOwnProperty(key)) { this._cache[key] = null; if (this.options.useJsonP) { this._loadTileP(zoom, xw, yw); } else { this._loadTile(zoom, xw, yw); } } } } // If we still have requests for tiles that have now gone out of sight, attempt to abort them. for (var req_key in this._requests) { if (visible_tiles.indexOf(req_key) < 0) { this._abort_request(req_key); } } }, _loadTileP: function (zoom, x, y) { var head = document.getElementsByTagName('head')[0], key = zoom + '_' + x + '_' + y, functionName = 'lu_' + key, wk = this._windowKey, self = this; var url = L.Util.template(this._url, L.Util.extend({ s: L.TileLayer.prototype._getSubdomain.call(this, { x: x, y: y }), z: zoom, x: x, y: y, cb: wk + '.' + functionName }, this.options)); var script = document.createElement('script'); script.setAttribute("type", "text/javascript"); script.setAttribute("src", url); window[wk][functionName] = function (data) { try { self._cache[key] = data; delete window[wk][functionName]; head.removeChild(script); self._finish_request(key); } catch (e) { } }; this._queue_request(key, url, function () { head.appendChild(script); return { abort: function () { head.removeChild(script); } }; }); }, _loadTile: function (zoom, x, y) { var url = L.Util.template(this._url, L.Util.extend({ s: L.TileLayer.prototype._getSubdomain.call(this, { x: x, y: y }), z: zoom, x: x, y: y }, this.options)); var key = zoom + '_' + x + '_' + y; this._queue_request(key, url, this._ajaxRequestFactory(key, url)); }, _ajaxRequestFactory: function (key, url) { var successCallback = this._successCallbackFactory(key); var errorCallback = this._errorCallbackFactory(url); return function () { var request = L.Util.utfgridAjax(url, successCallback, errorCallback); request.timeout = this.options.requestTimeout; return request; }.bind(this); }, _successCallbackFactory: function (key) { return function (data) { this._cache[key] = data; this._finish_request(key); }.bind(this); }, _errorCallbackFactory: function (tileurl) { return function (statuscode) { this.fire('tileerror', { url: tileurl, code: statuscode }); }.bind(this); }, _queue_request: function (key, url, callback) { this._requests[key] = { callback: callback, timeout: null, handler: null, url: url }; this._request_queue.push(key); this._process_queued_requests(); }, _finish_request: function (key) { // Remove from requests in process var pos = this._requests_in_process.indexOf(key); if (pos >= 0) { this._requests_in_process.splice(pos, 1); } // Remove from request queue pos = this._request_queue.indexOf(key); if (pos >= 0) { this._request_queue.splice(pos, 1); } // Remove the request entry if (this._requests[key]) { if (this._requests[key].timeout) { window.clearTimeout(this._requests[key].timeout); } delete this._requests[key]; } // Recurse this._process_queued_requests(); // Fire 'load' event if all tiles have been loaded if (this._requests_in_process.length === 0) { this.fire('load'); } }, _abort_request: function (key) { // Abort the request if possible if (this._requests[key] && this._requests[key].handler) { if (typeof this._requests[key].handler.abort === 'function') { this._requests[key].handler.abort(); } } // Ensure we don't keep a false copy of the data in the cache if (this._cache[key] === null) { delete this._cache[key]; } // And remove the request this._finish_request(key); }, _process_queued_requests: function () { while (this._request_queue.length > 0 && (this.options.maxRequests === 0 || this._requests_in_process.length < this.options.maxRequests)) { this._process_request(this._request_queue.pop()); } }, _process_request: function (key) { this._requests_in_process.push(key); // The callback might call _finish_request, so don't assume _requests[key] still exists. var handler = this._requests[key].callback(); if (this._requests[key]) { this._requests[key].handler = handler; if (handler.timeout === undefined) { var timeoutCallback = this._timeoutCallbackFactory(key); this._requests[key].timeout = window.setTimeout(timeoutCallback, this.options.requestTimeout); } } }, _timeoutCallbackFactory: function (key) { var tileurl = this._requests[key].url; return function () { this.fire('tileerror', { url: tileurl, code: 'timeout' }); this._abort_request(key); }.bind(this); }, _utfDecode: function (c) { if (c >= 93) { c--; } if (c >= 35) { c--; } return c - 32; } }); L.utfGrid = function (url, options) { return new L.UtfGrid(url, options); }; }(window)); /* Leaflet.label, a plugin that adds labels to markers and vectors for Leaflet powered maps. (c) 2012-2013, Jacob Toye, Smartrak https://github.com/Leaflet/Leaflet.label http://leafletjs.com https://github.com/jacobtoye */ (function () { //var L = window.L; /* * Leaflet.label assumes that you have already included the Leaflet library. */ //L.labelVersion = '0.2.2-dev'; L.Label = (L.Layer ? L.Layer : L.Class).extend({ includes: L.Mixin.Events, options: { className: '', clickable: false, direction: 'auto', noHide: false, offset: [13, -16], // 6 (width of the label triangle) + 6 (padding) opacity: 1, zoomAnimation: true }, initialize: function (options, source) { L.setOptions(this, options); this._source = source; this._animated = L.Browser.any3d && this.options.zoomAnimation; this._isOpen = false; }, onAdd: function (map) { this._map = map; this._pane = this.options.pane ? map._panes[this.options.pane] : this._source instanceof L.Marker ? map._panes.markerPane : map._panes.popupPane; if (!this._container) { this._initLayout(); } this._pane.appendChild(this._container); this._initInteraction(); this._update(); this.setOpacity(this.options.opacity); map .on('moveend', this._onMoveEnd, this) .on('viewreset', this._onViewReset, this); if (this._animated) { map.on('zoomanim', this._zoomAnimation, this); } if (L.Browser.touch && !this.options.noHide) { L.DomEvent.on(this._container, 'click', this.close, this); map.on('click', this.close, this); } }, onRemove: function (map) { this._pane.removeChild(this._container); map.off({ zoomanim: this._zoomAnimation, moveend: this._onMoveEnd, viewreset: this._onViewReset }, this); this._removeInteraction(); this._map = null; }, setLatLng: function (latlng) { this._latlng = L.latLng(latlng); if (this._map) { this._updatePosition(); } return this; }, setContent: function (content) { // Backup previous content and store new content this._previousContent = this._content; this._content = content; this._updateContent(); return this; }, close: function () { var map = this._map; if (map) { if (L.Browser.touch && !this.options.noHide) { L.DomEvent.off(this._container, 'click', this.close); map.off('click', this.close, this); } map.removeLayer(this); } }, updateZIndex: function (zIndex) { this._zIndex = zIndex; if (this._container && this._zIndex) { this._container.style.zIndex = zIndex; } }, setOpacity: function (opacity) { this.options.opacity = opacity; if (this._container) { L.DomUtil.setOpacity(this._container, opacity); } }, _initLayout: function () { this._container = L.DomUtil.create('div', 'leaflet-label ' + this.options.className + ' leaflet-zoom-animated'); this.updateZIndex(this._zIndex); }, _update: function () { if (!this._map) { return; } this._container.style.visibility = 'hidden'; this._updateContent(); this._updatePosition(); this._container.style.visibility = ''; }, _updateContent: function () { if (!this._content || !this._map || this._prevContent === this._content) { return; } if (typeof this._content === 'string') { this._container.innerHTML = this._content; this._prevContent = this._content; this._labelWidth = this._container.offsetWidth; }else { this._container.appendChild(this._content); this._prevContent = this._content; this._labelWidth = this._container.offsetWidth; } //==S== 修改标记 L.DomUtil.create('div','leaflet-label-tips',this._container); //==E== 修改标记 }, _updatePosition: function () { var pos = this._map.latLngToLayerPoint(this._latlng); this._setPosition(pos); }, _setPosition: function (pos) { var map = this._map, container = this._container, centerPoint = map.latLngToContainerPoint(map.getCenter()), labelPoint = map.layerPointToContainerPoint(pos), direction = this.options.direction, labelWidth = this._labelWidth, offset = L.point(this.options.offset); // position to the right (right or auto & needs to) if (direction === 'right' || direction === 'auto' && labelPoint.x < centerPoint.x) { L.DomUtil.addClass(container, 'leaflet-label-right'); L.DomUtil.removeClass(container, 'leaflet-label-left'); pos = pos.add(offset); } else { // position to the left L.DomUtil.addClass(container, 'leaflet-label-left'); L.DomUtil.removeClass(container, 'leaflet-label-right'); pos = pos.add(L.point(-offset.x - labelWidth, offset.y)); } L.DomUtil.setPosition(container, pos); }, _zoomAnimation: function (opt) { var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round(); this._setPosition(pos); }, _onMoveEnd: function () { if (!this._animated || this.options.direction === 'auto') { this._updatePosition(); } }, _onViewReset: function (e) { /* if map resets hard, we must update the label */ if (e && e.hard) { this._update(); } }, _initInteraction: function () { if (!this.options.clickable) { return; } var container = this._container, events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; L.DomUtil.addClass(container, 'leaflet-clickable'); L.DomEvent.on(container, 'click', this._onMouseClick, this); for (var i = 0; i < events.length; i++) { L.DomEvent.on(container, events[i], this._fireMouseEvent, this); } }, _removeInteraction: function () { if (!this.options.clickable) { return; } var container = this._container, events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; L.DomUtil.removeClass(container, 'leaflet-clickable'); L.DomEvent.off(container, 'click', this._onMouseClick, this); for (var i = 0; i < events.length; i++) { L.DomEvent.off(container, events[i], this._fireMouseEvent, this); } }, _onMouseClick: function (e) { if (this.hasEventListeners(e.type)) { L.DomEvent.stopPropagation(e); } this.fire(e.type, { originalEvent: e }); }, _fireMouseEvent: function (e) { this.fire(e.type, { originalEvent: e }); // TODO proper custom event propagation // this line will always be called if marker is in a FeatureGroup if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { L.DomEvent.preventDefault(e); } if (e.type !== 'mousedown') { L.DomEvent.stopPropagation(e); } else { L.DomEvent.preventDefault(e); } } }); // This object is a mixin for L.Marker and L.CircleMarker. We declare it here as both need to include the contents. L.BaseMarkerMethods = { showLabel: function () { if (this.label && this._map) { this.label.setLatLng(this._latlng); this._map.showLabel(this.label); } return this; }, hideLabel: function () { if (this.label) { this.label.close(); } return this; }, setLabelNoHide: function (noHide) { if (this._labelNoHide === noHide) { return; } this._labelNoHide = noHide; if (noHide) { this._removeLabelRevealHandlers(); this.showLabel(); } else { this._addLabelRevealHandlers(); this.hideLabel(); } }, bindLabel: function (content, options) { if(this.label){ return false; } var labelAnchor = this.options.icon ? this.options.icon.options.labelAnchor : this.options.labelAnchor, anchor = L.point(labelAnchor) || L.point(0, 0); anchor = anchor.add(L.Label.prototype.options.offset); if (options && options.offset) { anchor = anchor.add(options.offset); } options = L.Util.extend({offset: anchor}, options); this._labelNoHide = options.noHide; if (!this.label) { if (!this._labelNoHide) { this._addLabelRevealHandlers(); } this .on('remove', this.hideLabel, this) .on('move', this._moveLabel, this) .on('add', this._onMarkerAdd, this); this._hasLabelHandlers = true; } this.label = new L.Label(options, this) .setContent(content); return this; }, unbindLabel: function () { if (this.label) { this.hideLabel(); this.label = null; if (this._hasLabelHandlers) { if (!this._labelNoHide) { this._removeLabelRevealHandlers(); } this .off('remove', this.hideLabel, this) .off('move', this._moveLabel, this) .off('add', this._onMarkerAdd, this); } this._hasLabelHandlers = false; } return this; }, updateLabelContent: function (content) { if (this.label) { this.label.setContent(content); } }, getLabel: function () { return this.label; }, _onMarkerAdd: function () { if (this._labelNoHide) { this.showLabel(); } }, _addLabelRevealHandlers: function () { this .on('mouseover', this.showLabel, this) .on('mouseout', this.hideLabel, this); if (L.Browser.touch) { this.on('click', this.showLabel, this); } }, _removeLabelRevealHandlers: function () { this .off('mouseover', this.showLabel, this) .off('mouseout', this.hideLabel, this); if (L.Browser.touch) { this.off('click', this.showLabel, this); } }, _moveLabel: function (e) { this.label.setLatLng(e.latlng); } }; // Add in an option to icon that is used to set where the label anchor is L.Icon.Default.mergeOptions({ labelAnchor: new L.Point(4, -15) }); // Have to do this since Leaflet is loaded before this plugin and initializes // L.Marker.options.icon therefore missing our mixin above. L.Marker.mergeOptions({ icon: new L.Icon.Default() }); L.Marker.include(L.BaseMarkerMethods); L.Marker.include({ _originalUpdateZIndex: L.Marker.prototype._updateZIndex, _updateZIndex: function (offset) { var zIndex = this._zIndex + offset; this._originalUpdateZIndex(offset); if (this.label) { this.label.updateZIndex(zIndex); } }, _originalSetOpacity: L.Marker.prototype.setOpacity, setOpacity: function (opacity, labelHasSemiTransparency) { this.options.labelHasSemiTransparency = labelHasSemiTransparency; this._originalSetOpacity(opacity); }, _originalUpdateOpacity: L.Marker.prototype._updateOpacity, _updateOpacity: function () { var absoluteOpacity = this.options.opacity === 0 ? 0 : 1; this._originalUpdateOpacity(); if (this.label) { this.label.setOpacity(this.options.labelHasSemiTransparency ? this.options.opacity : absoluteOpacity); } }, _originalSetLatLng: L.Marker.prototype.setLatLng, setLatLng: function (latlng) { if (this.label && !this._labelNoHide) { this.hideLabel(); } return this._originalSetLatLng(latlng); } }); // Add in an option to icon that is used to set where the label anchor is L.CircleMarker.mergeOptions({ labelAnchor: new L.Point(-5, 5) }); L.CircleMarker.include(L.BaseMarkerMethods); L.Path.include({ bindLabel: function (content, options) { if (!this.label || this.label.options !== options) { this.label = new L.Label(options, this); } this.label.setContent(content); if (!this._showLabelAdded) { this .on('mouseover', this._showLabel, this) .on('mousemove', this._moveLabel, this) .on('mouseout remove', this._hideLabel, this); if (L.Browser.touch) { this.on('click', this._showLabel, this); } this._showLabelAdded = true; } return this; }, unbindLabel: function () { if (this.label) { this._hideLabel(); this.label = null; this._showLabelAdded = false; this .off('mouseover', this._showLabel, this) .off('mousemove', this._moveLabel, this) .off('mouseout remove', this._hideLabel, this); } return this; }, updateLabelContent: function (content) { if (this.label) { this.label.setContent(content); } }, _showLabel: function (e) { this.label.setLatLng(e.latlng); this._map.showLabel(this.label); }, _moveLabel: function (e) { this.label.setLatLng(e.latlng); }, _hideLabel: function () { this.label.close(); } }); L.Map.include({ showLabel: function (label) { return this.addLayer(label); } }); L.FeatureGroup.include({ // TODO: remove this when AOP is supported in Leaflet, need this as we cannot put code in removeLayer() clearLayers: function () { this.unbindLabel(); this.eachLayer(this.removeLayer, this); return this; }, bindLabel: function (content, options) { return this.invoke('bindLabel', content, options); }, unbindLabel: function () { return this.invoke('unbindLabel'); }, updateLabelContent: function (content) { this.invoke('updateLabelContent', content); } }); }(window, document)); /* Leaflet.plabel, a plugin that adds plabels to markers and vectors for Leaflet powered maps. (c) 2012-2013, Jacob Toye, Smartrak https://github.com/Leaflet/Leaflet.plabel http://leafletjs.com https://github.com/jacobtoye */ (function () { //var L = window.L; /* * Leaflet.plabel assumes that you have already included the Leaflet library. */ //L.plabelVersion = '0.2.2-dev'; L.Plabel = (L.Layer ? L.Layer : L.Class).extend({ includes: L.Mixin.Events, options: { className: '', clickable: true, direction: 'right', noHide: false, offset: [0, 0], // 6 (width of the plabel triangle) + 6 (padding) opacity: 1, color:'#000000', bold:false, background:'', zoomAnimation: true, lineWidth:42.4, }, initialize: function (options, source) { L.setOptions(this, options); this._source = source; this._animated = L.Browser.any3d && this.options.zoomAnimation; this._isOpen = false; }, onAdd: function (map) { this._map = map; this._isOpen = true; this._pane = this.options.pane ? map._panes[this.options.pane] : this._source instanceof L.Marker ? map._panes.markerPane : map._panes.popupPane; if (!this._container) { this._initLayout(); } this._pane.appendChild(this._container); this._initInteraction(); this._update(); this.setOpacity(this.options.opacity); map .on('moveend', this._onMoveEnd, this) .on('move',this._onMoveEnd,this) .on('viewreset', this._onViewReset, this); if (this._animated) { map.on('zoomanim', this._zoomAnimation, this); } // if (L.Browser.touch && !this.options.noHide) { // L.DomEvent.on(this._container, 'click', this.close, this); // map.on('click', this.close, this); // } }, onRemove: function (map) { this._pane.removeChild(this._container); this._isOpen = false; map.off({ zoomanim: this._zoomAnimation, move:this._onMoveEnd, moveend: this._onMoveEnd, viewreset: this._onViewReset }, this); this._removeInteraction(); this._map = null; }, setLatLng: function (latlng) { this._latlng = L.latLng(latlng); if (this._map) { this._updatePosition(); } return this; }, setContent: function (content) { // Backup previous content and store new content this._previousContent = this._content; this._content = content; this._updateContent(); return this; }, setColor:function(color){ this.options.color = color; if (this._container) { this._containerLine.style.borderBottomColor = color; this._containerText.style.color = color; } return this; }, setBold:function(flag){ this.options.bold = flag; if (this._container) { if(flag){ this._containerLine.style.borderBottomWidth = '2px'; this._containerText.style.fontWeight = 800; }else{ this._containerLine.style.borderBottomWidth = '1px'; this._containerText.style.fontWeight = 400; } } return this; }, setBackground:function(color){ this.options.background = color; if (this._container) { if(color){ this._containerText.style.backgroundColor = color; }else{ this._containerText.style.backgroundColor = ''; } } return this; }, close: function () { var map = this._map; this._isOpen = false; if (map) { // if (L.Browser.touch && !this.options.noHide) { // L.DomEvent.off(this._container, 'click', this.close); // map.off('click', this.close, this); // } map.removeLayer(this); } }, updateZIndex: function (zIndex) { this._zIndex = zIndex; if (this._container && this._zIndex) { this._container.style.zIndex = zIndex; } }, setOpacity: function (opacity) { this.options.opacity = opacity; if (this._container) { L.DomUtil.setOpacity(this._container, opacity); } }, _initLayout: function () { this._container = L.DomUtil.create('div', 'leaflet-plabel ' + this.options.className + ' leaflet-zoom-animated'); this._containerLine = L.DomUtil.create('div','leaflet-plabel-line',this._container); this._containerText = L.DomUtil.create('div','leaflet-plabel-text',this._container); $(this._containerText).dragmove(); var lleft = Math.pow(Math.pow(this.options.lineWidth,2)/2,0.5)+'px'; var ltop = -Math.pow(Math.pow(this.options.lineWidth,2)/2,0.5)+'px'; this._containerText.style.left = lleft; this._containerText.style.top = ltop; this._containerLine.style.width = this.options.lineWidth+'px'; this._containerText.style.backgroundColor = this.options.background; L.DomEvent.on(this._containerText,'mousedown',function(e){ this._map.dragging.disable(); },this) L.DomEvent.on(this._containerText,'mousemove',function(e){ var left = parseInt(this._containerText.style.left||30); var top = parseInt(this._containerText.style.top||-30); var angle = this._angle({x:0,y:0},{x:left,y:top}) this._containerLine.style.transform = 'rotate('+angle+'deg)'; this._containerLine.style.msTransform = 'rotate('+angle+'deg)'; var lineWidth = Math.pow((Math.abs(left) * Math.abs(left) + Math.abs(top) * Math.abs(top)), 0.5) this._containerLine.style.width = lineWidth+'px'; },this) L.DomEvent.on(this._containerText,'mouseup',function(e){ this._map.dragging.enable(); },this) this.updateZIndex(this._zIndex); }, _angle:function(start,end){ var diff_x = end.x - start.x, diff_y = end.y - start.y; //返回角度,不是弧度 var angle = 360*Math.atan(diff_y/diff_x)/(2*Math.PI); if(end.x this.options.distance) { while (dist > this.options.distance) { cur = new L.LatLng(cur.lat + dLat, cur.lng + dLng); dist = cur.distanceTo(next); chunkedLatLngs.push(cur); } } else { chunkedLatLngs.push(cur); } } chunkedLatLngs.push(latlngs[len-1]); return chunkedLatLngs; }, onAdd: function (map) { L.Marker.prototype.onAdd.call(this, map); // Start animating when added to the map if (this.options.autoStart) { this.start(); } }, animate: function() { map23DControl.anMarkerGon = true; var self = this, len = this._latlngs.length, speed = this.options.speedMultiple; var guid = this.guid; $.each(map23DData.timeLineData,function(i,t){ if((guid === i) && (t._i > 0)){ self._i = t._i; t._i = -11; } }); // Normalize the transition speed from vertex to vertex if (this._i < len && this._i > 0) { var maxlength = $("#"+guid+" .Main").width(); var curlength = Math.round((self._i/(len-1))*maxlength); $("#"+guid+" .scroll_Thumb").css("left", curlength -32+ "px"); $("#"+guid+" .scroll_Track").css("width", curlength + "px"); $("#"+guid+" .scrollBarTxt").html(self._i + "/" + len); var turnrorate = L.Util.getAngleByLatLng(this._latlngs[this._i-1].lng,this._latlngs[this._i-1].lat,this._latlngs[this._i].lng,this._latlngs[this._i].lat); turnrorate = turnrorate; var markerData = map23DData.markers[guid]; var marker = map2DViewer.markers[guid]; if(!!markerData){ var icon_html=''; var setDivIcon = L.divIcon({ className:'rorate_div', html:icon_html, iconAnchor:markerData.geojson.properties.iconAnchor, iconSize:markerData.geojson.properties.iconSize, popupAnchor:markerData.geojson.properties.popupAnchor}); marker.setIcon(setDivIcon); //var curTime = Date.parse(map23DData.markers[guid].geojson.properties.markerTime[this._i-1]); //var curPreTime = Date.parse(map23DData.markers[guid].geojson.properties.markerTime[this._i]); var curTime = map23DData.markers[guid].geojson.properties.markerTime[this._i-1]; var curPreTime = map23DData.markers[guid].geojson.properties.markerTime[this._i]; //marker实时更新信息 var curTSpeed = new L.LatLng(this._latlngs[this._i -1].lng,this._latlngs[this._i -1].lat).distanceTo(new L.LatLng(this._latlngs[this._i].lng,this._latlngs[this._i].lat)); this.curOptions = { "curTime":curTime, "curPreTime":curPreTime, "curLatlng":this._latlngs[this._i], "curPreLatlng":this._latlngs[this._i -1], "curDiatance":curTSpeed }; PubSub.publishSync('curMarkerOptions',guid); if(this._i === 1){ speed = 1; }else{ speed = (curPreTime - curTime)/this.options.speedMultiple; } } }else if(this._i == len){ } map2DViewer.map.on('zoomend',function(){ /*if (L.DomUtil.TRANSITION) { if (this._icon) { this._icon.style[L.DomUtil.TRANSITION] = ('all ' + 1 + 'ms linear'); } if (this._shadow) { this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + 1 + 'ms linear'; } } this.setLatLng(this._latlngs[this._i]);*/ map23DControl.Speed = true; if(!map23DControl.anMarkerGon){ $.each(map2DViewer.routeBackGroup,function(i,t){ var animate_data = map2DViewer.routeBackGroup[i].marker; if(map23DData.markers[animate_data].visible2D){ var _this = map2DViewer.markers[animate_data]; if (L.DomUtil.TRANSITION) { if (_this._icon) { _this._icon.style[L.DomUtil.TRANSITION] = ('all ' + 0 + 'ms linear'); } if (_this._shadow) { _this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + 0 + 'ms linear'; } } if(_this._i < _this._latlngs.length){ _this.setLatLng(_this._latlngs[_this._i]); _this['_i'] = _this._i; } } }) } }) // Only if CSS3 transitions are supported if (L.DomUtil.TRANSITION) { if(map23DControl.Speed){ if (this._icon) { this._icon.style[L.DomUtil.TRANSITION] = ('all ' + 0 + 'ms linear'); } if (this._shadow) { this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + 0 + 'ms linear'; } map23DControl.Speed = false; }else{ if (this._icon) { this._icon.style[L.DomUtil.TRANSITION] = ('all ' + speed + 'ms linear'); } if (this._shadow) { this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + speed + 'ms linear'; } } } // Move to the next vertex this.setLatLng(this._latlngs[this._i]); this._i++; map23DControl.anMarkerGon = false; // Queue up the animation to the next next vertex this._tid = setTimeout(function(){ if (self._i === len) { $.each(map2DViewer.routeBackGroup,function(i,t){ if(map2DViewer.routeBackGroup[i].marker === guid){ map2DViewer.routeBackGroup[i].isEnd = true; PubSub.publishSync('payBackEnd',i); }; }) self.options.onEnd.apply(self, Array.prototype.slice.call(arguments)); } else { self.animate(); } }, speed); }, // Start the animation start: function() { this.animate(); window.marker_Animate = true; $.each(map2DViewer.routeBackGroup,function(i,t){ map2DViewer.routeBackGroup[i].marker === this.guid; map2DViewer.routeBackGroup[i].isEnd = false; }) }, restart:function(){ this.stop(); this['_i'] = 0; this.start(); }, // Stop the animation in place stop: function() { if (this._tid) { clearTimeout(this._tid); window.marker_Animate = false; //this.animate(); } }, setLine: function(latlngs){ if (L.DomUtil.TRANSITION) { // No need to to check up the line if we can animate using CSS3 this._latlngs = latlngs; } else { // Chunk up the lines into options.distance bits this._latlngs = this._chunk(latlngs); this.options.distance = 10; this.options.interval = 3; } this._i = 0; } }); L.animatedMarker = function (latlngs, options) { return new L.AnimatedMarker(latlngs, options); }; /* Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps. https://github.com/Leaflet/Leaflet.markercluster (c) 2012-2013, Dave Leaver, smartrak */ (function (window, document, undefined) {/* * L.MarkerClusterGroup extends L.FeatureGroup by clustering the markers contained within */ L.MarkerClusterGroup = L.FeatureGroup.extend({ options: { maxClusterRadius: 120, //A cluster will cover at most this many pixels from its center iconCreateFunction: null, spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: true, singleMarkerMode: false, disableClusteringAtZoom: null, // Setting this to false prevents the removal of any clusters outside of the viewpoint, which // is the default behaviour for performance reasons. removeOutsideVisibleBounds: true, // Set to false to disable all animations (zoom and spiderfy). // If false, option animateAddingMarkers below has no effect. // If L.DomUtil.TRANSITION is falsy, this option has no effect. animate: true, //Whether to animate adding markers after adding the MarkerClusterGroup to the map // If you are adding individual markers set to true, if adding bulk markers leave false for massive performance gains. animateAddingMarkers: false, //Increase to increase the distance away that spiderfied markers appear from the center spiderfyDistanceMultiplier: 1, // Make it possible to specify a polyline options on a spider leg spiderLegPolylineOptions: { weight: 1, color: '#222', opacity: 0.5 }, // When bulk adding layers, adds markers in chunks. Means addLayers may not add all the layers in the call, others will be loaded during setTimeouts chunkedLoading: false, chunkInterval: 200, // process markers for a maximum of ~ n milliseconds (then trigger the chunkProgress callback) chunkDelay: 50, // at the end of each interval, give n milliseconds back to system/browser chunkProgress: null, // progress callback: function(processed, total, elapsed) (e.g. for a progress indicator) //Options to pass to the L.Polygon constructor polygonOptions: {weight: 1, opacity: 0.5} }, initialize: function (options) { L.Util.setOptions(this, options); if (!this.options.iconCreateFunction) { this.options.iconCreateFunction = this._defaultIconCreateFunction; } this._featureGroup = L.featureGroup(); this._featureGroup.addEventParent(this); this._nonPointGroup = L.featureGroup(); this._nonPointGroup.addEventParent(this); this._inZoomAnimation = 0; this._needsClustering = []; this._needsRemoving = []; //Markers removed while we aren't on the map need to be kept track of //The bounds of the currently shown area (from _getExpandedVisibleBounds) Updated on zoom/move this._currentShownBounds = null; this._queue = []; // Hook the appropriate animation methods. var animate = L.DomUtil.TRANSITION && this.options.animate; L.extend(this, animate ? this._withAnimation : this._noAnimation); // Remember which MarkerCluster class to instantiate (animated or not). this._markerCluster = animate ? L.MarkerCluster : L.MarkerClusterNonAnimated; }, addLayer: function (layer) { if (layer instanceof L.LayerGroup) { return this.addLayers([layer]); } //Don't cluster non point data if (!layer.getLatLng) { this._nonPointGroup.addLayer(layer); return this; } if (!this._map) { this._needsClustering.push(layer); return this; } if (this.hasLayer(layer)) { return this; } //If we have already clustered we'll need to add this one to a cluster if (this._unspiderfy) { this._unspiderfy(); } this._addLayer(layer, this._maxZoom); // Refresh bounds and weighted positions. this._topClusterLevel._recalculateBounds(); this._refreshClustersIcons(); //Work out what is visible var visibleLayer = layer, currentZoom = this._zoom; if (layer.__parent) { while (visibleLayer.__parent._zoom >= currentZoom) { visibleLayer = visibleLayer.__parent; } } if (this._currentShownBounds.contains(visibleLayer.getLatLng())) { if (this.options.animateAddingMarkers) { this._animationAddLayer(layer, visibleLayer); } else { this._animationAddLayerNonAnimated(layer, visibleLayer); } } return this; }, removeLayer: function (layer) { if (layer instanceof L.LayerGroup) { return this.removeLayers([layer]); } //Non point layers if (!layer.getLatLng) { this._nonPointGroup.removeLayer(layer); return this; } if (!this._map) { if (!this._arraySplice(this._needsClustering, layer) && this.hasLayer(layer)) { this._needsRemoving.push(layer); } return this; } if (!layer.__parent) { return this; } if (this._unspiderfy) { this._unspiderfy(); this._unspiderfyLayer(layer); } //Remove the marker from clusters this._removeLayer(layer, true); // Refresh bounds and weighted positions. this._topClusterLevel._recalculateBounds(); this._refreshClustersIcons(); layer.off('move', this._childMarkerMoved, this); if (this._featureGroup.hasLayer(layer)) { this._featureGroup.removeLayer(layer); if (layer.clusterShow) { layer.clusterShow(); } } return this; }, //Takes an array of markers and adds them in bulk addLayers: function (layersArray) { if (!L.Util.isArray(layersArray)) { return this.addLayer(layersArray); } var fg = this._featureGroup, npg = this._nonPointGroup, chunked = this.options.chunkedLoading, chunkInterval = this.options.chunkInterval, chunkProgress = this.options.chunkProgress, l = layersArray.length, offset = 0, originalArray = true, m; if (this._map) { var started = (new Date()).getTime(); var process = L.bind(function () { var start = (new Date()).getTime(); for (; offset < l; offset++) { if (chunked && offset % 200 === 0) { // every couple hundred markers, instrument the time elapsed since processing started: var elapsed = (new Date()).getTime() - start; if (elapsed > chunkInterval) { break; // been working too hard, time to take a break :-) } } m = layersArray[offset]; // Group of layers, append children to layersArray and skip. // Side effects: // - Total increases, so chunkProgress ratio jumps backward. // - Groups are not included in this group, only their non-group child layers (hasLayer). // Changing array length while looping does not affect performance in current browsers: // http://jsperf.com/for-loop-changing-length/6 if (m instanceof L.LayerGroup) { if (originalArray) { layersArray = layersArray.slice(); originalArray = false; } this._extractNonGroupLayers(m, layersArray); l = layersArray.length; continue; } //Not point data, can't be clustered if (!m.getLatLng) { npg.addLayer(m); continue; } if (this.hasLayer(m)) { continue; } this._addLayer(m, this._maxZoom); //If we just made a cluster of size 2 then we need to remove the other marker from the map (if it is) or we never will if (m.__parent) { if (m.__parent.getChildCount() === 2) { var markers = m.__parent.getAllChildMarkers(), otherMarker = markers[0] === m ? markers[1] : markers[0]; fg.removeLayer(otherMarker); } } } if (chunkProgress) { // report progress and time elapsed: chunkProgress(offset, l, (new Date()).getTime() - started); } // Completed processing all markers. if (offset === l) { // Refresh bounds and weighted positions. this._topClusterLevel._recalculateBounds(); this._refreshClustersIcons(); this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds); } else { setTimeout(process, this.options.chunkDelay); } }, this); process(); } else { var needsClustering = this._needsClustering; for (; offset < l; offset++) { m = layersArray[offset]; // Group of layers, append children to layersArray and skip. if (m instanceof L.LayerGroup) { if (originalArray) { layersArray = layersArray.slice(); originalArray = false; } this._extractNonGroupLayers(m, layersArray); l = layersArray.length; continue; } //Not point data, can't be clustered if (!m.getLatLng) { npg.addLayer(m); continue; } if (this.hasLayer(m)) { continue; } needsClustering.push(m); } } return this; }, //Takes an array of markers and removes them in bulk removeLayers: function (layersArray) { var i, m, l = layersArray.length, fg = this._featureGroup, npg = this._nonPointGroup, originalArray = true; if (!this._map) { for (i = 0; i < l; i++) { m = layersArray[i]; // Group of layers, append children to layersArray and skip. if (m instanceof L.LayerGroup) { if (originalArray) { layersArray = layersArray.slice(); originalArray = false; } this._extractNonGroupLayers(m, layersArray); l = layersArray.length; continue; } this._arraySplice(this._needsClustering, m); npg.removeLayer(m); if (this.hasLayer(m)) { this._needsRemoving.push(m); } } return this; } if (this._unspiderfy) { this._unspiderfy(); // Work on a copy of the array, so that next loop is not affected. var layersArray2 = layersArray.slice(), l2 = l; for (i = 0; i < l2; i++) { m = layersArray2[i]; // Group of layers, append children to layersArray and skip. if (m instanceof L.LayerGroup) { this._extractNonGroupLayers(m, layersArray2); l2 = layersArray2.length; continue; } this._unspiderfyLayer(m); } } for (i = 0; i < l; i++) { m = layersArray[i]; // Group of layers, append children to layersArray and skip. if (m instanceof L.LayerGroup) { if (originalArray) { layersArray = layersArray.slice(); originalArray = false; } this._extractNonGroupLayers(m, layersArray); l = layersArray.length; continue; } if (!m.__parent) { npg.removeLayer(m); continue; } this._removeLayer(m, true, true); if (fg.hasLayer(m)) { fg.removeLayer(m); if (m.clusterShow) { m.clusterShow(); } } } // Refresh bounds and weighted positions. this._topClusterLevel._recalculateBounds(); this._refreshClustersIcons(); //Fix up the clusters and markers on the map this._topClusterLevel._recursivelyAddChildrenToMap(null, this._zoom, this._currentShownBounds); return this; }, //Removes all layers from the MarkerClusterGroup clearLayers: function () { //Need our own special implementation as the LayerGroup one doesn't work for us //If we aren't on the map (yet), blow away the markers we know of if (!this._map) { this._needsClustering = []; delete this._gridClusters; delete this._gridUnclustered; } if (this._noanimationUnspiderfy) { this._noanimationUnspiderfy(); } //Remove all the visible layers this._featureGroup.clearLayers(); this._nonPointGroup.clearLayers(); this.eachLayer(function (marker) { marker.off('move', this._childMarkerMoved, this); delete marker.__parent; }); if (this._map) { //Reset _topClusterLevel and the DistanceGrids this._generateInitialClusters(); } return this; }, //Override FeatureGroup.getBounds as it doesn't work getBounds: function () { var bounds = new L.LatLngBounds(); if (this._topClusterLevel) { bounds.extend(this._topClusterLevel._bounds); } for (var i = this._needsClustering.length - 1; i >= 0; i--) { bounds.extend(this._needsClustering[i].getLatLng()); } bounds.extend(this._nonPointGroup.getBounds()); return bounds; }, //Overrides LayerGroup.eachLayer eachLayer: function (method, context) { var markers = this._needsClustering.slice(), needsRemoving = this._needsRemoving, i; if (this._topClusterLevel) { this._topClusterLevel.getAllChildMarkers(markers); } for (i = markers.length - 1; i >= 0; i--) { if (needsRemoving.indexOf(markers[i]) === -1) { method.call(context, markers[i]); } } this._nonPointGroup.eachLayer(method, context); }, //Overrides LayerGroup.getLayers getLayers: function () { var layers = []; this.eachLayer(function (l) { layers.push(l); }); return layers; }, //Overrides LayerGroup.getLayer, WARNING: Really bad performance getLayer: function (id) { var result = null; id = parseInt(id, 10); this.eachLayer(function (l) { if (L.stamp(l) === id) { result = l; } }); return result; }, //Returns true if the given layer is in this MarkerClusterGroup hasLayer: function (layer) { if (!layer) { return false; } var i, anArray = this._needsClustering; for (i = anArray.length - 1; i >= 0; i--) { if (anArray[i] === layer) { return true; } } anArray = this._needsRemoving; for (i = anArray.length - 1; i >= 0; i--) { if (anArray[i] === layer) { return false; } } return !!(layer.__parent && layer.__parent._group === this) || this._nonPointGroup.hasLayer(layer); }, //Zoom down to show the given layer (spiderfying if necessary) then calls the callback zoomToShowLayer: function (layer, callback) { if (typeof callback !== 'function') { callback = function () {}; } var showMarker = function () { if ((layer._icon || layer.__parent._icon) && !this._inZoomAnimation) { this._map.off('moveend', showMarker, this); this.off('animationend', showMarker, this); if (layer._icon) { callback(); } else if (layer.__parent._icon) { this.once('spiderfied', callback, this); layer.__parent.spiderfy(); } } }; if (layer._icon && this._map.getBounds().contains(layer.getLatLng())) { //Layer is visible ond on screen, immediate return callback(); } else if (layer.__parent._zoom < Math.round(this._map._zoom)) { //Layer should be visible at this zoom level. It must not be on screen so just pan over to it this._map.on('moveend', showMarker, this); this._map.panTo(layer.getLatLng()); } else { var moveStart = function () { this._map.off('movestart', moveStart, this); moveStart = null; }; this._map.on('movestart', moveStart, this); this._map.on('moveend', showMarker, this); this.on('animationend', showMarker, this); layer.__parent.zoomToBounds(); if (moveStart) { //Never started moving, must already be there, probably need clustering however showMarker.call(this); } } }, //Overrides FeatureGroup.onAdd onAdd: function (map) { this._map = map; var i, l, layer; if (!isFinite(this._map.getMaxZoom())) { throw "Map has no maxZoom specified"; } this._featureGroup.addTo(map); this._nonPointGroup.addTo(map); if (!this._gridClusters) { this._generateInitialClusters(); } this._maxLat = map.options.crs.projection.MAX_LATITUDE; for (i = 0, l = this._needsRemoving.length; i < l; i++) { layer = this._needsRemoving[i]; this._removeLayer(layer, true); } this._needsRemoving = []; //Remember the current zoom level and bounds this._zoom = Math.round(this._map._zoom); this._currentShownBounds = this._getExpandedVisibleBounds(); this._map.on('zoomend', this._zoomEnd, this); this._map.on('moveend', this._moveEnd, this); if (this._spiderfierOnAdd) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely this._spiderfierOnAdd(); } this._bindEvents(); //Actually add our markers to the map: l = this._needsClustering; this._needsClustering = []; this.addLayers(l); }, //Overrides FeatureGroup.onRemove onRemove: function (map) { map.off('zoomend', this._zoomEnd, this); map.off('moveend', this._moveEnd, this); this._unbindEvents(); //In case we are in a cluster animation this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', ''); if (this._spiderfierOnRemove) { //TODO FIXME: Not sure how to have spiderfier add something on here nicely this._spiderfierOnRemove(); } delete this._maxLat; //Clean up all the layers we added to the map this._hideCoverage(); this._featureGroup.remove(); this._nonPointGroup.remove(); this._featureGroup.clearLayers(); this._map = null; }, getVisibleParent: function (marker) { var vMarker = marker; while (vMarker && !vMarker._icon) { vMarker = vMarker.__parent; } return vMarker || null; }, //Remove the given object from the given array _arraySplice: function (anArray, obj) { for (var i = anArray.length - 1; i >= 0; i--) { if (anArray[i] === obj) { anArray.splice(i, 1); return true; } } }, /** * Removes a marker from all _gridUnclustered zoom levels, starting at the supplied zoom. * @param marker to be removed from _gridUnclustered. * @param z integer bottom start zoom level (included) * @private */ _removeFromGridUnclustered: function (marker, z) { var map = this._map, gridUnclustered = this._gridUnclustered; for (; z >= 0; z--) { if (!gridUnclustered[z].removeObject(marker, map.project(marker.getLatLng(), z))) { break; } } }, _childMarkerMoved: function (e) { if (!this._ignoreMove) { e.target._latlng = e.oldLatLng; this.removeLayer(e.target); e.target._latlng = e.latlng; this.addLayer(e.target); } }, //Internal function for removing a marker from everything. //dontUpdateMap: set to true if you will handle updating the map manually (for bulk functions) _removeLayer: function (marker, removeFromDistanceGrid, dontUpdateMap) { var gridClusters = this._gridClusters, gridUnclustered = this._gridUnclustered, fg = this._featureGroup, map = this._map; //Remove the marker from distance clusters it might be in if (removeFromDistanceGrid) { this._removeFromGridUnclustered(marker, this._maxZoom); } //Work our way up the clusters removing them as we go if required var cluster = marker.__parent, markers = cluster._markers, otherMarker; //Remove the marker from the immediate parents marker list this._arraySplice(markers, marker); while (cluster) { cluster._childCount--; cluster._boundsNeedUpdate = true; if (cluster._zoom < 0) { //Top level, do nothing break; } else if (removeFromDistanceGrid && cluster._childCount <= 1) { //Cluster no longer required //We need to push the other marker up to the parent otherMarker = cluster._markers[0] === marker ? cluster._markers[1] : cluster._markers[0]; //Update distance grid gridClusters[cluster._zoom].removeObject(cluster, map.project(cluster._cLatLng, cluster._zoom)); gridUnclustered[cluster._zoom].addObject(otherMarker, map.project(otherMarker.getLatLng(), cluster._zoom)); //Move otherMarker up to parent this._arraySplice(cluster.__parent._childClusters, cluster); cluster.__parent._markers.push(otherMarker); otherMarker.__parent = cluster.__parent; if (cluster._icon) { //Cluster is currently on the map, need to put the marker on the map instead fg.removeLayer(cluster); if (!dontUpdateMap) { fg.addLayer(otherMarker); } } } else { cluster._iconNeedsUpdate = true; } cluster = cluster.__parent; } delete marker.__parent; }, _isOrIsParent: function (el, oel) { while (oel) { if (el === oel) { return true; } oel = oel.parentNode; } return false; }, //Override L.Evented.fire fire: function (type, data, propagate) { if (data && data.layer instanceof L.MarkerCluster) { //Prevent multiple clustermouseover/off events if the icon is made up of stacked divs (Doesn't work in ie <= 8, no relatedTarget) if (data.originalEvent && this._isOrIsParent(data.layer._icon, data.originalEvent.relatedTarget)) { return; } type = 'cluster' + type; } L.FeatureGroup.prototype.fire.call(this, type, data, propagate); }, //Override L.Evented.listens listens: function (type, propagate) { return L.FeatureGroup.prototype.listens.call(this, type, propagate) || L.FeatureGroup.prototype.listens.call(this, 'cluster' + type, propagate); }, //Default functionality _defaultIconCreateFunction: function (cluster) { var childCount = cluster.getChildCount(); var c = ' marker-cluster-'; if (childCount < 10) { c += 'small'; } else if (childCount < 100) { c += 'medium'; } else { c += 'large'; } return new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) }); }, _bindEvents: function () { var map = this._map, spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, showCoverageOnHover = this.options.showCoverageOnHover, zoomToBoundsOnClick = this.options.zoomToBoundsOnClick; //Zoom on cluster click or spiderfy if we are at the lowest level if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { this.on('clusterclick', this._zoomOrSpiderfy, this); } //Show convex hull (boundary) polygon on mouse over if (showCoverageOnHover) { this.on('clustermouseover', this._showCoverage, this); this.on('clustermouseout', this._hideCoverage, this); map.on('zoomend', this._hideCoverage, this); } }, _zoomOrSpiderfy: function (e) { var cluster = e.layer, bottomCluster = cluster; while (bottomCluster._childClusters.length === 1) { bottomCluster = bottomCluster._childClusters[0]; } if (bottomCluster._zoom === this._maxZoom && bottomCluster._childCount === cluster._childCount && this.options.spiderfyOnMaxZoom) { // All child markers are contained in a single cluster from this._maxZoom to this cluster. cluster.spiderfy(); } else if (this.options.zoomToBoundsOnClick) { cluster.zoomToBounds(); } // Focus the map again for keyboard users. if (e.originalEvent && e.originalEvent.keyCode === 13) { this._map._container.focus(); } }, _showCoverage: function (e) { var map = this._map; if (this._inZoomAnimation) { return; } if (this._shownPolygon) { map.removeLayer(this._shownPolygon); } if (e.layer.getChildCount() > 2 && e.layer !== this._spiderfied) { this._shownPolygon = new L.Polygon(e.layer.getConvexHull(), this.options.polygonOptions); map.addLayer(this._shownPolygon); } }, _hideCoverage: function () { if (this._shownPolygon) { this._map.removeLayer(this._shownPolygon); this._shownPolygon = null; } }, _unbindEvents: function () { var spiderfyOnMaxZoom = this.options.spiderfyOnMaxZoom, showCoverageOnHover = this.options.showCoverageOnHover, zoomToBoundsOnClick = this.options.zoomToBoundsOnClick, map = this._map; if (spiderfyOnMaxZoom || zoomToBoundsOnClick) { this.off('clusterclick', this._zoomOrSpiderfy, this); } if (showCoverageOnHover) { this.off('clustermouseover', this._showCoverage, this); this.off('clustermouseout', this._hideCoverage, this); map.off('zoomend', this._hideCoverage, this); } }, _zoomEnd: function () { if (!this._map) { //May have been removed from the map by a zoomEnd handler return; } this._mergeSplitClusters(); this._zoom = Math.round(this._map._zoom); this._currentShownBounds = this._getExpandedVisibleBounds(); }, _moveEnd: function () { if (this._inZoomAnimation) { return; } var newBounds = this._getExpandedVisibleBounds(); this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, newBounds); this._topClusterLevel._recursivelyAddChildrenToMap(null, Math.round(this._map._zoom), newBounds); this._currentShownBounds = newBounds; return; }, _generateInitialClusters: function () { var maxZoom = this._map.getMaxZoom(), radius = this.options.maxClusterRadius, radiusFn = radius; //If we just set maxClusterRadius to a single number, we need to create //a simple function to return that number. Otherwise, we just have to //use the function we've passed in. if (typeof radius !== "function") { radiusFn = function () { return radius; }; } if (this.options.disableClusteringAtZoom) { maxZoom = this.options.disableClusteringAtZoom - 1; } this._maxZoom = maxZoom; this._gridClusters = {}; this._gridUnclustered = {}; //Set up DistanceGrids for each zoom for (var zoom = maxZoom; zoom >= 0; zoom--) { this._gridClusters[zoom] = new L.DistanceGrid(radiusFn(zoom)); this._gridUnclustered[zoom] = new L.DistanceGrid(radiusFn(zoom)); } // Instantiate the appropriate L.MarkerCluster class (animated or not). this._topClusterLevel = new this._markerCluster(this, -1); }, //Zoom: Zoom to start adding at (Pass this._maxZoom to start at the bottom) _addLayer: function (layer, zoom) { var gridClusters = this._gridClusters, gridUnclustered = this._gridUnclustered, markerPoint, z; if (this.options.singleMarkerMode) { this._overrideMarkerIcon(layer); } layer.on('move', this._childMarkerMoved, this); //Find the lowest zoom level to slot this one in for (; zoom >= 0; zoom--) { markerPoint = this._map.project(layer.getLatLng(), zoom); // calculate pixel position //Try find a cluster close by var closest = gridClusters[zoom].getNearObject(markerPoint); if (closest) { closest._addChild(layer); layer.__parent = closest; return; } //Try find a marker close by to form a new cluster with closest = gridUnclustered[zoom].getNearObject(markerPoint); if (closest) { var parent = closest.__parent; if (parent) { this._removeLayer(closest, false); } //Create new cluster with these 2 in it var newCluster = new this._markerCluster(this, zoom, closest, layer); gridClusters[zoom].addObject(newCluster, this._map.project(newCluster._cLatLng, zoom)); closest.__parent = newCluster; layer.__parent = newCluster; //First create any new intermediate parent clusters that don't exist var lastParent = newCluster; for (z = zoom - 1; z > parent._zoom; z--) { lastParent = new this._markerCluster(this, z, lastParent); gridClusters[z].addObject(lastParent, this._map.project(closest.getLatLng(), z)); } parent._addChild(lastParent); //Remove closest from this zoom level and any above that it is in, replace with newCluster this._removeFromGridUnclustered(closest, zoom); return; } //Didn't manage to cluster in at this zoom, record us as a marker here and continue upwards gridUnclustered[zoom].addObject(layer, markerPoint); } //Didn't get in anything, add us to the top this._topClusterLevel._addChild(layer); layer.__parent = this._topClusterLevel; return; }, /** * Refreshes the icon of all "dirty" visible clusters. * Non-visible "dirty" clusters will be updated when they are added to the map. * @private */ _refreshClustersIcons: function () { this._featureGroup.eachLayer(function (c) { if (c instanceof L.MarkerCluster && c._iconNeedsUpdate) { c._updateIcon(); } }); }, //Enqueue code to fire after the marker expand/contract has happened _enqueue: function (fn) { this._queue.push(fn); if (!this._queueTimeout) { this._queueTimeout = setTimeout(L.bind(this._processQueue, this), 300); } }, _processQueue: function () { for (var i = 0; i < this._queue.length; i++) { this._queue[i].call(this); } this._queue.length = 0; clearTimeout(this._queueTimeout); this._queueTimeout = null; }, //Merge and split any existing clusters that are too big or small _mergeSplitClusters: function () { var mapZoom = Math.round(this._map._zoom); //In case we are starting to split before the animation finished this._processQueue(); if (this._zoom < mapZoom && this._currentShownBounds.intersects(this._getExpandedVisibleBounds())) { //Zoom in, split this._animationStart(); //Remove clusters now off screen this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, this._zoom, this._getExpandedVisibleBounds()); this._animationZoomIn(this._zoom, mapZoom); } else if (this._zoom > mapZoom) { //Zoom out, merge this._animationStart(); this._animationZoomOut(this._zoom, mapZoom); } else { this._moveEnd(); } }, //Gets the maps visible bounds expanded in each direction by the size of the screen (so the user cannot see an area we do not cover in one pan) _getExpandedVisibleBounds: function () { if (!this.options.removeOutsideVisibleBounds) { return this._mapBoundsInfinite; } else if (L.Browser.mobile) { return this._checkBoundsMaxLat(this._map.getBounds()); } return this._checkBoundsMaxLat(this._map.getBounds().pad(1)); // Padding expands the bounds by its own dimensions but scaled with the given factor. }, /** * Expands the latitude to Infinity (or -Infinity) if the input bounds reach the map projection maximum defined latitude * (in the case of Web/Spherical Mercator, it is 85.0511287798 / see https://en.wikipedia.org/wiki/Web_Mercator#Formulas). * Otherwise, the removeOutsideVisibleBounds option will remove markers beyond that limit, whereas the same markers without * this option (or outside MCG) will have their position floored (ceiled) by the projection and rendered at that limit, * making the user think that MCG "eats" them and never displays them again. * @param bounds L.LatLngBounds * @returns {L.LatLngBounds} * @private */ _checkBoundsMaxLat: function (bounds) { var maxLat = this._maxLat; if (maxLat !== undefined) { if (bounds.getNorth() >= maxLat) { bounds._northEast.lat = Infinity; } if (bounds.getSouth() <= -maxLat) { bounds._southWest.lat = -Infinity; } } return bounds; }, //Shared animation code _animationAddLayerNonAnimated: function (layer, newCluster) { if (newCluster === layer) { this._featureGroup.addLayer(layer); } else if (newCluster._childCount === 2) { newCluster._addToMap(); var markers = newCluster.getAllChildMarkers(); this._featureGroup.removeLayer(markers[0]); this._featureGroup.removeLayer(markers[1]); } else { newCluster._updateIcon(); } }, /** * Extracts individual (i.e. non-group) layers from a Layer Group. * @param group to extract layers from. * @param output {Array} in which to store the extracted layers. * @returns {*|Array} * @private */ _extractNonGroupLayers: function (group, output) { var layers = group.getLayers(), i = 0, layer; output = output || []; for (; i < layers.length; i++) { layer = layers[i]; if (layer instanceof L.LayerGroup) { this._extractNonGroupLayers(layer, output); continue; } output.push(layer); } return output; }, /** * Implements the singleMarkerMode option. * @param layer Marker to re-style using the Clusters iconCreateFunction. * @returns {L.Icon} The newly created icon. * @private */ _overrideMarkerIcon: function (layer) { var icon = layer.options.icon = this.options.iconCreateFunction({ getChildCount: function () { return 1; }, getAllChildMarkers: function () { return [layer]; } }); return icon; } }); // Constant bounds used in case option "removeOutsideVisibleBounds" is set to false. L.MarkerClusterGroup.include({ _mapBoundsInfinite: new L.LatLngBounds(new L.LatLng(-Infinity, -Infinity), new L.LatLng(Infinity, Infinity)) }); L.MarkerClusterGroup.include({ _noAnimation: { //Non Animated versions of everything _animationStart: function () { //Do nothing... }, _animationZoomIn: function (previousZoomLevel, newZoomLevel) { this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel); this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); //We didn't actually animate, but we use this event to mean "clustering animations have finished" this.fire('animationend'); }, _animationZoomOut: function (previousZoomLevel, newZoomLevel) { this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel); this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); //We didn't actually animate, but we use this event to mean "clustering animations have finished" this.fire('animationend'); }, _animationAddLayer: function (layer, newCluster) { this._animationAddLayerNonAnimated(layer, newCluster); } }, _withAnimation: { //Animated versions here _animationStart: function () { this._map._mapPane.className += ' leaflet-cluster-anim'; this._inZoomAnimation++; }, _animationZoomIn: function (previousZoomLevel, newZoomLevel) { var bounds = this._getExpandedVisibleBounds(), fg = this._featureGroup, i; this._ignoreMove = true; //Add all children of current clusters to map and remove those clusters from map this._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) { var startPos = c._latlng, markers = c._markers, m; if (!bounds.contains(startPos)) { startPos = null; } if (c._isSingleParent() && previousZoomLevel + 1 === newZoomLevel) { //Immediately add the new child and remove us fg.removeLayer(c); c._recursivelyAddChildrenToMap(null, newZoomLevel, bounds); } else { //Fade out old cluster c.clusterHide(); c._recursivelyAddChildrenToMap(startPos, newZoomLevel, bounds); } //Remove all markers that aren't visible any more //TODO: Do we actually need to do this on the higher levels too? for (i = markers.length - 1; i >= 0; i--) { m = markers[i]; if (!bounds.contains(m._latlng)) { fg.removeLayer(m); } } }); this._forceLayout(); //Update opacities this._topClusterLevel._recursivelyBecomeVisible(bounds, newZoomLevel); //TODO Maybe? Update markers in _recursivelyBecomeVisible fg.eachLayer(function (n) { if (!(n instanceof L.MarkerCluster) && n._icon) { n.clusterShow(); } }); //update the positions of the just added clusters/markers this._topClusterLevel._recursively(bounds, previousZoomLevel, newZoomLevel, function (c) { c._recursivelyRestoreChildPositions(newZoomLevel); }); this._ignoreMove = false; //Remove the old clusters and close the zoom animation this._enqueue(function () { //update the positions of the just added clusters/markers this._topClusterLevel._recursively(bounds, previousZoomLevel, 0, function (c) { fg.removeLayer(c); c.clusterShow(); }); this._animationEnd(); }); }, _animationZoomOut: function (previousZoomLevel, newZoomLevel) { this._animationZoomOutSingle(this._topClusterLevel, previousZoomLevel - 1, newZoomLevel); //Need to add markers for those that weren't on the map before but are now this._topClusterLevel._recursivelyAddChildrenToMap(null, newZoomLevel, this._getExpandedVisibleBounds()); //Remove markers that were on the map before but won't be now this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds, previousZoomLevel, this._getExpandedVisibleBounds()); }, _animationAddLayer: function (layer, newCluster) { var me = this, fg = this._featureGroup; fg.addLayer(layer); if (newCluster !== layer) { if (newCluster._childCount > 2) { //Was already a cluster newCluster._updateIcon(); this._forceLayout(); this._animationStart(); layer._setPos(this._map.latLngToLayerPoint(newCluster.getLatLng())); layer.clusterHide(); this._enqueue(function () { fg.removeLayer(layer); layer.clusterShow(); me._animationEnd(); }); } else { //Just became a cluster this._forceLayout(); me._animationStart(); me._animationZoomOutSingle(newCluster, this._map.getMaxZoom(), this._zoom); } } } }, // Private methods for animated versions. _animationZoomOutSingle: function (cluster, previousZoomLevel, newZoomLevel) { var bounds = this._getExpandedVisibleBounds(); //Animate all of the markers in the clusters to move to their cluster center point cluster._recursivelyAnimateChildrenInAndAddSelfToMap(bounds, previousZoomLevel + 1, newZoomLevel); var me = this; //Update the opacity (If we immediately set it they won't animate) this._forceLayout(); cluster._recursivelyBecomeVisible(bounds, newZoomLevel); //TODO: Maybe use the transition timing stuff to make this more reliable //When the animations are done, tidy up this._enqueue(function () { //This cluster stopped being a cluster before the timeout fired if (cluster._childCount === 1) { var m = cluster._markers[0]; //If we were in a cluster animation at the time then the opacity and position of our child could be wrong now, so fix it this._ignoreMove = true; m.setLatLng(m.getLatLng()); this._ignoreMove = false; if (m.clusterShow) { m.clusterShow(); } } else { cluster._recursively(bounds, newZoomLevel, 0, function (c) { c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel + 1); }); } me._animationEnd(); }); }, _animationEnd: function () { if (this._map) { this._map._mapPane.className = this._map._mapPane.className.replace(' leaflet-cluster-anim', ''); } this._inZoomAnimation--; this.fire('animationend'); }, //Force a browser layout of stuff in the map // Should apply the current opacity and location to all elements so we can update them again for an animation _forceLayout: function () { //In my testing this works, infact offsetWidth of any element seems to work. //Could loop all this._layers and do this for each _icon if it stops working L.Util.falseFn(document.body.offsetWidth); } }); L.markerClusterGroup = function (options) { return new L.MarkerClusterGroup(options); }; L.MarkerCluster = L.Marker.extend({ initialize: function (group, zoom, a, b) { L.Marker.prototype.initialize.call(this, a ? (a._cLatLng || a.getLatLng()) : new L.LatLng(0, 0), { icon: this }); this._group = group; this._zoom = zoom; this._markers = []; this._childClusters = []; this._childCount = 0; this._iconNeedsUpdate = true; this._boundsNeedUpdate = true; this._bounds = new L.LatLngBounds(); if (a) { this._addChild(a); } if (b) { this._addChild(b); } }, //Recursively retrieve all child markers of this cluster getAllChildMarkers: function (storageArray) { storageArray = storageArray || []; for (var i = this._childClusters.length - 1; i >= 0; i--) { this._childClusters[i].getAllChildMarkers(storageArray); } for (var j = this._markers.length - 1; j >= 0; j--) { storageArray.push(this._markers[j]); } return storageArray; }, //Returns the count of how many child markers we have getChildCount: function () { return this._childCount; }, //Zoom to the minimum of showing all of the child markers, or the extents of this cluster zoomToBounds: function () { var childClusters = this._childClusters.slice(), map = this._group._map, boundsZoom = map.getBoundsZoom(this._bounds), zoom = this._zoom + 1, mapZoom = map.getZoom(), i; //calculate how far we need to zoom down to see all of the markers while (childClusters.length > 0 && boundsZoom > zoom) { zoom++; var newClusters = []; for (i = 0; i < childClusters.length; i++) { newClusters = newClusters.concat(childClusters[i]._childClusters); } childClusters = newClusters; } if (boundsZoom > zoom) { this._group._map.setView(this._latlng, zoom); } else if (boundsZoom <= mapZoom) { //If fitBounds wouldn't zoom us down, zoom us down instead this._group._map.setView(this._latlng, mapZoom + 1); } else { this._group._map.fitBounds(this._bounds); } }, getBounds: function () { var bounds = new L.LatLngBounds(); bounds.extend(this._bounds); return bounds; }, _updateIcon: function () { this._iconNeedsUpdate = true; if (this._icon) { this.setIcon(this); } }, //Cludge for Icon, we pretend to be an icon for performance createIcon: function () { if (this._iconNeedsUpdate) { this._iconObj = this._group.options.iconCreateFunction(this); this._iconNeedsUpdate = false; } return this._iconObj.createIcon(); }, createShadow: function () { return this._iconObj.createShadow(); }, _addChild: function (new1, isNotificationFromChild) { this._iconNeedsUpdate = true; this._boundsNeedUpdate = true; this._setClusterCenter(new1); if (new1 instanceof L.MarkerCluster) { if (!isNotificationFromChild) { this._childClusters.push(new1); new1.__parent = this; } this._childCount += new1._childCount; } else { if (!isNotificationFromChild) { this._markers.push(new1); } this._childCount++; } if (this.__parent) { this.__parent._addChild(new1, true); } }, /** * Makes sure the cluster center is set. If not, uses the child center if it is a cluster, or the marker position. * @param child L.MarkerCluster|L.Marker that will be used as cluster center if not defined yet. * @private */ _setClusterCenter: function (child) { if (!this._cLatLng) { // when clustering, take position of the first point as the cluster center this._cLatLng = child._cLatLng || child._latlng; } }, /** * Assigns impossible bounding values so that the next extend entirely determines the new bounds. * This method avoids having to trash the previous L.LatLngBounds object and to create a new one, which is much slower for this class. * As long as the bounds are not extended, most other methods would probably fail, as they would with bounds initialized but not extended. * @private */ _resetBounds: function () { var bounds = this._bounds; if (bounds._southWest) { bounds._southWest.lat = Infinity; bounds._southWest.lng = Infinity; } if (bounds._northEast) { bounds._northEast.lat = -Infinity; bounds._northEast.lng = -Infinity; } }, _recalculateBounds: function () { var markers = this._markers, childClusters = this._childClusters, latSum = 0, lngSum = 0, totalCount = this._childCount, i, child, childLatLng, childCount; // Case where all markers are removed from the map and we are left with just an empty _topClusterLevel. if (totalCount === 0) { return; } // Reset rather than creating a new object, for performance. this._resetBounds(); // Child markers. for (i = 0; i < markers.length; i++) { childLatLng = markers[i]._latlng; this._bounds.extend(childLatLng); latSum += childLatLng.lat; lngSum += childLatLng.lng; } // Child clusters. for (i = 0; i < childClusters.length; i++) { child = childClusters[i]; // Re-compute child bounds and weighted position first if necessary. if (child._boundsNeedUpdate) { child._recalculateBounds(); } this._bounds.extend(child._bounds); childLatLng = child._wLatLng; childCount = child._childCount; latSum += childLatLng.lat * childCount; lngSum += childLatLng.lng * childCount; } this._latlng = this._wLatLng = new L.LatLng(latSum / totalCount, lngSum / totalCount); // Reset dirty flag. this._boundsNeedUpdate = false; }, //Set our markers position as given and add it to the map _addToMap: function (startPos) { if (startPos) { this._backupLatlng = this._latlng; this.setLatLng(startPos); } this._group._featureGroup.addLayer(this); if(this.plabel){ if(this.plabel._isOpen){ this.showPlabel(); } } }, _recursivelyAnimateChildrenIn: function (bounds, center, maxZoom) { this._recursively(bounds, 0, maxZoom - 1, function (c) { var markers = c._markers, i, m; for (i = markers.length - 1; i >= 0; i--) { m = markers[i]; //Only do it if the icon is still on the map if (m._icon) { m._setPos(center); m.clusterHide(); } } }, function (c) { var childClusters = c._childClusters, j, cm; for (j = childClusters.length - 1; j >= 0; j--) { cm = childClusters[j]; if (cm._icon) { cm._setPos(center); cm.clusterHide(); } } } ); }, _recursivelyAnimateChildrenInAndAddSelfToMap: function (bounds, previousZoomLevel, newZoomLevel) { this._recursively(bounds, newZoomLevel, 0, function (c) { c._recursivelyAnimateChildrenIn(bounds, c._group._map.latLngToLayerPoint(c.getLatLng()).round(), previousZoomLevel); //TODO: depthToAnimateIn affects _isSingleParent, if there is a multizoom we may/may not be. //As a hack we only do a animation free zoom on a single level zoom, if someone does multiple levels then we always animate if (c._isSingleParent() && previousZoomLevel - 1 === newZoomLevel) { c.clusterShow(); c._recursivelyRemoveChildrenFromMap(bounds, previousZoomLevel); //Immediately remove our children as we are replacing them. TODO previousBounds not bounds } else { c.clusterHide(); } c._addToMap(); } ); }, _recursivelyBecomeVisible: function (bounds, zoomLevel) { this._recursively(bounds, 0, zoomLevel, null, function (c) { c.clusterShow(); }); }, _recursivelyAddChildrenToMap: function (startPos, zoomLevel, bounds) { this._recursively(bounds, -1, zoomLevel, function (c) { if (zoomLevel === c._zoom) { return; } //Add our child markers at startPos (so they can be animated out) for (var i = c._markers.length - 1; i >= 0; i--) { var nm = c._markers[i]; if (!bounds.contains(nm._latlng)) { continue; } if (startPos) { nm._backupLatlng = nm.getLatLng(); nm.setLatLng(startPos); if (nm.clusterHide) { nm.clusterHide(); } } c._group._featureGroup.addLayer(nm); } }, function (c) { c._addToMap(startPos); } ); }, _recursivelyRestoreChildPositions: function (zoomLevel) { //Fix positions of child markers for (var i = this._markers.length - 1; i >= 0; i--) { var nm = this._markers[i]; if (nm._backupLatlng) { nm.setLatLng(nm._backupLatlng); delete nm._backupLatlng; } } if (zoomLevel - 1 === this._zoom) { //Reposition child clusters for (var j = this._childClusters.length - 1; j >= 0; j--) { this._childClusters[j]._restorePosition(); } } else { for (var k = this._childClusters.length - 1; k >= 0; k--) { this._childClusters[k]._recursivelyRestoreChildPositions(zoomLevel); } } }, _restorePosition: function () { if (this._backupLatlng) { this.setLatLng(this._backupLatlng); delete this._backupLatlng; } }, //exceptBounds: If set, don't remove any markers/clusters in it _recursivelyRemoveChildrenFromMap: function (previousBounds, zoomLevel, exceptBounds) { var m, i; this._recursively(previousBounds, -1, zoomLevel - 1, function (c) { //Remove markers at every level for (i = c._markers.length - 1; i >= 0; i--) { m = c._markers[i]; if (!exceptBounds || !exceptBounds.contains(m._latlng)) { c._group._featureGroup.removeLayer(m); if (m.clusterShow) { m.clusterShow(); } } } }, function (c) { //Remove child clusters at just the bottom level for (i = c._childClusters.length - 1; i >= 0; i--) { m = c._childClusters[i]; if (!exceptBounds || !exceptBounds.contains(m._latlng)) { c._group._featureGroup.removeLayer(m); if (m.clusterShow) { m.clusterShow(); } } } } ); }, //Run the given functions recursively to this and child clusters // boundsToApplyTo: a L.LatLngBounds representing the bounds of what clusters to recurse in to // zoomLevelToStart: zoom level to start running functions (inclusive) // zoomLevelToStop: zoom level to stop running functions (inclusive) // runAtEveryLevel: function that takes an L.MarkerCluster as an argument that should be applied on every level // runAtBottomLevel: function that takes an L.MarkerCluster as an argument that should be applied at only the bottom level _recursively: function (boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel) { var childClusters = this._childClusters, zoom = this._zoom, i, c; if (zoomLevelToStart <= zoom) { if (runAtEveryLevel) { runAtEveryLevel(this); } if (runAtBottomLevel && zoom === zoomLevelToStop) { runAtBottomLevel(this); } } if (zoom < zoomLevelToStart || zoom < zoomLevelToStop) { for (i = childClusters.length - 1; i >= 0; i--) { c = childClusters[i]; if (boundsToApplyTo.intersects(c._bounds)) { c._recursively(boundsToApplyTo, zoomLevelToStart, zoomLevelToStop, runAtEveryLevel, runAtBottomLevel); } } } }, //Returns true if we are the parent of only one cluster and that cluster is the same as us _isSingleParent: function () { //Don't need to check this._markers as the rest won't work if there are any return this._childClusters.length > 0 && this._childClusters[0]._childCount === this._childCount; } }); /* * Extends L.Marker to include two extra methods: clusterHide and clusterShow. * * They work as setOpacity(0) and setOpacity(1) respectively, but * they will remember the marker's opacity when hiding and showing it again. * */ L.Marker.include({ clusterHide: function () { this.options.opacityWhenUnclustered = this.options.opacity || 1; return this.setOpacity(0); }, clusterShow: function () { var ret = this.setOpacity(this.options.opacity || this.options.opacityWhenUnclustered); delete this.options.opacityWhenUnclustered; return ret; } }); L.DistanceGrid = function (cellSize) { this._cellSize = cellSize; this._sqCellSize = cellSize * cellSize; this._grid = {}; this._objectPoint = { }; }; L.DistanceGrid.prototype = { addObject: function (obj, point) { var x = this._getCoord(point.x), y = this._getCoord(point.y), grid = this._grid, row = grid[y] = grid[y] || {}, cell = row[x] = row[x] || [], stamp = L.Util.stamp(obj); this._objectPoint[stamp] = point; cell.push(obj); }, updateObject: function (obj, point) { this.removeObject(obj); this.addObject(obj, point); }, //Returns true if the object was found removeObject: function (obj, point) { var x = this._getCoord(point.x), y = this._getCoord(point.y), grid = this._grid, row = grid[y] = grid[y] || {}, cell = row[x] = row[x] || [], i, len; delete this._objectPoint[L.Util.stamp(obj)]; for (i = 0, len = cell.length; i < len; i++) { if (cell[i] === obj) { cell.splice(i, 1); if (len === 1) { delete row[x]; } return true; } } }, eachObject: function (fn, context) { var i, j, k, len, row, cell, removed, grid = this._grid; for (i in grid) { row = grid[i]; for (j in row) { cell = row[j]; for (k = 0, len = cell.length; k < len; k++) { removed = fn.call(context, cell[k]); if (removed) { k--; len--; } } } } }, getNearObject: function (point) { var x = this._getCoord(point.x), y = this._getCoord(point.y), i, j, k, row, cell, len, obj, dist, objectPoint = this._objectPoint, closestDistSq = this._sqCellSize, closest = null; for (i = y - 1; i <= y + 1; i++) { row = this._grid[i]; if (row) { for (j = x - 1; j <= x + 1; j++) { cell = row[j]; if (cell) { for (k = 0, len = cell.length; k < len; k++) { obj = cell[k]; dist = this._sqDist(objectPoint[L.Util.stamp(obj)], point); if (dist < closestDistSq) { closestDistSq = dist; closest = obj; } } } } } } return closest; }, _getCoord: function (x) { return Math.floor(x / this._cellSize); }, _sqDist: function (p, p2) { var dx = p2.x - p.x, dy = p2.y - p.y; return dx * dx + dy * dy; } }; /* Copyright (c) 2012 the authors listed at the following URL, and/or the authors of referenced articles or incorporated external code: http://en.literateprograms.org/Quickhull_(Javascript)?action=history&offset=20120410175256 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Retrieved from: http://en.literateprograms.org/Quickhull_(Javascript)?oldid=18434 */ (function () { L.QuickHull = { /* * @param {Object} cpt a point to be measured from the baseline * @param {Array} bl the baseline, as represented by a two-element * array of latlng objects. * @returns {Number} an approximate distance measure */ getDistant: function (cpt, bl) { var vY = bl[1].lat - bl[0].lat, vX = bl[0].lng - bl[1].lng; return (vX * (cpt.lat - bl[0].lat) + vY * (cpt.lng - bl[0].lng)); }, /* * @param {Array} baseLine a two-element array of latlng objects * representing the baseline to project from * @param {Array} latLngs an array of latlng objects * @returns {Object} the maximum point and all new points to stay * in consideration for the hull. */ findMostDistantPointFromBaseLine: function (baseLine, latLngs) { var maxD = 0, maxPt = null, newPoints = [], i, pt, d; for (i = latLngs.length - 1; i >= 0; i--) { pt = latLngs[i]; d = this.getDistant(pt, baseLine); if (d > 0) { newPoints.push(pt); } else { continue; } if (d > maxD) { maxD = d; maxPt = pt; } } return { maxPoint: maxPt, newPoints: newPoints }; }, /* * Given a baseline, compute the convex hull of latLngs as an array * of latLngs. * * @param {Array} latLngs * @returns {Array} */ buildConvexHull: function (baseLine, latLngs) { var convexHullBaseLines = [], t = this.findMostDistantPointFromBaseLine(baseLine, latLngs); if (t.maxPoint) { // if there is still a point "outside" the base line convexHullBaseLines = convexHullBaseLines.concat( this.buildConvexHull([baseLine[0], t.maxPoint], t.newPoints) ); convexHullBaseLines = convexHullBaseLines.concat( this.buildConvexHull([t.maxPoint, baseLine[1]], t.newPoints) ); return convexHullBaseLines; } else { // if there is no more point "outside" the base line, the current base line is part of the convex hull return [baseLine[0]]; } }, /* * Given an array of latlngs, compute a convex hull as an array * of latlngs * * @param {Array} latLngs * @returns {Array} */ getConvexHull: function (latLngs) { // find first baseline var maxLat = false, minLat = false, maxLng = false, minLng = false, maxLatPt = null, minLatPt = null, maxLngPt = null, minLngPt = null, maxPt = null, minPt = null, i; for (i = latLngs.length - 1; i >= 0; i--) { var pt = latLngs[i]; if (maxLat === false || pt.lat > maxLat) { maxLatPt = pt; maxLat = pt.lat; } if (minLat === false || pt.lat < minLat) { minLatPt = pt; minLat = pt.lat; } if (maxLng === false || pt.lng > maxLng) { maxLngPt = pt; maxLng = pt.lng; } if (minLng === false || pt.lng < minLng) { minLngPt = pt; minLng = pt.lng; } } if (minLat !== maxLat) { minPt = minLatPt; maxPt = maxLatPt; } else { minPt = minLngPt; maxPt = maxLngPt; } var ch = [].concat(this.buildConvexHull([minPt, maxPt], latLngs), this.buildConvexHull([maxPt, minPt], latLngs)); return ch; } }; }()); L.MarkerCluster.include({ getConvexHull: function () { var childMarkers = this.getAllChildMarkers(), points = [], p, i; for (i = childMarkers.length - 1; i >= 0; i--) { p = childMarkers[i].getLatLng(); points.push(p); } return L.QuickHull.getConvexHull(points); } }); //This code is 100% based on https://github.com/jawj/OverlappingMarkerSpiderfier-Leaflet //Huge thanks to jawj for implementing it first to make my job easy :-) L.MarkerCluster.include({ _2PI: Math.PI * 2, _circleFootSeparation: 25, //related to circumference of circle _circleStartAngle: Math.PI / 6, _spiralFootSeparation: 28, //related to size of spiral (experiment!) _spiralLengthStart: 11, _spiralLengthFactor: 5, _circleSpiralSwitchover: 9, //show spiral instead of circle from this marker count upwards. // 0 -> always spiral; Infinity -> always circle spiderfy: function () { if (this._group._spiderfied === this || this._group._inZoomAnimation) { return; } var childMarkers = this.getAllChildMarkers(), group = this._group, map = group._map, center = map.latLngToLayerPoint(this._latlng), positions; this._group._unspiderfy(); this._group._spiderfied = this; //TODO Maybe: childMarkers order by distance to center if (childMarkers.length >= this._circleSpiralSwitchover) { positions = this._generatePointsSpiral(childMarkers.length, center); } else { center.y += 10; // Otherwise circles look wrong => hack for standard blue icon, renders differently for other icons. positions = this._generatePointsCircle(childMarkers.length, center); } this._animationSpiderfy(childMarkers, positions); }, unspiderfy: function (zoomDetails) { /// Argument from zoomanim if being called in a zoom animation or null otherwise if (this._group._inZoomAnimation) { return; } this._animationUnspiderfy(zoomDetails); this._group._spiderfied = null; }, _generatePointsCircle: function (count, centerPt) { var circumference = this._group.options.spiderfyDistanceMultiplier * this._circleFootSeparation * (2 + count), legLength = circumference / this._2PI, //radius from circumference angleStep = this._2PI / count, res = [], i, angle; res.length = count; for (i = count - 1; i >= 0; i--) { angle = this._circleStartAngle + i * angleStep; res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round(); } return res; }, _generatePointsSpiral: function (count, centerPt) { var spiderfyDistanceMultiplier = this._group.options.spiderfyDistanceMultiplier, legLength = spiderfyDistanceMultiplier * this._spiralLengthStart, separation = spiderfyDistanceMultiplier * this._spiralFootSeparation, lengthFactor = spiderfyDistanceMultiplier * this._spiralLengthFactor * this._2PI, angle = 0, res = [], i; res.length = count; // Higher index, closer position to cluster center. for (i = count - 1; i >= 0; i--) { angle += separation / legLength + i * 0.0005; res[i] = new L.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle))._round(); legLength += lengthFactor / angle; } return res; }, _noanimationUnspiderfy: function () { var group = this._group, map = group._map, fg = group._featureGroup, childMarkers = this.getAllChildMarkers(), m, i; group._ignoreMove = true; this.setOpacity(1); for (i = childMarkers.length - 1; i >= 0; i--) { m = childMarkers[i]; fg.removeLayer(m); if (m._preSpiderfyLatlng) { m.setLatLng(m._preSpiderfyLatlng); delete m._preSpiderfyLatlng; } if (m.setZIndexOffset) { m.setZIndexOffset(0); } if (m._spiderLeg) { map.removeLayer(m._spiderLeg); delete m._spiderLeg; } } group.fire('unspiderfied', { cluster: this, markers: childMarkers }); group._ignoreMove = false; group._spiderfied = null; } }); //Non Animated versions of everything L.MarkerClusterNonAnimated = L.MarkerCluster.extend({ _animationSpiderfy: function (childMarkers, positions) { var group = this._group, map = group._map, fg = group._featureGroup, legOptions = this._group.options.spiderLegPolylineOptions, i, m, leg, newPos; group._ignoreMove = true; // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition. // The reverse order trick no longer improves performance on modern browsers. for (i = 0; i < childMarkers.length; i++) { newPos = map.layerPointToLatLng(positions[i]); m = childMarkers[i]; // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it. leg = new L.Polyline([this._latlng, newPos], legOptions); map.addLayer(leg); m._spiderLeg = leg; // Now add the marker. m._preSpiderfyLatlng = m._latlng; m.setLatLng(newPos); if (m.setZIndexOffset) { m.setZIndexOffset(1000000); //Make these appear on top of EVERYTHING } fg.addLayer(m); } this.setOpacity(0.3); group._ignoreMove = false; group.fire('spiderfied', { cluster: this, markers: childMarkers }); }, _animationUnspiderfy: function () { this._noanimationUnspiderfy(); } }); //Animated versions here L.MarkerCluster.include({ _animationSpiderfy: function (childMarkers, positions) { var me = this, group = this._group, map = group._map, fg = group._featureGroup, thisLayerLatLng = this._latlng, thisLayerPos = map.latLngToLayerPoint(thisLayerLatLng), svg = L.Path.SVG, legOptions = L.extend({}, this._group.options.spiderLegPolylineOptions), // Copy the options so that we can modify them for animation. finalLegOpacity = legOptions.opacity, i, m, leg, legPath, legLength, newPos; if (finalLegOpacity === undefined) { finalLegOpacity = L.MarkerClusterGroup.prototype.options.spiderLegPolylineOptions.opacity; } if (svg) { // If the initial opacity of the spider leg is not 0 then it appears before the animation starts. legOptions.opacity = 0; // Add the class for CSS transitions. legOptions.className = (legOptions.className || '') + ' leaflet-cluster-spider-leg'; } else { // Make sure we have a defined opacity. legOptions.opacity = finalLegOpacity; } group._ignoreMove = true; // Add markers and spider legs to map, hidden at our center point. // Traverse in ascending order to make sure that inner circleMarkers are on top of further legs. Normal markers are re-ordered by newPosition. // The reverse order trick no longer improves performance on modern browsers. for (i = 0; i < childMarkers.length; i++) { m = childMarkers[i]; newPos = map.layerPointToLatLng(positions[i]); // Add the leg before the marker, so that in case the latter is a circleMarker, the leg is behind it. leg = new L.Polyline([thisLayerLatLng, newPos], legOptions); map.addLayer(leg); m._spiderLeg = leg; // Explanations: https://jakearchibald.com/2013/animated-line-drawing-svg/ // In our case the transition property is declared in the CSS file. if (svg) { legPath = leg._path; legLength = legPath.getTotalLength() + 0.1; // Need a small extra length to avoid remaining dot in Firefox. legPath.style.strokeDasharray = legLength; // Just 1 length is enough, it will be duplicated. legPath.style.strokeDashoffset = legLength; } // If it is a marker, add it now and we'll animate it out if (m.setZIndexOffset) { m.setZIndexOffset(1000000); // Make normal markers appear on top of EVERYTHING } if (m.clusterHide) { m.clusterHide(); } // Vectors just get immediately added fg.addLayer(m); if (m._setPos) { m._setPos(thisLayerPos); } } group._forceLayout(); group._animationStart(); // Reveal markers and spider legs. for (i = childMarkers.length - 1; i >= 0; i--) { newPos = map.layerPointToLatLng(positions[i]); m = childMarkers[i]; //Move marker to new position m._preSpiderfyLatlng = m._latlng; m.setLatLng(newPos); if (m.clusterShow) { m.clusterShow(); } // Animate leg (animation is actually delegated to CSS transition). if (svg) { leg = m._spiderLeg; legPath = leg._path; legPath.style.strokeDashoffset = 0; //legPath.style.strokeOpacity = finalLegOpacity; leg.setStyle({opacity: finalLegOpacity}); } } this.setOpacity(0.3); group._ignoreMove = false; setTimeout(function () { group._animationEnd(); group.fire('spiderfied', { cluster: me, markers: childMarkers }); }, 200); }, _animationUnspiderfy: function (zoomDetails) { var me = this, group = this._group, map = group._map, fg = group._featureGroup, thisLayerPos = zoomDetails ? map._latLngToNewLayerPoint(this._latlng, zoomDetails.zoom, zoomDetails.center) : map.latLngToLayerPoint(this._latlng), childMarkers = this.getAllChildMarkers(), svg = L.Path.SVG, m, i, leg, legPath, legLength, nonAnimatable; group._ignoreMove = true; group._animationStart(); //Make us visible and bring the child markers back in this.setOpacity(1); for (i = childMarkers.length - 1; i >= 0; i--) { m = childMarkers[i]; //Marker was added to us after we were spiderfied if (!m._preSpiderfyLatlng) { continue; } //Fix up the location to the real one m.setLatLng(m._preSpiderfyLatlng); delete m._preSpiderfyLatlng; //Hack override the location to be our center nonAnimatable = true; if (m._setPos) { m._setPos(thisLayerPos); nonAnimatable = false; } if (m.clusterHide) { m.clusterHide(); nonAnimatable = false; } if (nonAnimatable) { fg.removeLayer(m); } // Animate the spider leg back in (animation is actually delegated to CSS transition). if (svg) { leg = m._spiderLeg; legPath = leg._path; legLength = legPath.getTotalLength() + 0.1; legPath.style.strokeDashoffset = legLength; leg.setStyle({opacity: 0}); } } group._ignoreMove = false; setTimeout(function () { //If we have only <= one child left then that marker will be shown on the map so don't remove it! var stillThereChildCount = 0; for (i = childMarkers.length - 1; i >= 0; i--) { m = childMarkers[i]; if (m._spiderLeg) { stillThereChildCount++; } } for (i = childMarkers.length - 1; i >= 0; i--) { m = childMarkers[i]; if (!m._spiderLeg) { //Has already been unspiderfied continue; } if (m.clusterShow) { m.clusterShow(); } if (m.setZIndexOffset) { m.setZIndexOffset(0); } if (stillThereChildCount > 1) { fg.removeLayer(m); } map.removeLayer(m._spiderLeg); delete m._spiderLeg; } group._animationEnd(); group.fire('unspiderfied', { cluster: me, markers: childMarkers }); }, 200); } }); L.MarkerClusterGroup.include({ //The MarkerCluster currently spiderfied (if any) _spiderfied: null, unspiderfy: function () { this._unspiderfy.apply(this, arguments); }, _spiderfierOnAdd: function () { this._map.on('click', this._unspiderfyWrapper, this); if (this._map.options.zoomAnimation) { this._map.on('zoomstart', this._unspiderfyZoomStart, this); } //Browsers without zoomAnimation or a big zoom don't fire zoomstart this._map.on('zoomend', this._noanimationUnspiderfy, this); if (!L.Browser.touch) { this._map.getRenderer(this); //Needs to happen in the pageload, not after, or animations don't work in webkit // http://stackoverflow.com/questions/8455200/svg-animate-with-dynamically-added-elements //Disable on touch browsers as the animation messes up on a touch zoom and isn't very noticable } }, _spiderfierOnRemove: function () { this._map.off('click', this._unspiderfyWrapper, this); this._map.off('zoomstart', this._unspiderfyZoomStart, this); this._map.off('zoomanim', this._unspiderfyZoomAnim, this); this._map.off('zoomend', this._noanimationUnspiderfy, this); //Ensure that markers are back where they should be // Use no animation to avoid a sticky leaflet-cluster-anim class on mapPane this._noanimationUnspiderfy(); }, //On zoom start we add a zoomanim handler so that we are guaranteed to be last (after markers are animated) //This means we can define the animation they do rather than Markers doing an animation to their actual location _unspiderfyZoomStart: function () { if (!this._map) { //May have been removed from the map by a zoomEnd handler return; } this._map.on('zoomanim', this._unspiderfyZoomAnim, this); }, _unspiderfyZoomAnim: function (zoomDetails) { //Wait until the first zoomanim after the user has finished touch-zooming before running the animation if (L.DomUtil.hasClass(this._map._mapPane, 'leaflet-touching')) { return; } this._map.off('zoomanim', this._unspiderfyZoomAnim, this); this._unspiderfy(zoomDetails); }, _unspiderfyWrapper: function () { /// _unspiderfy but passes no arguments this._unspiderfy(); }, _unspiderfy: function (zoomDetails) { if (this._spiderfied) { this._spiderfied.unspiderfy(zoomDetails); } }, _noanimationUnspiderfy: function () { if (this._spiderfied) { this._spiderfied._noanimationUnspiderfy(); } }, //If the given layer is currently being spiderfied then we unspiderfy it so it isn't on the map anymore etc _unspiderfyLayer: function (layer) { if (layer._spiderLeg) { this._featureGroup.removeLayer(layer); if (layer.clusterShow) { layer.clusterShow(); } //Position will be fixed up immediately in _animationUnspiderfy if (layer.setZIndexOffset) { layer.setZIndexOffset(0); } this._map.removeLayer(layer._spiderLeg); delete layer._spiderLeg; } } }); /** * Adds 1 public method to MCG and 1 to L.Marker to facilitate changing * markers' icon options and refreshing their icon and their parent clusters * accordingly (case where their iconCreateFunction uses data of childMarkers * to make up the cluster icon). */ L.MarkerClusterGroup.include({ /** * Updates the icon of all clusters which are parents of the given marker(s). * In singleMarkerMode, also updates the given marker(s) icon. * @param layers L.MarkerClusterGroup|L.LayerGroup|Array(L.Marker)|Map(L.Marker)| * L.MarkerCluster|L.Marker (optional) list of markers (or single marker) whose parent * clusters need to be updated. If not provided, retrieves all child markers of this. * @returns {L.MarkerClusterGroup} */ refreshClusters: function (layers) { if (!layers) { layers = this._topClusterLevel.getAllChildMarkers(); } else if (layers instanceof L.MarkerClusterGroup) { layers = layers._topClusterLevel.getAllChildMarkers(); } else if (layers instanceof L.LayerGroup) { layers = layers._layers; } else if (layers instanceof L.MarkerCluster) { layers = layers.getAllChildMarkers(); } else if (layers instanceof L.Marker) { layers = [layers]; } // else: must be an Array(L.Marker)|Map(L.Marker) this._flagParentsIconsNeedUpdate(layers); this._refreshClustersIcons(); // In case of singleMarkerMode, also re-draw the markers. if (this.options.singleMarkerMode) { this._refreshSingleMarkerModeMarkers(layers); } return this; }, /** * Simply flags all parent clusters of the given markers as having a "dirty" icon. * @param layers Array(L.Marker)|Map(L.Marker) list of markers. * @private */ _flagParentsIconsNeedUpdate: function (layers) { var id, parent; // Assumes layers is an Array or an Object whose prototype is non-enumerable. for (id in layers) { // Flag parent clusters' icon as "dirty", all the way up. // Dumb process that flags multiple times upper parents, but still // much more efficient than trying to be smart and make short lists, // at least in the case of a hierarchy following a power law: // http://jsperf.com/flag-nodes-in-power-hierarchy/2 parent = layers[id].__parent; while (parent) { parent._iconNeedsUpdate = true; parent = parent.__parent; } } }, /** * Re-draws the icon of the supplied markers. * To be used in singleMarkerMode only. * @param layers Array(L.Marker)|Map(L.Marker) list of markers. * @private */ _refreshSingleMarkerModeMarkers: function (layers) { var id, layer; for (id in layers) { layer = layers[id]; // Make sure we do not override markers that do not belong to THIS group. if (this.hasLayer(layer)) { // Need to re-create the icon first, then re-draw the marker. layer.setIcon(this._overrideMarkerIcon(layer)); } } } }); L.Marker.include({ /** * Updates the given options in the marker's icon and refreshes the marker. * @param options map object of icon options. * @param directlyRefreshClusters boolean (optional) true to trigger * MCG.refreshClustersOf() right away with this single marker. * @returns {L.Marker} */ refreshIconOptions: function (options, directlyRefreshClusters) { var icon = this.options.icon; L.setOptions(icon, options); this.setIcon(icon); // Shortcut to refresh the associated MCG clusters right away. // To be used when refreshing a single marker. // Otherwise, better use MCG.refreshClusters() once at the end with // the list of modified markers. if (directlyRefreshClusters && this.__parent) { this.__parent._group.refreshClusters(this); } return this; } }); }(window, document)); 'use strict'; (function (factory, window) { /*globals define, module, require*/ // define an AMD module that relies on 'leaflet' if (typeof define === 'function' && define.amd) { define(['leaflet'], factory); // define a Common JS module that relies on 'leaflet' } else if (typeof exports === 'object') { module.exports = factory(require('leaflet')); } // attach your plugin to the global 'L' variable if(typeof window !== 'undefined' && window.L){ factory(window.L); } }(function (L) { // 🍂miniclass CancelableEvent (Event objects) // 🍂method cancel() // Cancel any subsequent action. // 🍂miniclass VertexEvent (Event objects) // 🍂property vertex: VertexMarker // The vertex that fires the event. // 🍂miniclass ShapeEvent (Event objects) // 🍂property shape: Array // The shape (LatLngs array) subject of the action. // 🍂miniclass CancelableVertexEvent (Event objects) // 🍂inherits VertexEvent // 🍂inherits CancelableEvent // 🍂miniclass CancelableShapeEvent (Event objects) // 🍂inherits ShapeEvent // 🍂inherits CancelableEvent // 🍂miniclass LayerEvent (Event objects) // 🍂property layer: object // The Layer (Marker, Polyline…) subject of the action. // 🍂namespace Editable; 🍂class Editable; 🍂aka L.Editable // Main edition handler. By default, it is attached to the map // as `map.editTools` property. // Leaflet.Editable is made to be fully extendable. You have three ways to customize // the behaviour: using options, listening to events, or extending. L.Editable = L.Evented.extend({ statics: { FORWARD: 1, BACKWARD: -1 }, options: { // You can pass them when creating a map using the `editOptions` key. // 🍂option zIndex: int = 1000 // The default zIndex of the editing tools. zIndex: 1000, // 🍂option polygonClass: class = L.Polygon // Class to be used when creating a new Polygon. polygonClass: L.Polygon, // 🍂option polylineClass: class = L.Polyline // Class to be used when creating a new Polyline. polylineClass: L.Polyline, // 🍂option markerClass: class = L.Marker // Class to be used when creating a new Marker. markerClass: L.Marker, // 🍂option rectangleClass: class = L.Rectangle // Class to be used when creating a new Rectangle. rectangleClass: L.Rectangle, // 🍂option circleClass: class = L.Circle // Class to be used when creating a new Circle. circleClass: L.Circle, // 🍂option drawingCSSClass: string = 'leaflet-editable-drawing' // CSS class to be added to the map container while drawing. drawingCSSClass: 'leaflet-editable-drawing', // 🍂option drawingCursor: const = 'crosshair' // Cursor mode set to the map while drawing. drawingCursor: 'crosshair', // 🍂option editLayer: Layer = new L.LayerGroup() // Layer used to store edit tools (vertex, line guide…). editLayer: undefined, // 🍂option featuresLayer: Layer = new L.LayerGroup() // Default layer used to store drawn features (Marker, Polyline…). featuresLayer: undefined, // 🍂option polylineEditorClass: class = PolylineEditor // Class to be used as Polyline editor. polylineEditorClass: undefined, // 🍂option polygonEditorClass: class = PolygonEditor // Class to be used as Polygon editor. polygonEditorClass: undefined, // 🍂option markerEditorClass: class = MarkerEditor // Class to be used as Marker editor. markerEditorClass: undefined, // 🍂option rectangleEditorClass: class = RectangleEditor // Class to be used as Rectangle editor. rectangleEditorClass: undefined, // 🍂option circleEditorClass: class = CircleEditor // Class to be used as Circle editor. circleEditorClass: undefined, // 🍂option lineGuideOptions: hash = {} // Options to be passed to the line guides. lineGuideOptions: {}, // 🍂option skipMiddleMarkers: boolean = false // Set this to true if you don't want middle markers. skipMiddleMarkers: false }, initialize: function (map, options) { L.setOptions(this, options); this._lastZIndex = this.options.zIndex; this.map = map; this.editLayer = this.createEditLayer(); this.featuresLayer = this.createFeaturesLayer(); this.forwardLineGuide = this.createLineGuide(); this.backwardLineGuide = this.createLineGuide(); }, fireAndForward: function (type, e) { e = e || {}; e.editTools = this; this.fire(type, e); this.map.fire(type, e); }, createLineGuide: function () { var options = L.extend({dashArray: '5,10', weight: 1, interactive: false}, this.options.lineGuideOptions); return L.polyline([], options); }, createVertexIcon: function (options) { return L.Browser.touch ? new L.Editable.TouchVertexIcon(options) : new L.Editable.VertexIcon(options); }, createEditLayer: function () { return this.options.editLayer || new L.LayerGroup().addTo(this.map); }, createFeaturesLayer: function () { return this.options.featuresLayer || new L.LayerGroup().addTo(this.map); }, moveForwardLineGuide: function (latlng) { if (this.forwardLineGuide._latlngs.length) { this.forwardLineGuide._latlngs[1] = latlng; this.forwardLineGuide._bounds.extend(latlng); this.forwardLineGuide.redraw(); } }, moveBackwardLineGuide: function (latlng) { if (this.backwardLineGuide._latlngs.length) { this.backwardLineGuide._latlngs[1] = latlng; this.backwardLineGuide._bounds.extend(latlng); this.backwardLineGuide.redraw(); } }, anchorForwardLineGuide: function (latlng) { this.forwardLineGuide._latlngs[0] = latlng; this.forwardLineGuide._bounds.extend(latlng); this.forwardLineGuide.redraw(); }, anchorBackwardLineGuide: function (latlng) { this.backwardLineGuide._latlngs[0] = latlng; this.backwardLineGuide._bounds.extend(latlng); this.backwardLineGuide.redraw(); }, attachForwardLineGuide: function () { this.editLayer.addLayer(this.forwardLineGuide); }, attachBackwardLineGuide: function () { this.editLayer.addLayer(this.backwardLineGuide); }, detachForwardLineGuide: function () { this.forwardLineGuide.setLatLngs([]); this.editLayer.removeLayer(this.forwardLineGuide); }, detachBackwardLineGuide: function () { this.backwardLineGuide.setLatLngs([]); this.editLayer.removeLayer(this.backwardLineGuide); }, blockEvents: function () { // Hack: force map not to listen to other layers events while drawing. if (!this._oldTargets) { this._oldTargets = this.map._targets; this.map._targets = {}; } }, unblockEvents: function () { if (this._oldTargets) { // Reset, but keep targets created while drawing. this.map._targets = L.extend(this.map._targets, this._oldTargets); delete this._oldTargets; } }, registerForDrawing: function (editor) { if (this._drawingEditor) this.unregisterForDrawing(this._drawingEditor); this.blockEvents(); editor.reset(); // Make sure editor tools still receive events. this._drawingEditor = editor; this.map.on('mousemove touchmove', editor.onDrawingMouseMove, editor); this.map.on('mousedown', this.onMousedown, this); this.map.on('mouseup', this.onMouseup, this); L.DomUtil.addClass(this.map._container, this.options.drawingCSSClass); this.defaultMapCursor = this.map._container.style.cursor; this.map._container.style.cursor = this.options.drawingCursor; }, unregisterForDrawing: function (editor) { this.unblockEvents(); L.DomUtil.removeClass(this.map._container, this.options.drawingCSSClass); this.map._container.style.cursor = this.defaultMapCursor; editor = editor || this._drawingEditor; if (!editor) return; this.map.off('mousemove touchmove', editor.onDrawingMouseMove, editor); this.map.off('mousedown', this.onMousedown, this); this.map.off('mouseup', this.onMouseup, this); if (editor !== this._drawingEditor) return; delete this._drawingEditor; if (editor._drawing) editor.cancelDrawing(); }, onMousedown: function (e) { this._mouseDown = e; this._drawingEditor.onDrawingMouseDown(e); }, onMouseup: function (e) { if (this._mouseDown) { var editor = this._drawingEditor, mouseDown = this._mouseDown; this._mouseDown = null; editor.onDrawingMouseUp(e); if (this._drawingEditor !== editor) return; // onDrawingMouseUp may call unregisterFromDrawing. var origin = L.point(mouseDown.originalEvent.clientX, mouseDown.originalEvent.clientY); var distance = L.point(e.originalEvent.clientX, e.originalEvent.clientY).distanceTo(origin); if (Math.abs(distance) < 9 * (window.devicePixelRatio || 1)) this._drawingEditor.onDrawingClick(e); } }, // 🍂section Public methods // You will generally access them by the `map.editTools` // instance: // // `map.editTools.startPolyline();` // 🍂method drawing(): boolean // Return true if any drawing action is ongoing. drawing: function () { return this._drawingEditor && this._drawingEditor.drawing(); }, // 🍂method stopDrawing() // When you need to stop any ongoing drawing, without needing to know which editor is active. stopDrawing: function () { this.unregisterForDrawing(); }, // 🍂method commitDrawing() // When you need to commit any ongoing drawing, without needing to know which editor is active. commitDrawing: function (e) { if (!this._drawingEditor) return; this._drawingEditor.commitDrawing(e); }, connectCreatedToMap: function (layer) { return this.featuresLayer.addLayer(layer); }, // 🍂method startPolyline(latlng: L.LatLng, options: hash): L.Polyline // Start drawing a Polyline. If `latlng` is given, a first point will be added. In any case, continuing on user click. // If `options` is given, it will be passed to the Polyline class constructor. startPolyline: function (latlng, options) { var line = this.createPolyline([], options); line.enableEdit(this.map).newShape(latlng); return line; }, // 🍂method startPolygon(latlng: L.LatLng, options: hash): L.Polygon // Start drawing a Polygon. If `latlng` is given, a first point will be added. In any case, continuing on user click. // If `options` is given, it will be passed to the Polygon class constructor. startPolygon: function (latlng, options) { var polygon = this.createPolygon([], options); polygon.enableEdit(this.map).newShape(latlng); return polygon; }, // 🍂method startMarker(latlng: L.LatLng, options: hash): L.Marker // Start adding a Marker. If `latlng` is given, the Marker will be shown first at this point. // In any case, it will follow the user mouse, and will have a final `latlng` on next click (or touch). // If `options` is given, it will be passed to the Marker class constructor. startMarker: function (latlng, options) { latlng = latlng || this.map.getCenter().clone(); var marker = this.createMarker(latlng, options); marker.enableEdit(this.map).startDrawing(); return marker; }, // 🍂method startRectangle(latlng: L.LatLng, options: hash): L.Rectangle // Start drawing a Rectangle. If `latlng` is given, the Rectangle anchor will be added. In any case, continuing on user drag. // If `options` is given, it will be passed to the Rectangle class constructor. startRectangle: function(latlng, options) { var corner = latlng || L.latLng([0, 0]); var bounds = new L.LatLngBounds(corner, corner); var rectangle = this.createRectangle(bounds, options); rectangle.enableEdit(this.map).startDrawing(); return rectangle; }, // 🍂method startCircle(latlng: L.LatLng, options: hash): L.Circle // Start drawing a Circle. If `latlng` is given, the Circle anchor will be added. In any case, continuing on user drag. // If `options` is given, it will be passed to the Circle class constructor. startCircle: function (latlng, options) { latlng = latlng || this.map.getCenter().clone(); var circle = this.createCircle(latlng, options); circle.enableEdit(this.map).startDrawing(); return circle; }, startHole: function (editor, latlng) { editor.newHole(latlng); }, createLayer: function (klass, latlngs, options) { options = L.Util.extend({editOptions: {editTools: this}}, options); var layer = new klass(latlngs, options); // 🍂namespace Editable // 🍂event editable:created: LayerEvent // Fired when a new feature (Marker, Polyline…) is created. this.fireAndForward('editable:created', {layer: layer}); return layer; }, createPolyline: function (latlngs, options) { return this.createLayer(options && options.polylineClass || this.options.polylineClass, latlngs, options); }, createPolygon: function (latlngs, options) { return this.createLayer(options && options.polygonClass || this.options.polygonClass, latlngs, options); }, createMarker: function (latlng, options) { return this.createLayer(options && options.markerClass || this.options.markerClass, latlng, options); }, createRectangle: function (bounds, options) { return this.createLayer(options && options.rectangleClass || this.options.rectangleClass, bounds, options); }, createCircle: function (latlng, options) { return this.createLayer(options && options.circleClass || this.options.circleClass, latlng, options); } }); L.extend(L.Editable, { makeCancellable: function (e) { e.cancel = function () { e._cancelled = true; }; } }); // 🍂namespace Map; 🍂class Map // Leaflet.Editable add options and events to the `L.Map` object. // See `Editable` events for the list of events fired on the Map. // 🍂example // // ```js // var map = L.map('map', { // editable: true, // editOptions: { // … // } // }); // ``` // 🍂section Editable Map Options L.Map.mergeOptions({ // 🍂namespace Map // 🍂section Map Options // 🍂option editToolsClass: class = L.Editable // Class to be used as vertex, for path editing. editToolsClass: L.Editable, // 🍂option editable: boolean = false // Whether to create a L.Editable instance at map init. editable: false, // 🍂option editOptions: hash = {} // Options to pass to L.Editable when instanciating. editOptions: {} }); L.Map.addInitHook(function () { this.whenReady(function () { if (this.options.editable) { this.editTools = new this.options.editToolsClass(this, this.options.editOptions); } }); }); L.Editable.VertexIcon = L.DivIcon.extend({ options: { iconSize: new L.Point(8, 8) } }); L.Editable.TouchVertexIcon = L.Editable.VertexIcon.extend({ options: { iconSize: new L.Point(20, 20) } }); // 🍂namespace Editable; 🍂class VertexMarker; Handler for dragging path vertices. L.Editable.VertexMarker = L.Marker.extend({ options: { draggable: true, className: 'leaflet-div-icon leaflet-vertex-icon' }, // 🍂section Public methods // The marker used to handle path vertex. You will usually interact with a `VertexMarker` // instance when listening for events like `editable:vertex:ctrlclick`. initialize: function (latlng, latlngs, editor, options) { // We don't use this._latlng, because on drag Leaflet replace it while // we want to keep reference. this.latlng = latlng; this.latlngs = latlngs; this.editor = editor; L.Marker.prototype.initialize.call(this, latlng, options); this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className}); this.latlng.__vertex = this; this.editor.editLayer.addLayer(this); this.setZIndexOffset(editor.tools._lastZIndex + 1); }, onAdd: function (map) { L.Marker.prototype.onAdd.call(this, map); this.on('drag', this.onDrag); this.on('dragstart', this.onDragStart); this.on('dragend', this.onDragEnd); this.on('mouseup', this.onMouseup); this.on('click', this.onClick); this.on('contextmenu', this.onContextMenu); this.on('mousedown touchstart', this.onMouseDown); this.addMiddleMarkers(); }, onRemove: function (map) { if (this.middleMarker) this.middleMarker.delete(); delete this.latlng.__vertex; this.off('drag', this.onDrag); this.off('dragstart', this.onDragStart); this.off('dragend', this.onDragEnd); this.off('mouseup', this.onMouseup); this.off('click', this.onClick); this.off('contextmenu', this.onContextMenu); this.off('mousedown touchstart', this.onMouseDown); L.Marker.prototype.onRemove.call(this, map); }, onDrag: function (e) { e.vertex = this; this.editor.onVertexMarkerDrag(e); var iconPos = L.DomUtil.getPosition(this._icon), latlng = this._map.layerPointToLatLng(iconPos); this.latlng.update(latlng); this._latlng = this.latlng; // Push back to Leaflet our reference. this.editor.refresh(); if (this.middleMarker) this.middleMarker.updateLatLng(); var next = this.getNext(); if (next && next.middleMarker) next.middleMarker.updateLatLng(); }, onDragStart: function (e) { e.vertex = this; this.editor.onVertexMarkerDragStart(e); }, onDragEnd: function (e) { e.vertex = this; this.editor.onVertexMarkerDragEnd(e); }, onClick: function (e) { e.vertex = this; this.editor.onVertexMarkerClick(e); }, onMouseup: function (e) { L.DomEvent.stop(e); e.vertex = this; this.editor.map.fire('mouseup', e); }, onContextMenu: function (e) { e.vertex = this; this.editor.onVertexMarkerContextMenu(e); }, onMouseDown: function (e) { e.vertex = this; this.editor.onVertexMarkerMouseDown(e); }, // 🍂method delete() // Delete a vertex and the related LatLng. delete: function () { var next = this.getNext(); // Compute before changing latlng this.latlngs.splice(this.getIndex(), 1); this.editor.editLayer.removeLayer(this); this.editor.onVertexDeleted({latlng: this.latlng, vertex: this}); if (!this.latlngs.length) this.editor.deleteShape(this.latlngs); if (next) next.resetMiddleMarker(); this.editor.refresh(); }, // 🍂method getIndex(): int // Get the index of the current vertex among others of the same LatLngs group. getIndex: function () { return this.latlngs.indexOf(this.latlng); }, // 🍂method getLastIndex(): int // Get last vertex index of the LatLngs group of the current vertex. getLastIndex: function () { return this.latlngs.length - 1; }, // 🍂method getPrevious(): VertexMarker // Get the previous VertexMarker in the same LatLngs group. getPrevious: function () { if (this.latlngs.length < 2) return; var index = this.getIndex(), previousIndex = index - 1; if (index === 0 && this.editor.CLOSED) previousIndex = this.getLastIndex(); var previous = this.latlngs[previousIndex]; if (previous) return previous.__vertex; }, // 🍂method getNext(): VertexMarker // Get the next VertexMarker in the same LatLngs group. getNext: function () { if (this.latlngs.length < 2) return; var index = this.getIndex(), nextIndex = index + 1; if (index === this.getLastIndex() && this.editor.CLOSED) nextIndex = 0; var next = this.latlngs[nextIndex]; if (next) return next.__vertex; }, addMiddleMarker: function (previous) { if (!this.editor.hasMiddleMarkers()) return; previous = previous || this.getPrevious(); if (previous && !this.middleMarker) this.middleMarker = this.editor.addMiddleMarker(previous, this, this.latlngs, this.editor); }, addMiddleMarkers: function () { if (!this.editor.hasMiddleMarkers()) return; var previous = this.getPrevious(); if (previous) this.addMiddleMarker(previous); var next = this.getNext(); if (next) next.resetMiddleMarker(); }, resetMiddleMarker: function () { if (this.middleMarker) this.middleMarker.delete(); this.addMiddleMarker(); }, // 🍂method split() // Split the vertex LatLngs group at its index, if possible. split: function () { if (!this.editor.splitShape) return; // Only for PolylineEditor this.editor.splitShape(this.latlngs, this.getIndex()); }, // 🍂method continue() // Continue the vertex LatLngs from this vertex. Only active for first and last vertices of a Polyline. continue: function () { if (!this.editor.continueBackward) return; // Only for PolylineEditor var index = this.getIndex(); if (index === 0) this.editor.continueBackward(this.latlngs); else if (index === this.getLastIndex()) this.editor.continueForward(this.latlngs); } }); L.Editable.mergeOptions({ // 🍂namespace Editable // 🍂option vertexMarkerClass: class = VertexMarker // Class to be used as vertex, for path editing. vertexMarkerClass: L.Editable.VertexMarker }); L.Editable.MiddleMarker = L.Marker.extend({ options: { opacity: 0.5, className: 'leaflet-div-icon leaflet-middle-icon', draggable: true }, initialize: function (left, right, latlngs, editor, options) { this.left = left; this.right = right; this.editor = editor; this.latlngs = latlngs; L.Marker.prototype.initialize.call(this, this.computeLatLng(), options); this._opacity = this.options.opacity; this.options.icon = this.editor.tools.createVertexIcon({className: this.options.className}); this.editor.editLayer.addLayer(this); this.setVisibility(); }, setVisibility: function () { var leftPoint = this._map.latLngToContainerPoint(this.left.latlng), rightPoint = this._map.latLngToContainerPoint(this.right.latlng), size = L.point(this.options.icon.options.iconSize); if (leftPoint.distanceTo(rightPoint) < size.x * 3) this.hide(); else this.show(); }, show: function () { this.setOpacity(this._opacity); }, hide: function () { this.setOpacity(0); }, updateLatLng: function () { this.setLatLng(this.computeLatLng()); this.setVisibility(); }, computeLatLng: function () { var leftPoint = this.editor.map.latLngToContainerPoint(this.left.latlng), rightPoint = this.editor.map.latLngToContainerPoint(this.right.latlng), y = (leftPoint.y + rightPoint.y) / 2, x = (leftPoint.x + rightPoint.x) / 2; return this.editor.map.containerPointToLatLng([x, y]); }, onAdd: function (map) { L.Marker.prototype.onAdd.call(this, map); L.DomEvent.on(this._icon, 'mousedown touchstart', this.onMouseDown, this); map.on('zoomend', this.setVisibility, this); }, onRemove: function (map) { delete this.right.middleMarker; L.DomEvent.off(this._icon, 'mousedown touchstart', this.onMouseDown, this); map.off('zoomend', this.setVisibility, this); L.Marker.prototype.onRemove.call(this, map); }, onMouseDown: function (e) { var iconPos = L.DomUtil.getPosition(this._icon), latlng = this.editor.map.layerPointToLatLng(iconPos); e = { originalEvent: e, latlng: latlng }; if (this.options.opacity === 0) return; L.Editable.makeCancellable(e); this.editor.onMiddleMarkerMouseDown(e); if (e._cancelled) return; this.latlngs.splice(this.index(), 0, e.latlng); this.editor.refresh(); var icon = this._icon; var marker = this.editor.addVertexMarker(e.latlng, this.latlngs); /* Hack to workaround browser not firing touchend when element is no more on DOM */ var parent = marker._icon.parentNode; parent.removeChild(marker._icon); marker._icon = icon; parent.appendChild(marker._icon); marker._initIcon(); marker._initInteraction(); marker.setOpacity(1); /* End hack */ // Transfer ongoing dragging to real marker L.Draggable._dragging = false; marker.dragging._draggable._onDown(e.originalEvent); this.delete(); }, delete: function () { this.editor.editLayer.removeLayer(this); }, index: function () { return this.latlngs.indexOf(this.right.latlng); } }); L.Editable.mergeOptions({ // 🍂namespace Editable // 🍂option middleMarkerClass: class = VertexMarker // Class to be used as middle vertex, pulled by the user to create a new point in the middle of a path. middleMarkerClass: L.Editable.MiddleMarker }); // 🍂namespace Editable; 🍂class BaseEditor; 🍂aka L.Editable.BaseEditor // When editing a feature (Marker, Polyline…), an editor is attached to it. This // editor basically knows how to handle the edition. L.Editable.BaseEditor = L.Handler.extend({ initialize: function (map, feature, options) { L.setOptions(this, options); this.map = map; this.feature = feature; this.feature.editor = this; this.editLayer = new L.LayerGroup(); this.tools = this.options.editTools || map.editTools; }, // 🍂method enable(): this // Set up the drawing tools for the feature to be editable. addHooks: function () { if (this.isConnected()) this.onFeatureAdd(); else this.feature.once('add', this.onFeatureAdd, this); this.onEnable(); this.feature.on(this._getEvents(), this); return; }, // 🍂method disable(): this // Remove the drawing tools for the feature. removeHooks: function () { this.feature.off(this._getEvents(), this); if (this.feature.dragging) this.feature.dragging.disable(); this.editLayer.clearLayers(); this.tools.editLayer.removeLayer(this.editLayer); this.onDisable(); if (this._drawing) this.cancelDrawing(); return; }, // 🍂method drawing(): boolean // Return true if any drawing action is ongoing with this editor. drawing: function () { return !!this._drawing; }, reset: function () {}, onFeatureAdd: function () { this.tools.editLayer.addLayer(this.editLayer); if (this.feature.dragging) this.feature.dragging.enable(); }, hasMiddleMarkers: function () { return !this.options.skipMiddleMarkers && !this.tools.options.skipMiddleMarkers; }, fireAndForward: function (type, e) { if(this.feature.linetype === "circleline" || this.feature.linetype === "circlepolygon"){ }else{ e = e || {}; e.layer = this.feature; this.feature.fire(type, e); this.tools.fireAndForward(type, e); } }, onEnable: function () { // 🍂namespace Editable // 🍂event editable:enable: Event // Fired when an existing feature is ready to be edited. this.fireAndForward('editable:enable'); }, onDisable: function () { // 🍂namespace Editable // 🍂event editable:disable: Event // Fired when an existing feature is not ready anymore to be edited. this.fireAndForward('editable:disable'); }, onEditing: function () { // 🍂namespace Editable // 🍂event editable:editing: Event // Fired as soon as any change is made to the feature geometry. this.fireAndForward('editable:editing'); }, onStartDrawing: function () { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:start: Event // Fired when a feature is to be drawn. this.fireAndForward('editable:drawing:start'); }, onEndDrawing: function () { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:end: Event // Fired when a feature is not drawn anymore. this.fireAndForward('editable:drawing:end'); }, onCancelDrawing: function () { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:cancel: Event // Fired when user cancel drawing while a feature is being drawn. this.fireAndForward('editable:drawing:cancel'); }, onCommitDrawing: function (e) { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:commit: Event // Fired when user finish drawing a feature. this.fireAndForward('editable:drawing:commit', e); }, onDrawingMouseDown: function (e) { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:mousedown: Event // Fired when user `mousedown` while drawing. this.fireAndForward('editable:drawing:mousedown', e); }, onDrawingMouseUp: function (e) { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:mouseup: Event // Fired when user `mouseup` while drawing. this.fireAndForward('editable:drawing:mouseup', e); }, startDrawing: function () { if (!this._drawing) this._drawing = L.Editable.FORWARD; this.tools.registerForDrawing(this); this.onStartDrawing(); }, commitDrawing: function (e) { this.onCommitDrawing(e); this.endDrawing(); }, cancelDrawing: function () { // If called during a vertex drag, the vertex will be removed before // the mouseup fires on it. This is a workaround. Maybe better fix is // To have L.Draggable reset it's status on disable (Leaflet side). L.Draggable._dragging = false; this.onCancelDrawing(); this.endDrawing(); }, endDrawing: function () { this._drawing = false; this.tools.unregisterForDrawing(this); this.onEndDrawing(); }, onDrawingClick: function (e) { if (!this.drawing()) return; L.Editable.makeCancellable(e); // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:click: CancelableEvent // Fired when user `click` while drawing, before any internal action is being processed. this.fireAndForward('editable:drawing:click', e); if (e._cancelled) return; if (!this.isConnected()) this.connect(e); this.processDrawingClick(e); }, isConnected: function () { return this.map.hasLayer(this.feature); }, connect: function (e) { this.tools.connectCreatedToMap(this.feature); this.tools.editLayer.addLayer(this.editLayer); }, onMove: function (e) { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:move: Event // Fired when `move` mouse while drawing, while dragging a marker, and while dragging a vertex. this.fireAndForward('editable:drawing:move', e); }, onDrawingMouseMove: function (e) { this.onMove(e); }, _getEvents: function () { return { dragstart: this.onDragStart, drag: this.onDrag, dragend: this.onDragEnd, remove: this.disable }; }, onDragStart: function (e) { this.onEditing(); // 🍂namespace Editable // 🍂event editable:dragstart: Event // Fired before a path feature is dragged. this.fireAndForward('editable:dragstart', e); }, onDrag: function (e) { this.onMove(e); // 🍂namespace Editable // 🍂event editable:drag: Event // Fired when a path feature is being dragged. this.fireAndForward('editable:drag', e); }, onDragEnd: function (e) { // 🍂namespace Editable // 🍂event editable:dragend: Event // Fired after a path feature has been dragged. this.fireAndForward('editable:dragend', e); } }); // 🍂namespace Editable; 🍂class MarkerEditor; 🍂aka L.Editable.MarkerEditor // 🍂inherits BaseEditor // Editor for Marker. L.Editable.MarkerEditor = L.Editable.BaseEditor.extend({ onDrawingMouseMove: function (e) { L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e); if (this._drawing) this.feature.setLatLng(e.latlng); }, processDrawingClick: function (e) { // 🍂namespace Editable // 🍂section Drawing events // 🍂event editable:drawing:clicked: Event // Fired when user `click` while drawing, after all internal actions. this.fireAndForward('editable:drawing:clicked', e); this.commitDrawing(e); }, connect: function (e) { // On touch, the latlng has not been updated because there is // no mousemove. if (e) this.feature._latlng = e.latlng; L.Editable.BaseEditor.prototype.connect.call(this, e); } }); // 🍂namespace Editable; 🍂class PathEditor; 🍂aka L.Editable.PathEditor // 🍂inherits BaseEditor // Base class for all path editors. L.Editable.PathEditor = L.Editable.BaseEditor.extend({ CLOSED: false, MIN_VERTEX: 2, addHooks: function () { L.Editable.BaseEditor.prototype.addHooks.call(this); if (this.feature) this.initVertexMarkers(); return this; }, initVertexMarkers: function (latlngs) { if (!this.enabled()) return; latlngs = latlngs || this.getLatLngs(); if (L.Polyline._flat(latlngs)) this.addVertexMarkers(latlngs); else for (var i = 0; i < latlngs.length; i++) this.initVertexMarkers(latlngs[i]); }, getLatLngs: function () { return this.feature.getLatLngs(); }, // 🍂method reset() // Rebuild edit elements (Vertex, MiddleMarker, etc.). reset: function () { this.editLayer.clearLayers(); this.initVertexMarkers(); }, addVertexMarker: function (latlng, latlngs) { return new this.tools.options.vertexMarkerClass(latlng, latlngs, this); }, addVertexMarkers: function (latlngs) { for (var i = 0; i < latlngs.length; i++) { this.addVertexMarker(latlngs[i], latlngs); } }, refreshVertexMarkers: function (latlngs) { latlngs = latlngs || this.getDefaultLatLngs(); for (var i = 0; i < latlngs.length; i++) { latlngs[i].__vertex.update(); } }, addMiddleMarker: function (left, right, latlngs) { return new this.tools.options.middleMarkerClass(left, right, latlngs, this); }, onVertexMarkerClick: function (e) { L.Editable.makeCancellable(e); // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:click: CancelableVertexEvent // Fired when a `click` is issued on a vertex, before any internal action is being processed. this.fireAndForward('editable:vertex:click', e); if (e._cancelled) return; if (this.tools.drawing() && this.tools._drawingEditor !== this) return; var index = e.vertex.getIndex(), commit; if (e.originalEvent.ctrlKey) { this.onVertexMarkerCtrlClick(e); } else if (e.originalEvent.altKey) { this.onVertexMarkerAltClick(e); } else if (e.originalEvent.shiftKey) { this.onVertexMarkerShiftClick(e); } else if (e.originalEvent.metaKey) { this.onVertexMarkerMetaKeyClick(e); } else if (index === e.vertex.getLastIndex() && this._drawing === L.Editable.FORWARD) { if (index >= this.MIN_VERTEX - 1) commit = true; } else if (index === 0 && this._drawing === L.Editable.BACKWARD && this._drawnLatLngs.length >= this.MIN_VERTEX) { commit = true; } else if (index === 0 && this._drawing === L.Editable.FORWARD && this._drawnLatLngs.length >= this.MIN_VERTEX && this.CLOSED) { commit = true; // Allow to close on first point also for polygons } else { this.onVertexRawMarkerClick(e); } // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:clicked: VertexEvent // Fired when a `click` is issued on a vertex, after all internal actions. this.fireAndForward('editable:vertex:clicked', e); if (commit) this.commitDrawing(e); }, onVertexRawMarkerClick: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:rawclick: CancelableVertexEvent // Fired when a `click` is issued on a vertex without any special key and without being in drawing mode. this.fireAndForward('editable:vertex:rawclick', e); if (e._cancelled) return; if (!this.vertexCanBeDeleted(e.vertex)) return; e.vertex.delete(); }, vertexCanBeDeleted: function (vertex) { return vertex.latlngs.length > this.MIN_VERTEX; }, onVertexDeleted: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:deleted: VertexEvent // Fired after a vertex has been deleted by user. this.fireAndForward('editable:vertex:deleted', e); }, onVertexMarkerCtrlClick: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:ctrlclick: VertexEvent // Fired when a `click` with `ctrlKey` is issued on a vertex. this.fireAndForward('editable:vertex:ctrlclick', e); }, onVertexMarkerShiftClick: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:shiftclick: VertexEvent // Fired when a `click` with `shiftKey` is issued on a vertex. this.fireAndForward('editable:vertex:shiftclick', e); }, onVertexMarkerMetaKeyClick: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:metakeyclick: VertexEvent // Fired when a `click` with `metaKey` is issued on a vertex. this.fireAndForward('editable:vertex:metakeyclick', e); }, onVertexMarkerAltClick: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:altclick: VertexEvent // Fired when a `click` with `altKey` is issued on a vertex. this.fireAndForward('editable:vertex:altclick', e); }, onVertexMarkerContextMenu: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:contextmenu: VertexEvent // Fired when a `contextmenu` is issued on a vertex. this.fireAndForward('editable:vertex:contextmenu', e); }, onVertexMarkerMouseDown: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:mousedown: VertexEvent // Fired when user `mousedown` a vertex. this.fireAndForward('editable:vertex:mousedown', e); }, onMiddleMarkerMouseDown: function (e) { // 🍂namespace Editable // 🍂section MiddleMarker events // 🍂event editable:middlemarker:mousedown: VertexEvent // Fired when user `mousedown` a middle marker. this.fireAndForward('editable:middlemarker:mousedown', e); }, onVertexMarkerDrag: function (e) { this.onMove(e); if (this.feature._bounds) this.extendBounds(e); // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:drag: VertexEvent // Fired when a vertex is dragged by user. this.fireAndForward('editable:vertex:drag', e); }, onVertexMarkerDragStart: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:dragstart: VertexEvent // Fired before a vertex is dragged by user. this.fireAndForward('editable:vertex:dragstart', e); }, onVertexMarkerDragEnd: function (e) { // 🍂namespace Editable // 🍂section Vertex events // 🍂event editable:vertex:dragend: VertexEvent // Fired after a vertex is dragged by user. this.fireAndForward('editable:vertex:dragend', e); }, setDrawnLatLngs: function (latlngs) { this._drawnLatLngs = latlngs || this.getDefaultLatLngs(); }, startDrawing: function () { if (!this._drawnLatLngs) this.setDrawnLatLngs(); L.Editable.BaseEditor.prototype.startDrawing.call(this); }, startDrawingForward: function () { this.startDrawing(); }, endDrawing: function () { this.tools.detachForwardLineGuide(); this.tools.detachBackwardLineGuide(); if (this._drawnLatLngs && this._drawnLatLngs.length < this.MIN_VERTEX) this.deleteShape(this._drawnLatLngs); L.Editable.BaseEditor.prototype.endDrawing.call(this); delete this._drawnLatLngs; }, addLatLng: function (latlng) { if (this._drawing === L.Editable.FORWARD) this._drawnLatLngs.push(latlng); else this._drawnLatLngs.unshift(latlng); this.feature._bounds.extend(latlng); this.addVertexMarker(latlng, this._drawnLatLngs); this.refresh(); }, newPointForward: function (latlng) { this.addLatLng(latlng); this.tools.attachForwardLineGuide(); this.tools.anchorForwardLineGuide(latlng); }, newPointBackward: function (latlng) { this.addLatLng(latlng); this.tools.anchorBackwardLineGuide(latlng); }, // 🍂namespace PathEditor // 🍂method push() // Programmatically add a point while drawing. push: function (latlng) { if (!latlng) return console.error('L.Editable.PathEditor.push expect a vaild latlng as parameter'); if (this._drawing === L.Editable.FORWARD) this.newPointForward(latlng); else this.newPointBackward(latlng); }, removeLatLng: function (latlng) { latlng.__vertex.delete(); this.refresh(); }, // 🍂method pop(): L.LatLng or null // Programmatically remove last point (if any) while drawing. pop: function () { if (this._drawnLatLngs.length <= 1) return; var latlng; if (this._drawing === L.Editable.FORWARD) latlng = this._drawnLatLngs[this._drawnLatLngs.length - 1]; else latlng = this._drawnLatLngs[0]; this.removeLatLng(latlng); if (this._drawing === L.Editable.FORWARD) this.tools.anchorForwardLineGuide(this._drawnLatLngs[this._drawnLatLngs.length - 1]); else this.tools.anchorForwardLineGuide(this._drawnLatLngs[0]); return latlng; }, processDrawingClick: function (e) { if (e.vertex && e.vertex.editor === this) return; if (this._drawing === L.Editable.FORWARD) this.newPointForward(e.latlng); else this.newPointBackward(e.latlng); this.fireAndForward('editable:drawing:clicked', e); }, onDrawingMouseMove: function (e) { L.Editable.BaseEditor.prototype.onDrawingMouseMove.call(this, e); if (this._drawing) { this.tools.moveForwardLineGuide(e.latlng); this.tools.moveBackwardLineGuide(e.latlng); } }, refresh: function () { this.feature.redraw(); this.callback(this.feature) this.onEditing(); }, // 🍂namespace PathEditor // 🍂method newShape(latlng?: L.LatLng) // Add a new shape (Polyline, Polygon) in a multi, and setup up drawing tools to draw it; // if optional `latlng` is given, start a path at this point. newShape: function (latlng) { var shape = this.addNewEmptyShape(); if (!shape) return; this.setDrawnLatLngs(shape[0] || shape); // Polygon or polyline this.startDrawingForward(); // 🍂namespace Editable // 🍂section Shape events // 🍂event editable:shape:new: ShapeEvent // Fired when a new shape is created in a multi (Polygon or Polyline). this.fireAndForward('editable:shape:new', {shape: shape}); if (latlng) this.newPointForward(latlng); }, deleteShape: function (shape, latlngs) { var e = {shape: shape}; L.Editable.makeCancellable(e); // 🍂namespace Editable // 🍂section Shape events // 🍂event editable:shape:delete: CancelableShapeEvent // Fired before a new shape is deleted in a multi (Polygon or Polyline). this.fireAndForward('editable:shape:delete', e); if (e._cancelled) return; shape = this._deleteShape(shape, latlngs); if (this.ensureNotFlat) this.ensureNotFlat(); // Polygon. this.feature.setLatLngs(this.getLatLngs()); // Force bounds reset. this.refresh(); this.reset(); // 🍂namespace Editable // 🍂section Shape events // 🍂event editable:shape:deleted: ShapeEvent // Fired after a new shape is deleted in a multi (Polygon or Polyline). this.fireAndForward('editable:shape:deleted', {shape: shape}); return shape; }, _deleteShape: function (shape, latlngs) { latlngs = latlngs || this.getLatLngs(); if (!latlngs.length) return; var self = this, inplaceDelete = function (latlngs, shape) { // Called when deleting a flat latlngs shape = latlngs.splice(0, Number.MAX_VALUE); return shape; }, spliceDelete = function (latlngs, shape) { // Called when removing a latlngs inside an array latlngs.splice(latlngs.indexOf(shape), 1); if (!latlngs.length) self._deleteShape(latlngs); return shape; }; if (latlngs === shape) return inplaceDelete(latlngs, shape); for (var i = 0; i < latlngs.length; i++) { if (latlngs[i] === shape) return spliceDelete(latlngs, shape); else if (latlngs[i].indexOf(shape) !== -1) return spliceDelete(latlngs[i], shape); } }, // 🍂namespace PathEditor // 🍂method deleteShapeAt(latlng: L.LatLng): Array // Remove a path shape at the given `latlng`. deleteShapeAt: function (latlng) { var shape = this.feature.shapeAt(latlng); if (shape) return this.deleteShape(shape); }, // 🍂method appendShape(shape: Array) // Append a new shape to the Polygon or Polyline. appendShape: function (shape) { this.insertShape(shape); }, // 🍂method prependShape(shape: Array) // Prepend a new shape to the Polygon or Polyline. prependShape: function (shape) { this.insertShape(shape, 0); }, // 🍂method insertShape(shape: Array, index: int) // Insert a new shape to the Polygon or Polyline at given index (default is to append). insertShape: function (shape, index) { this.ensureMulti(); shape = this.formatShape(shape); if (typeof index === 'undefined') index = this.feature._latlngs.length; this.feature._latlngs.splice(index, 0, shape); this.feature.redraw(); if (this._enabled) this.reset(); }, extendBounds: function (e) { this.feature._bounds.extend(e.vertex.latlng); }, onDragStart: function (e) { this.editLayer.clearLayers(); L.Editable.BaseEditor.prototype.onDragStart.call(this, e); }, onDragEnd: function (e) { this.initVertexMarkers(); L.Editable.BaseEditor.prototype.onDragEnd.call(this, e); } }); // 🍂namespace Editable; 🍂class PolylineEditor; 🍂aka L.Editable.PolylineEditor // 🍂inherits PathEditor L.Editable.PolylineEditor = L.Editable.PathEditor.extend({ startDrawingBackward: function () { this._drawing = L.Editable.BACKWARD; this.startDrawing(); }, // 🍂method continueBackward(latlngs?: Array) // Set up drawing tools to continue the line backward. continueBackward: function (latlngs) { if (this.drawing()) return; latlngs = latlngs || this.getDefaultLatLngs(); this.setDrawnLatLngs(latlngs); if (latlngs.length > 0) { this.tools.attachBackwardLineGuide(); this.tools.anchorBackwardLineGuide(latlngs[0]); } this.startDrawingBackward(); }, // 🍂method continueForward(latlngs?: Array) // Set up drawing tools to continue the line forward. continueForward: function (latlngs) { if (this.drawing()) return; latlngs = latlngs || this.getDefaultLatLngs(); this.setDrawnLatLngs(latlngs); if (latlngs.length > 0) { this.tools.attachForwardLineGuide(); this.tools.anchorForwardLineGuide(latlngs[latlngs.length - 1]); } this.startDrawingForward(); }, getDefaultLatLngs: function (latlngs) { latlngs = latlngs || this.feature._latlngs; if (!latlngs.length || latlngs[0] instanceof L.LatLng) return latlngs; else return this.getDefaultLatLngs(latlngs[0]); }, ensureMulti: function () { if (this.feature._latlngs.length && L.Polyline._flat(this.feature._latlngs)) { this.feature._latlngs = [this.feature._latlngs]; } }, addNewEmptyShape: function () { if (this.feature._latlngs.length) { var shape = []; this.appendShape(shape); return shape; } else { return this.feature._latlngs; } }, formatShape: function (shape) { if (L.Polyline._flat(shape)) return shape; else if (shape[0]) return this.formatShape(shape[0]); }, // 🍂method splitShape(latlngs?: Array, index: int) // Split the given `latlngs` shape at index `index` and integrate new shape in instance `latlngs`. splitShape: function (shape, index) { if (!index || index >= shape.length - 1) return; this.ensureMulti(); var shapeIndex = this.feature._latlngs.indexOf(shape); if (shapeIndex === -1) return; var first = shape.slice(0, index + 1), second = shape.slice(index); // We deal with reference, we don't want twice the same latlng around. second[0] = L.latLng(second[0].lat, second[0].lng, second[0].alt); this.feature._latlngs.splice(shapeIndex, 1, first, second); this.refresh(); this.reset(); } }); // 🍂namespace Editable; 🍂class PolygonEditor; 🍂aka L.Editable.PolygonEditor // 🍂inherits PathEditor L.Editable.PolygonEditor = L.Editable.PathEditor.extend({ CLOSED: true, MIN_VERTEX: 3, newPointForward: function (latlng) { L.Editable.PathEditor.prototype.newPointForward.call(this, latlng); if (!this.tools.backwardLineGuide._latlngs.length) this.tools.anchorBackwardLineGuide(latlng); if (this._drawnLatLngs.length === 2) this.tools.attachBackwardLineGuide(); }, addNewEmptyHole: function (latlng) { this.ensureNotFlat(); var latlngs = this.feature.shapeAt(latlng); if (!latlngs) return; var holes = []; latlngs.push(holes); return holes; }, // 🍂method newHole(latlng?: L.LatLng, index: int) // Set up drawing tools for creating a new hole on the Polygon. If the `latlng` param is given, a first point is created. newHole: function (latlng) { var holes = this.addNewEmptyHole(latlng); if (!holes) return; this.setDrawnLatLngs(holes); this.startDrawingForward(); if (latlng) this.newPointForward(latlng); }, addNewEmptyShape: function () { if (this.feature._latlngs.length && this.feature._latlngs[0].length) { var shape = []; this.appendShape(shape); return shape; } else { return this.feature._latlngs; } }, ensureMulti: function () { if (this.feature._latlngs.length && L.Polyline._flat(this.feature._latlngs[0])) { this.feature._latlngs = [this.feature._latlngs]; } }, ensureNotFlat: function () { if (!this.feature._latlngs.length || L.Polyline._flat(this.feature._latlngs)) this.feature._latlngs = [this.feature._latlngs]; }, vertexCanBeDeleted: function (vertex) { var parent = this.feature.parentShape(vertex.latlngs), idx = L.Util.indexOf(parent, vertex.latlngs); if (idx > 0) return true; // Holes can be totally deleted without removing the layer itself. return L.Editable.PathEditor.prototype.vertexCanBeDeleted.call(this, vertex); }, getDefaultLatLngs: function () { if (!this.feature._latlngs.length) this.feature._latlngs.push([]); return this.feature._latlngs[0]; }, formatShape: function (shape) { // [[1, 2], [3, 4]] => must be nested // [] => must be nested // [[]] => is already nested if (L.Polyline._flat(shape) && (!shape[0] || shape[0].length !== 0)) return [shape]; else return shape; } }); // 🍂namespace Editable; 🍂class RectangleEditor; 🍂aka L.Editable.RectangleEditor // 🍂inherits PathEditor L.Editable.RectangleEditor = L.Editable.PathEditor.extend({ CLOSED: true, MIN_VERTEX: 4, options: { skipMiddleMarkers: true }, extendBounds: function (e) { var index = e.vertex.getIndex(), next = e.vertex.getNext(), previous = e.vertex.getPrevious(), oppositeIndex = (index + 2) % 4, opposite = e.vertex.latlngs[oppositeIndex], bounds = new L.LatLngBounds(e.latlng, opposite); // Update latlngs by hand to preserve order. previous.latlng.update([e.latlng.lat, opposite.lng]); next.latlng.update([opposite.lat, e.latlng.lng]); this.updateBounds(bounds); this.refreshVertexMarkers(); }, onDrawingMouseDown: function (e) { L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e); this.connect(); var latlngs = this.getDefaultLatLngs(); // L.Polygon._convertLatLngs removes last latlng if it equals first point, // which is the case here as all latlngs are [0, 0] if (latlngs.length === 3) latlngs.push(e.latlng); var bounds = new L.LatLngBounds(e.latlng, e.latlng); this.updateBounds(bounds); this.updateLatLngs(bounds); this.refresh(); this.reset(); // Stop dragging map. // L.Draggable has two workflows: // - mousedown => mousemove => mouseup // - touchstart => touchmove => touchend // Problem: L.Map.Tap does not allow us to listen to touchstart, so we only // can deal with mousedown, but then when in a touch device, we are dealing with // simulated events (actually simulated by L.Map.Tap), which are no more taken // into account by L.Draggable. // Ref.: https://github.com/Leaflet/Leaflet.Editable/issues/103 e.originalEvent._simulated = false; this.map.dragging._draggable._onUp(e.originalEvent); // Now transfer ongoing drag action to the bottom right corner. // Should we refine which corne will handle the drag according to // drag direction? latlngs[3].__vertex.dragging._draggable._onDown(e.originalEvent); }, onDrawingMouseUp: function (e) { this.commitDrawing(e); e.originalEvent._simulated = false; L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e); }, onDrawingMouseMove: function (e) { e.originalEvent._simulated = false; L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e); }, getDefaultLatLngs: function (latlngs) { return latlngs || this.feature._latlngs[0]; }, updateBounds: function (bounds) { this.feature._bounds = bounds; }, updateLatLngs: function (bounds) { var latlngs = this.getDefaultLatLngs(), newLatlngs = this.feature._boundsToLatLngs(bounds); // Keep references. for (var i = 0; i < latlngs.length; i++) { latlngs[i].update(newLatlngs[i]); }; } }); // 🍂namespace Editable; 🍂class CircleEditor; 🍂aka L.Editable.CircleEditor // 🍂inherits PathEditor L.Editable.CircleEditor = L.Editable.PathEditor.extend({ MIN_VERTEX: 2, options: { skipMiddleMarkers: true }, initialize: function (map, feature, options) { L.Editable.PathEditor.prototype.initialize.call(this, map, feature, options); this._resizeLatLng = this.computeResizeLatLng(); }, computeResizeLatLng: function () { // While circle is not added to the map, _radius is not set. var delta = (this.feature._radius || this.feature._mRadius) * Math.cos(Math.PI / 4), point = this.map.project(this.feature._latlng); return this.map.unproject([point.x + delta, point.y - delta]); }, updateResizeLatLng: function () { this._resizeLatLng.update(this.computeResizeLatLng()); this._resizeLatLng.__vertex.update(); }, getLatLngs: function () { return [this.feature._latlng, this._resizeLatLng]; }, getDefaultLatLngs: function () { return this.getLatLngs(); }, onVertexMarkerDrag: function (e) { if (e.vertex.getIndex() === 1) this.resize(e); else this.updateResizeLatLng(e); L.Editable.PathEditor.prototype.onVertexMarkerDrag.call(this, e); }, resize: function (e) { var radius = this.feature._latlng.distanceTo(e.latlng) this.feature.setRadius(radius); }, onDrawingMouseDown: function (e) { L.Editable.PathEditor.prototype.onDrawingMouseDown.call(this, e); this._resizeLatLng.update(e.latlng); this.feature._latlng.update(e.latlng); this.connect(); // Stop dragging map. e.originalEvent._simulated = false; this.map.dragging._draggable._onUp(e.originalEvent); // Now transfer ongoing drag action to the radius handler. this._resizeLatLng.__vertex.dragging._draggable._onDown(e.originalEvent); }, onDrawingMouseUp: function (e) { this.commitDrawing(e); e.originalEvent._simulated = false; L.Editable.PathEditor.prototype.onDrawingMouseUp.call(this, e); }, onDrawingMouseMove: function (e) { e.originalEvent._simulated = false; L.Editable.PathEditor.prototype.onDrawingMouseMove.call(this, e); }, onDrag: function (e) { L.Editable.PathEditor.prototype.onDrag.call(this, e); this.feature.dragging.updateLatLng(this._resizeLatLng); } }); // 🍂namespace Editable; 🍂class EditableMixin // `EditableMixin` is included to `L.Polyline`, `L.Polygon`, `L.Rectangle`, `L.Circle` // and `L.Marker`. It adds some methods to them. // *When editing is enabled, the editor is accessible on the instance with the // `editor` property.* var EditableMixin = { createEditor: function (map) { map = map || this._map; var tools = (this.options.editOptions || {}).editTools || map.editTools; if (!tools) throw Error('Unable to detect Editable instance.') var Klass = this.options.editorClass || this.getEditorClass(tools); return new Klass(map, this, this.options.editOptions); }, // 🍂method enableEdit(map?: L.Map): this.editor // Enable editing, by creating an editor if not existing, and then calling `enable` on it. enableEdit: function (callback,map) { if (!this.editor) this.createEditor(map); this.editor.enable(); this.editor.callback = callback; return this.editor; }, // 🍂method editEnabled(): boolean // Return true if current instance has an editor attached, and this editor is enabled. editEnabled: function () { return this.editor && this.editor.enabled(); }, // 🍂method disableEdit() // Disable editing, also remove the editor property reference. disableEdit: function () { if (this.editor) { this.editor.disable(); delete this.editor; } }, // 🍂method toggleEdit() // Enable or disable editing, according to current status. toggleEdit: function () { if (this.editEnabled()) this.disableEdit(); else this.enableEdit(); }, _onEditableAdd: function () { if (this.editor) this.enableEdit(); } }; var PolylineMixin = { getEditorClass: function (tools) { return (tools && tools.options.polylineEditorClass) ? tools.options.polylineEditorClass : L.Editable.PolylineEditor; }, shapeAt: function (latlng, latlngs) { // We can have those cases: // - latlngs are just a flat array of latlngs, use this // - latlngs is an array of arrays of latlngs, loop over var shape = null; latlngs = latlngs || this._latlngs; if (!latlngs.length) return shape; else if (L.Polyline._flat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs; else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i])) return latlngs[i]; return shape; }, isInLatLngs: function (l, latlngs) { if (!latlngs) return false; var i, k, len, part = [], p, w = this._clickTolerance(); this._projectLatlngs(latlngs, part, this._pxBounds); part = part[0]; p = this._map.latLngToLayerPoint(l); if (!this._pxBounds.contains(p)) { return false; } for (i = 1, len = part.length, k = 0; i < len; k = i++) { if (L.LineUtil.pointToSegmentDistance(p, part[k], part[i]) <= w) { return true; } } return false; } }; var PolygonMixin = { getEditorClass: function (tools) { return (tools && tools.options.polygonEditorClass) ? tools.options.polygonEditorClass : L.Editable.PolygonEditor; }, shapeAt: function (latlng, latlngs) { // We can have those cases: // - latlngs are just a flat array of latlngs, use this // - latlngs is an array of arrays of latlngs, this is a simple polygon (maybe with holes), use the first // - latlngs is an array of arrays of arrays, this is a multi, loop over var shape = null; latlngs = latlngs || this._latlngs; if (!latlngs.length) return shape; else if (L.Polyline._flat(latlngs) && this.isInLatLngs(latlng, latlngs)) shape = latlngs; else if (L.Polyline._flat(latlngs[0]) && this.isInLatLngs(latlng, latlngs[0])) shape = latlngs; else for (var i = 0; i < latlngs.length; i++) if (this.isInLatLngs(latlng, latlngs[i][0])) return latlngs[i]; return shape; }, isInLatLngs: function (l, latlngs) { var inside = false, l1, l2, j, k, len2; for (j = 0, len2 = latlngs.length, k = len2 - 1; j < len2; k = j++) { l1 = latlngs[j]; l2 = latlngs[k]; if (((l1.lat > l.lat) !== (l2.lat > l.lat)) && (l.lng < (l2.lng - l1.lng) * (l.lat - l1.lat) / (l2.lat - l1.lat) + l1.lng)) { inside = !inside; } } return inside; }, parentShape: function (shape, latlngs) { latlngs = latlngs || this._latlngs; if (!latlngs) return; var idx = L.Util.indexOf(latlngs, shape); if (idx !== -1) return latlngs; for (var i = 0; i < latlngs.length; i++) { idx = L.Util.indexOf(latlngs[i], shape); if (idx !== -1) return latlngs[i]; } } }; var MarkerMixin = { getEditorClass: function (tools) { return (tools && tools.options.markerEditorClass) ? tools.options.markerEditorClass : L.Editable.MarkerEditor; } }; var RectangleMixin = { getEditorClass: function (tools) { return (tools && tools.options.rectangleEditorClass) ? tools.options.rectangleEditorClass : L.Editable.RectangleEditor; } }; var CircleMixin = { getEditorClass: function (tools) { return (tools && tools.options.circleEditorClass) ? tools.options.circleEditorClass : L.Editable.CircleEditor; } }; var keepEditable = function () { // Make sure you can remove/readd an editable layer. this.on('add', this._onEditableAdd); }; if (L.Polyline) { L.Polyline.include(EditableMixin); L.Polyline.include(PolylineMixin); L.Polyline.addInitHook(keepEditable); } if (L.Polygon) { L.Polygon.include(EditableMixin); L.Polygon.include(PolygonMixin); } if (L.Marker) { L.Marker.include(EditableMixin); L.Marker.include(MarkerMixin); L.Marker.addInitHook(keepEditable); } if (L.Rectangle) { L.Rectangle.include(EditableMixin); L.Rectangle.include(RectangleMixin); } if (L.Circle) { L.Circle.include(EditableMixin); L.Circle.include(CircleMixin); } L.LatLng.prototype.update = function (latlng) { latlng = L.latLng(latlng); this.lat = latlng.lat; this.lng = latlng.lng; } }, window)); /* Leaflet.contextmenu, a context menu for Leaflet. (c) 2015, Adam Ratcliffe, GeoSmart Maps Limited @preserve */ (function(factory) { // Packaging/modules magic dance var L; if (typeof define === 'function' && define.amd) { // AMD define(['leaflet'], factory); } else if (typeof module !== 'undefined') { // Node/CommonJS L = require('leaflet'); module.exports = factory(L); } else { // Browser globals if (typeof window.L === 'undefined') { throw new Error('Leaflet must be loaded first'); } factory(window.L); } })(function(L) { L.Map.mergeOptions({ contextmenuItems: [] }); L.Map.ContextMenu = L.Handler.extend({ _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart', statics: { BASE_CLS: 'leaflet-contextmenu' }, runCallFunc:[], initialize: function (map) { L.Handler.prototype.initialize.call(this, map); this._items = []; this._visible = false; var container = this._container = L.DomUtil.create('div', L.Map.ContextMenu.BASE_CLS, map._container); container.style.zIndex = 10000; container.style.position = 'absolute'; if (map.options.contextmenuWidth) { container.style.width = map.options.contextmenuWidth + 'px'; } this._createItems(); L.DomEvent .on(container, 'click', L.DomEvent.stop) .on(container, 'mousedown', L.DomEvent.stop) .on(container, 'dblclick', L.DomEvent.stop) .on(container, 'contextmenu', L.DomEvent.stop); }, addHooks: function () { var container = this._map.getContainer(); L.DomEvent .on(container, 'mouseleave', this._hide, this) .on(document, 'keydown', this._onKeyDown, this); if (L.Browser.touch) { L.DomEvent.on(document, this._touchstart, this._hide, this); } this._map.on({ contextmenu: this._show, mousedown: this._hide, movestart: this._hide, zoomstart: this._hide }, this); }, removeHooks: function () { var container = this._map.getContainer(); L.DomEvent .off(container, 'mouseleave', this._hide, this) .off(document, 'keydown', this._onKeyDown, this); if (L.Browser.touch) { L.DomEvent.off(document, this._touchstart, this._hide, this); } this._map.off({ contextmenu: this._show, mousedown: this._hide, movestart: this._hide, zoomstart: this._hide }, this); }, showAt: function (point, data) { if (point instanceof L.LatLng) { point = this._map.latLngToContainerPoint(point); } this._showAtPoint(point, data); }, hide: function () { this._hide(); }, addItem: function (options) { return this.insertItem(options); }, insertItem: function (options, index) { index = index !== undefined ? index: this._items.length; var item = this._createItem(this._container, options, index); this._items.push(item); this._sizeChanged = true; this._map.fire('contextmenu.additem', { contextmenu: this, el: item.el, index: index }); return item.el; }, removeItem: function (item) { var container = this._container; if (!isNaN(item)) { item = container.children[item]; } if (item) { this._removeItem(L.Util.stamp(item)); this._sizeChanged = true; this._map.fire('contextmenu.removeitem', { contextmenu: this, el: item }); } }, removeAllItems: function () { var item; while (this._container.children.length) { item = this._container.children[0]; this._removeItem(L.Util.stamp(item)); } }, hideAllItems: function () { var item, i, l; for (i = 0, l = this._items.length; i < l; i++) { item = this._items[i]; item.el.style.display = 'none'; } }, showAllItems: function () { var item, i, l; for (i = 0, l = this._items.length; i < l; i++) { item = this._items[i]; item.el.style.display = ''; } }, setDisabled: function (item, disabled) { var container = this._container, itemCls = L.Map.ContextMenu.BASE_CLS + '-item'; if (!isNaN(item)) { item = container.children[item]; } if (item && L.DomUtil.hasClass(item, itemCls)) { if (disabled) { L.DomUtil.addClass(item, itemCls + '-disabled'); this._map.fire('contextmenu.disableitem', { contextmenu: this, el: item }); } else { L.DomUtil.removeClass(item, itemCls + '-disabled'); this._map.fire('contextmenu.enableitem', { contextmenu: this, el: item }); } } }, isVisible: function () { return this._visible; }, _createItems: function () { var itemOptions = this._map.options.contextmenuItems, item, i, l; for (i = 0, l = itemOptions.length; i < l; i++) { this._items.push(this._createItem(this._container, itemOptions[i])); } }, _createItem: function (container, options, index) { if (options.separator || options === '-') { return this._createSeparator(container, index); } var itemCls = L.Map.ContextMenu.BASE_CLS + '-item', cls = options.disabled ? (itemCls + ' ' + itemCls + '-disabled') : itemCls; if(options.hasOwnProperty('className')){ cls = cls + ' ' + options.className; } var el = this._insertElementAt('a', cls, container, index), callback = this._createEventHandler(el, options.callback, options.context, options.hideOnSelect), html = ''; if(options.hasOwnProperty('runCall')){ this.runCallFunc.push(options.runCall); } if (options.icon) { html = ''; } else if (options.iconCls) { html = ''; } if(typeof options.text === 'object'){ el.innerHTML = html; el.appendChild(options.text); }else { el.innerHTML = html + options.text; } el.href = '#'; L.DomEvent .on(el, 'mouseover', this._onItemMouseOver, this) .on(el, 'mouseout', this._onItemMouseOut, this) .on(el, 'mousedown', L.DomEvent.stopPropagation) .on(el, 'click', callback); if (L.Browser.touch) { L.DomEvent.on(el, this._touchstart, L.DomEvent.stopPropagation); } return { id: L.Util.stamp(el), el: el, callback: callback }; }, _removeItem: function (id) { var item, el, i, l, callback; for (i = 0, l = this._items.length; i < l; i++) { item = this._items[i]; if (item.id === id) { el = item.el; callback = item.callback; if (callback) { L.DomEvent .off(el, 'mouseover', this._onItemMouseOver, this) .off(el, 'mouseover', this._onItemMouseOut, this) .off(el, 'mousedown', L.DomEvent.stopPropagation) .off(el, 'click', callback); if (L.Browser.touch) { L.DomEvent.off(el, this._touchstart, L.DomEvent.stopPropagation); } } this._container.removeChild(el); this._items.splice(i, 1); return item; } } return null; }, _createSeparator: function (container, index) { var el = this._insertElementAt('div', L.Map.ContextMenu.BASE_CLS + '-separator', container, index); return { id: L.Util.stamp(el), el: el }; }, _createEventHandler: function (el, func, context, hideOnSelect) { var me = this, map = this._map, disabledCls = L.Map.ContextMenu.BASE_CLS + '-item-disabled', hideOnSelect = (hideOnSelect !== undefined) ? hideOnSelect : true; return function (e) { if (L.DomUtil.hasClass(el, disabledCls)) { return; } if (hideOnSelect) { me._hide(); } if (func) { func.call(context || map, me._showLocation); } me._map.fire('contextmenu:select', { contextmenu: me, el: el }); }; }, _insertElementAt: function (tagName, className, container, index) { var refEl, el = document.createElement(tagName); el.className = className; if (index !== undefined) { refEl = container.children[index]; } if (refEl) { container.insertBefore(el, refEl); } else { container.appendChild(el); } return el; }, _show: function (e) { var _this = this; //this._showAtPoint(e.containerPoint, e); for(var i = 0, l=this.runCallFunc.length; i mapSize.x) { container.style.left = 'auto'; container.style.right = Math.max(mapSize.x - pt.x, 0) + 'px'; } else { container.style.left = Math.max(pt.x, 0) + 'px'; container.style.right = 'auto'; } if (pt.y + containerSize.y > mapSize.y) { container.style.top = 'auto'; container.style.bottom = Math.max(mapSize.y - pt.y, 0) + 'px'; } else { container.style.top = Math.max(pt.y, 0) + 'px'; container.style.bottom = 'auto'; } }, _getElementSize: function (el) { var size = this._size, initialDisplay = el.style.display; if (!size || this._sizeChanged) { size = {}; el.style.left = '-999999px'; el.style.right = 'auto'; el.style.display = 'block'; size.x = el.offsetWidth; size.y = el.offsetHeight; el.style.left = 'auto'; el.style.display = initialDisplay; this._sizeChanged = false; } return size; }, _onKeyDown: function (e) { var key = e.keyCode; // If ESC pressed and context menu is visible hide it if (key === 27) { this._hide(); } }, _onItemMouseOver: function (e) { L.DomUtil.addClass(e.target || e.srcElement, 'over'); }, _onItemMouseOut: function (e) { L.DomUtil.removeClass(e.target || e.srcElement, 'over'); } }); L.Map.addInitHook('addHandler', 'contextmenu', L.Map.ContextMenu); L.Mixin.ContextMenu = { bindContextMenu: function (options) { L.setOptions(this, options); this._initContextMenu(); return this; }, unbindContextMenu: function (){ this.off('contextmenu', this._showContextMenu, this); return this; }, addContextMenuItem: function (item) { this.options.contextmenuItems.push(item); }, removeContextMenuItemWithIndex: function (index) { var items = []; for (var i = 0; i < this.options.contextmenuItems.length; i++) { if(this.options.contextmenuItems[i].index == index){ items.push(i); } } var elem = items.pop(); while (elem !== undefined) { this.options.contextmenuItems.splice(elem,1); elem = items.pop(); } }, replaceConextMenuItem: function (item) { this.removeContextMenuItemWithIndex(item.index); this.addContextMenuItem(item); }, _initContextMenu: function () { this._items = []; this.on('contextmenu', this._showContextMenu, this); }, _showContextMenu: function (e) { var itemOptions, data, pt, i, l; if (this._map.contextmenu) { data = L.extend({relatedTarget: this}, e) pt = this._map.mouseEventToContainerPoint(e.originalEvent); if (!this.options.contextmenuInheritItems) { this._map.contextmenu.hideAllItems(); } for (i = 0, l = this.options.contextmenuItems.length; i < l; i++) { itemOptions = this.options.contextmenuItems[i]; this._items.push(this._map.contextmenu.insertItem(itemOptions, itemOptions.index)); } this._map.once('contextmenu.hide', this._hideContextMenu, this); this._map.contextmenu.showAt(pt, data); } }, _hideContextMenu: function () { var i, l; for (i = 0, l = this._items.length; i < l; i++) { this._map.contextmenu.removeItem(this._items[i]); } this._items.length = 0; if (!this.options.contextmenuInheritItems) { this._map.contextmenu.showAllItems(); } } }; var classes = [L.Marker, L.Path], defaultOptions = { contextmenu: false, contextmenuItems: [], contextmenuInheritItems: true }, cls, i, l; for (i = 0, l = classes.length; i < l; i++) { cls = classes[i]; // L.Class should probably provide an empty options hash, as it does not test // for it here and add if needed if (!cls.prototype.options) { cls.prototype.options = defaultOptions; } else { cls.mergeOptions(defaultOptions); } cls.addInitHook(function () { if (this.options.contextmenu) { this._initContextMenu(); } }); cls.include(L.Mixin.ContextMenu); } return L.Map.ContextMenu; }); /** * Semicircle extension for L.Circle. * Jan Pieter Waagmeester * * This version is tested with leaflet 1.0.2 */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD define(['leaflet'], factory); } else if (typeof module !== 'undefined') { // Node/CommonJS module.exports = factory(require('leaflet')); } else { // Browser globals if (typeof window.L === 'undefined') { throw 'Leaflet must be loaded first'; } factory(window.L); } })(function (L) { var DEG_TO_RAD = Math.PI / 180; // make sure 0 degrees is up (North) and convert to radians. function fixAngle (angle) { return (angle - 90) * DEG_TO_RAD; } // rotate point [x + r, y+r] around [x, y] by `angle` radians. function rotated (p, angle, r) { return p.add( L.point(Math.cos(angle), Math.sin(angle)).multiplyBy(r) ); } L.Point.prototype.rotated = function (angle, r) { return rotated(this, angle, r); }; L.Circle = L.Circle.extend({ options: { startAngle: 0, stopAngle: 359.9999999999999999999999 }, startAngle: function () { if (this.options.startAngle < this.options.stopAngle) { return fixAngle(this.options.startAngle); } else { return fixAngle(this.options.stopAngle); } }, stopAngle: function () { if (this.options.startAngle < this.options.stopAngle) { return fixAngle(this.options.stopAngle); } else { return fixAngle(this.options.startAngle); } }, setStartAngle: function (angle) { this.options.startAngle = angle; return this.redraw(); }, setStopAngle: function (angle) { this.options.stopAngle = angle; return this.redraw(); }, setDirection: function (direction, degrees) { if (degrees === undefined) { degrees = 10; } this.options.startAngle = direction - (degrees / 2); this.options.stopAngle = direction + (degrees / 2); return this.redraw(); }, getDirection: function () { return this.stopAngle() - (this.stopAngle() - this.startAngle()) / 2; }, isSemicircle: function () { var startAngle = this.options.startAngle, stopAngle = this.options.stopAngle; return ( !(startAngle === 0 && stopAngle > 359) && !(startAngle == stopAngle) ); }, _containsPoint: function (p) { function normalize (angle) { while (angle <= -Math.PI) { angle += 2.0 * Math.PI; } while (angle > Math.PI) { angle -= 2.0 * Math.PI; } return angle; } var angle = Math.atan2(p.y - this._point.y, p.x - this._point.x); var nStart = normalize(this.startAngle()); var nStop = normalize(this.stopAngle()); if (nStop <= nStart) { nStop += 2.0 * Math.PI; } if (angle <= nStart) { angle += 2.0 * Math.PI; } return ( nStart < angle && angle <= nStop && p.distanceTo(this._point) <= this._radius + this._clickTolerance() ); } }); var _updateCircleSVG = L.SVG.prototype._updateCircle; var _updateCircleCanvas = L.Canvas.prototype._updateCircle; L.SVG.include({ _updateCircle: function (layer) { // If we want a circle, we use the original function if (!layer.isSemicircle()) { return _updateCircleSVG.call(this, layer); } if (layer._empty()) { return this._setPath(layer, 'M0 0'); } var p = layer._point, r = layer._radius, r2 = Math.round(layer._radiusY || r), start = p.rotated(layer.startAngle(), r), end = p.rotated(layer.stopAngle(), r); var largeArc = (layer.options.stopAngle - layer.options.startAngle >= 180) ? '1' : '0'; var d = 'M' + p.x + ',' + p.y + // line to first start point 'L' + start.x + ',' + start.y + 'A ' + r + ',' + r2 + ',0,' + largeArc + ',1,' + end.x + ',' + end.y + ' z'; this._setPath(layer, d); } }); L.Canvas.include({ _updateCircle: function (layer) { // If we want a circle, we use the original function if (!layer.isSemicircle()) { return _updateCircleCanvas.call(this, layer); } var p = layer._point, ctx = this._ctx, r = layer._radius, s = (layer._radiusY || r) / r, start = p.rotated(layer.startAngle(), r); this._drawnLayers[layer._leaflet_id] = layer; if (s !== 1) { ctx.save(); ctx.scale(1, s); } ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(start.x, start.y); ctx.arc(p.x, p.y, r, layer.startAngle(), layer.stopAngle()); ctx.lineTo(p.x, p.y); if (s !== 1) { ctx.restore(); } this._fillStroke(ctx, layer); } }); // L.CircleMarker inherits from L.Circle before the Semicircle stuff is // added. The renderers test if the layer is a semicircle with a function // isSemicircle, so add that to L.CircleMarker to make sure we can still // make L.CircleMarkers. L.CircleMarker = L.CircleMarker.extend({ isSemicircle: function () { return false; } }); }); ; (function(window, document, undefined) { //获取三维视图任一点象素位置的经纬度坐标 function get3DPixToLnglat(option) { var point = locaSpaceMap.CreatePoint2D(); if (option == 'topleft') { var S2dx = 0; //3D视图容器宽度的二分之一 var S2dy = 0; //3D视图容器高度的二分之一 } else if (option == 'bottomright') { var S2dx = $('#map3DWrap').width(); //3D视图容器宽度的二分之一 var S2dy = $('#map3DWrap').height(); //3D视图容器高度的二分之一 } else if (option == 'center') { var S2dx = $('#map3DWrap').width() / 2; //3D视图容器宽度的二分之一 var S2dy = $('#map3DWrap').height() / 2; //3D视图容器高度的二分之一 } point.x = parseInt(S2dx); point.y = parseInt(S2dy); var result = locaSpaceMap.Globe.ScreenToScene(point); return { lng: result.x, lat: result.y }; } /** * 聚集区显示 * 根据两个点或三个点计算出聚集区坐标 */ function getGeoGatheringPlace(start, middle, stop) { var originP = new SuperMap.Geometry.Point(start[0], start[1]); var lastP = new SuperMap.Geometry.Point(stop[0], stop[1]); var gather = new SuperMap.Geometry.GeoGatheringPlace; var points = []; // 向量originP_lastP var vectorOL = new SuperMap.Geometry.Point(lastP.x - originP.x, lastP.y - originP.y); // 向量originP_lastP的模 var dOL = Math.sqrt(vectorOL.x * vectorOL.x + vectorOL.y * vectorOL.y); //计算第一个插值控制点 //向量originP_P1以originP为起点,与向量originP_lastP的夹角设为30,模为√3/12*dOL, var v_O_P1_lr = gather.calculateVector(vectorOL, Math.PI / 3, Math.sqrt(3) / 12 * dOL); //取左边的向量作为向量originP_P1 var originP_P1 = v_O_P1_lr[0]; var p1 = new SuperMap.Geometry.Point(originP_P1.x + originP.x, originP_P1.y + originP.y); //计算第二个插值控制点,取第一控制点和第二控制点的中点为第二个插值控制点 var p2 = new SuperMap.Geometry.Point((originP.x + lastP.x) / 2, (originP.y + lastP.y) / 2); //计算第三个插值控制点 //向量originP_P3以lastP为起点,与向量originP_lastP的夹角设为150°,模为√3/12*dOL, var v_L_P3_lr = gather.calculateVector(vectorOL, Math.PI * 2 / 3, Math.sqrt(3) / 12 * dOL); //取左边的向量作为向量originP_P1 var lastP_P3 = v_L_P3_lr[0]; var p3 = new SuperMap.Geometry.Point(lastP_P3.x + lastP.x, lastP_P3.y + lastP.y); //计算第四个插值控制点 if (middle) { var p5 = new SuperMap.Geometry.Point(middle[0], middle[1]); } else { //向量originP_P4以向量originP_lastP中点为起点,与向量originP_lastP的夹角设为90°,模为1/2*dOL, var v_O_P5_lr = gather.calculateVector(vectorOL, Math.PI / 2, 1 / 2 * dOL); //取左边的向量作为向量originP_P1 var v_O_P5 = v_O_P5_lr[1]; var p5 = new SuperMap.Geometry.Point(v_O_P5.x + p2.x, v_O_P5.y + p2.y); } var P0 = originP.clone(); var P4 = lastP.clone(); points.push(P0, p1, p2, p3, P4, p5); var cardinalPoints = SuperMap.Geometry.LineString.createCloseCardinal(points); var gatherGeo = SuperMap.Geometry.LineString.createBezier3(cardinalPoints, 100); gatherGeo = gatherGeo.components; var newGatherGeo = []; for (var i = 0; i < gatherGeo.length; i++) { newGatherGeo.push([gatherGeo[i].x, gatherGeo[i].y]) } return newGatherGeo; } /** * 转换3世界坐标 用于在leaflet中实现跨逆子午线,线走最近距离 坐标不能超过一圈 * 遍历坐标数组,取经度, * 如果(N+1).lng-N.lng 绝对值超过180表示需要进行换算,取最近路线:负数为逆时针,正数为顺时针 * * @param {[type]} lnglats [description] * @return {[type]} [description] */ function lnglatsToDateLineLnglats(lnglats, circleLng) { for (var i = 1; i < lnglats.length; i++) { var dY = lnglats[i][0] - lnglats[i - 1][0]; if (dY > 180) { if (dY > 540) { lnglats[i][0] -= 720; } else { lnglats[i][0] -= 360; } } if (dY < -180) { if (dY < -540) { lnglats[i][0] += 720; } else { lnglats[i][0] += 360; } } } //如果第一个点和圆心的差值小于-180 则圆平移360度 if (circleLng) { if ((lnglats[0][0] - circleLng) < -180) { for (var i = 0; i < lnglats.length; i++) { lnglats[i][0] += 360 } } } return lnglats; } /** * 3世界坐标 转换 -180 180 纬度坐标 * @param {[type]} lnglats [description] * @return {[type]} [description] */ function dateLineLnglatsToLnglats(lnglats) { for (var i = 1; i < lnglats.length; i++) { var dY = lnglats[i][0] + lnglats[i - 1][0]; if (dY > 180) { lnglats[i][0] -= 360; } if (dY < -180) { lnglats[i][0] += 360; } } return lnglats; } /** * * 2D坐标转3D视角中心点 */ function latlngsTo3DViewCenter(mapState) { var RoraTilt = map23DData.view.pitch; var gausscenter = coordn_to_gauss([mapState.center.lng, mapState.center.lat], mapState.zoom); var h = map23DData.view.distance; var heading3D = -map23DData.view.heading; if (heading3D > 180) { heading3D = heading3D % 180 - 180; } else if (heading3D < -180) { heading3D = 180 + heading3D % 180; } if (-90 < heading3D && heading3D <= 0) { var RoraHead = Math.abs(map23DData.view.heading / 180 * Math.PI); gausscenter[1] = gausscenter[1] - h * Math.sin(RoraTilt) * Math.cos(RoraHead); gausscenter[0] = gausscenter[0] + h * Math.sin(RoraTilt) * Math.sin(RoraHead); var mapsetlatlng = gaussToGeo(gausscenter[0], gausscenter[1], mapState.center.lng, mapState.zoom); } else if (-180 <= heading3D && heading3D <= -90) { var RoraHead = Math.abs((map23DData.view.heading + 180) / 180 * Math.PI); gausscenter[1] = gausscenter[1] + h * Math.sin(RoraTilt) * Math.cos(RoraHead); gausscenter[0] = gausscenter[0] - h * Math.sin(RoraTilt) * Math.sin(RoraHead); var mapsetlatlng = gaussToGeo(gausscenter[0], gausscenter[1], mapState.center.lng, mapState.zoom); } else if (0 < heading3D && heading3D <= 90) { var RoraHead = Math.abs(map23DData.view.heading / 180 * Math.PI); gausscenter[1] = gausscenter[1] - h * Math.sin(RoraTilt) * Math.cos(RoraHead); gausscenter[0] = gausscenter[0] - h * Math.sin(RoraTilt) * Math.sin(RoraHead); var mapsetlatlng = gaussToGeo(gausscenter[0], gausscenter[1], mapState.center.lng, mapState.zoom); } else if (90 < heading3D && heading3D <= 180) { var RoraHead = Math.abs((180 - map23DData.view.heading) / 180 * Math.PI); gausscenter[1] = gausscenter[1] + h * Math.sin(RoraTilt) * Math.cos(RoraHead); gausscenter[0] = gausscenter[0] + h * Math.sin(RoraTilt) * Math.sin(RoraHead); var mapsetlatlng = gaussToGeo(gausscenter[0], gausscenter[1], mapState.center.lng, mapState.zoom); } return { View3Dlat: mapsetlatlng.latitude, View3Dlng: mapsetlatlng.longitude } } /** * 北半球高纬度雷达转换 */ function northHeightLatLD(coordinates) { var positive; var isPositive = false; for (var i = 0; i < coordinates.length - 2; i++) { if (coordinates[i][0] - coordinates[i + 1][0] > 0) { if (!isPositive) { positive = i; isPositive = true; } coordinates[i + 1][0] = coordinates[positive][0] * 2 - coordinates[i + 1][0]; } } return coordinates; } /** * 南半球高纬度雷达经纬度转换 */ function southHeightLatLD(coordinates) { var negative; var isNegative = false; for (var i = 0; i < coordinates.length - 2; i++) { if (coordinates[i][0] - coordinates[i + 1][0] < 0) { if (!isNegative) { negative = i; isNegative = true; } coordinates[i + 1][0] = coordinates[negative][0] * 2 - coordinates[i + 1][0]; } } return coordinates; } /** * 计算雷达半球最低拉伸高度 */ function getLDCircleExtrude(radius) { var earthRadius = 6371000; //地球半径 var tangle = (360 * radius) / (4 * Math.PI * earthRadius); tangle = tangle * Math.PI / 180; var minExtrude = 2 * earthRadius * Math.sin(tangle) * Math.sin(tangle); return minExtrude; }; /** * 经纬度转高斯坐标 */ function coordn_to_gauss(mapCenter_data, zoom) { var mapxy = mapCenter_data; var longitude = mapCenter_data[0]; var latitude = mapCenter_data[1]; var f = 1.0 / 298.257222101; var a = 6378137; var ipi = Math.PI / 180; var X0 = 500000; var Y0 = 0; longitude = parseFloat(longitude); latitude = parseFloat(latitude); if (zoom >= 16) { ProjNo = parseInt((longitude) / 3); longitude0 = ProjNo * 3; } else { ProjNo = parseInt((longitude) / 6); longitude0 = ProjNo * 6 + 3; } longitude0 = longitude0 * ipi; latitude0 = 0; longitude1 = longitude * ipi; latitude1 = latitude * ipi; e2 = 2 * f - f * f; ee = e2 * (1.0 - e2); NN = a / Math.sqrt(1.0 - e2 * Math.sin(latitude1) * Math.sin(latitude1)); T = Math.tan(latitude1) * Math.tan(latitude1); C = ee * Math.cos(latitude1) * Math.cos(latitude1); A = (longitude1 - longitude0) * Math.cos(latitude1); M = a * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * latitude1 - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2 / 1024) * Math.sin(2 * latitude1) + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072) * Math.sin(6 * latitude1)); xval = NN * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee) * A * A * A * A * A / 120); yval = M + NN * Math.tan(latitude1) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * ee) * A * A * A * A * A * A / 720); xval = xval + X0; yval = yval + Y0; X = xval; X = parseInt((X - 500000) * 0.9996 + 500000); Y = yval; Y = parseInt(Y * 0.9996); return [X, Y]; } /** * 高斯坐标转经纬度 */ function gaussToGeo(X, Y, lng, zoom) { var f = 1.0 / 298.257222101; var X0 = 500000; var Y0 = 0; var iPI = Math.PI / 180; var a = 6378137; if (zoom >= 16) { var ZoneWide = 3; var ProjNo = parseInt((lng) / ZoneWide); var longitude0 = ProjNo * ZoneWide; } else { var ZoneWide = 6; var ProjNo = parseInt((lng) / ZoneWide); var longitude0 = ProjNo * ZoneWide + ZoneWide / 2 } longitude0 = longitude0 * iPI X = (X - 500000) / 0.9996 + 500000; Y = Y / 0.9996; var xval = X - X0; var yval = Y - Y0; var e2 = 2 * f - f * f; var e1 = (1.0 - Math.sqrt(1 - e2)) / (1.0 + Math.sqrt(1 - e2)); var ee = e2 / (1 - e2); var M = yval; var u = M / (a * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256)); var fai = u + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * u) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * u) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * u) + (1097 * e1 * e1 * e1 * e1 / 512) * Math.sin(8 * u); var C = ee * Math.cos(fai) * Math.cos(fai); var T = Math.tan(fai) * Math.tan(fai); var NN = a / Math.sqrt(1.0 - e2 * Math.sin(fai) * Math.sin(fai)); var R = a * (1 - e2) / Math.sqrt((1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai))); var D = xval / NN; longitude1 = longitude0 + (D - (1 + 2 * T + C) * D * D * D / 6 + (5 - 2 * C + 28 * T - 3 * C * C + 8 * ee + 24 * T * T) * D * D * D * D * D / 120) / Math.cos(fai); latitude1 = fai - (NN * Math.tan(fai) / R) * (D * D / 2 - (5 + 3 * T + 10 * C - 4 * C * C - 9 * ee) * D * D * D * D / 24 + (61 + 90 * T + 298 * C + 45 * T * T - 256 * ee - 3 * C * C) * D * D * D * D * D * D / 720); longitude = longitude1 / iPI; latitude = latitude1 / iPI; return { longitude: longitude, latitude: latitude } } /** * 坐标反转 * @param {[type]} latlngsAry [description] * @return {[type]} [description] */ function latLngsToReverse(latlngsAry) { var tempLatlngsAry = JSON.parse(JSON.stringify(latlngsAry)); if (!_.isArray(tempLatlngsAry[0])) { return tempLatlngsAry.reverse(); } else { for (var i = 0, l = tempLatlngsAry.length; i < l; i++) { tempLatlngsAry[i] = latLngsToReverse(tempLatlngsAry[i]); } } return tempLatlngsAry; } function getCentroid(arr) { var twoTimesSignedArea = 0; var cxTimes6SignedArea = 0; var cyTimes6SignedArea = 0; var length = arr.length; var x = function(i) { return arr[i % length][0] }; var y = function(i) { return arr[i % length][1] }; for (var i = 0; i < arr.length; i++) { var twoSA = x(i) * y(i + 1) - x(i + 1) * y(i); twoTimesSignedArea += twoSA; cxTimes6SignedArea += (x(i) + x(i + 1)) * twoSA; cyTimes6SignedArea += (y(i) + y(i + 1)) * twoSA; } var sixSignedArea = 3 * twoTimesSignedArea; return [cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea]; } window.map23DUtil = { latLngsToReverse: latLngsToReverse, getCentroid: getCentroid, latlngsTo3DViewCenter: latlngsTo3DViewCenter, gaussToGeo: gaussToGeo, coordn_to_gauss: coordn_to_gauss, getLDCircleExtrude: getLDCircleExtrude, dateLineLnglatsToLnglats: dateLineLnglatsToLnglats, lnglatsToDateLineLnglats: lnglatsToDateLineLnglats, northHeightLatLD: northHeightLatLD, southHeightLatLD: southHeightLatLD, getGeoGatheringPlace: getGeoGatheringPlace, get3DPixToLnglat: get3DPixToLnglat }; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map23DUtil; } else if (typeof define === 'function' && define.amd) { define(map23DUtil); } }(window, document)); ; (function (window, document, undefined) { window.map23DDefaultData = { imageOverlay: { from: '23D', type: 'imageOverlay', guid: null, //图层ID tileLayer23D/tileLayer2D/tileLayer3D add2D: false, //2D是否已添加 add3D: false, //3D是否已添加 visible2D: false, visible3D: false, layers: { opacity: 1, //2D透明度 layerBounds: [ [80, -180], [-80, 180] ], //左上角 右下角 imageUrl2D: null, //2D图片地址 imageUrl3D: null //3D图片服务地址 } }, layer: { from: '23D', type: 'tileLayer', guid: null, //图层ID tileLayer23D/tileLayer2D/tileLayer3D add2D: false, //2D是否已添加 add3D: false, //3D是否已添加 visible2D: false, visible3D: false, layer: { url2D: null, //2D瓦片服务地址 url3D: null, //3D瓦片服务地址 minZoom: map23DConfig.map23DMinZoom || 1, //23D最大缩放等级 maxZoom: map23DConfig.map23DMaxZoom || 21, //23D最小缩放等级 maxNativeZoom: map23DConfig.map2DMaxZoom || 21, //2D最大渲染等级 tileSubdomains: '0123456789', attribution: null, //瓦片附属信息 opacity: 1, //瓦片透明度 layerBounds: [ [90, -180], [-90, 180] ], //左上角 右下角 imageType: 'png' //3D瓦片图片类型 } }, DEMLayer: { from: '23D', type: 'tileLayer', guid: null, //图层ID tileLayer23D/tileLayer2D/tileLayer3D add2D: false, //2D是否已添加 add3D: false, //3D是否已添加 visible2D: false, visible3D: false, layer: { url2D: null, // 2D瓦片服务地址 url3D: null, // 3D瓦片服务地址 DEMFormat: "bil", // bil terrain DEMMaxZoom: 9 // DEM最大 } }, group: { from: '23D', type: 'group', guid: null, //图层组ID group23D/group2D/group3D add2D: false, //2D是否已添加 add3D: false, //3D是否已添加 visible2D: false, visible3D: false, clustering: false, //2D是否聚合 clusterOptions: { maxClusterRadius: 120, //多少像素距离的点会聚合 默认小于120像素内的点会聚合 polygonOptions: { weight: 1, opacity: 0.5 }, //聚合范围面样式 showCoverageOnHover: true, //是否显示聚合范围 disableClusteringAtZoom: null, //设置到达指定缩放等级后禁用聚合 } //2D聚合参数 }, marker: { from: '23D', type: 'marker', guid: null, //标记ID marker23D/marker2D/marker3D add2D: false, add3D: false, visible2D: false, visible3D: false, groupId: null, animate: false, vectorMarker: false, geojson: { "type": "Feature", "properties": { title: null, titleColor: '#FFFFFF', titleFontSize: 12, baseSize: null, //矢量图片基础大小 控制地图缩放时显示 baseZoom: null, //矢量图片基础缩放级别 iconUrl: null, icon3DUrl: null, iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], popupContent: null, altitude: 0, altitudeMode: 0, iconRorate: 0, iconScale: 10, fontIcon: null, fontSize: null, fontColor: null, fontWeight: null, distanceDisplayCondition: [0, 100000000] }, "geometry": { "type": "Point", "coordinates": [0, 0] } } }, polyline: { from: '23D', type: 'polyline', guid: null, add2D: false, add3D: false, visible2D: false, visible3D: false, groupId: null, linetype: 'line', geojson: { "type": "Feature", "properties": { title: null, color: '#0033ff', weight: 1, opacity: 1, popupContent: null, dashArray: null, lineType: 0, //3D用 Solid:0/Dash:1/Dot:2/DashDot:3/DashDotDot:4 extrude: 0, //拉伸高度 altitude: 0, //海拔高度 altitudeMode: 1 }, "geometry": { "type": "LineString", "coordinates": [ [0, 0] ] } } }, polygon: { from: '23D', type: 'polygon', guid: null, add2D: false, add3D: false, visible2D: false, visible3D: false, groupId: null, polygontype: 'polygon', geojson: { "type": "Feature", "properties": { title: null, color: '#ff0000', weight: 1, //cesium部分外边框宽度固定为1 fillColor: '#ff6600', opacity: 1, fillOpacity: 1, popupContent: null, extrude: 0, altitude: 0, altitudeMode: 1, extrudedHeight: 0 }, "geometry": { "type": "Polygon", "coordinates": [ [0, 0] ] } } }, circle: { from: '23D', type: 'circle', guid: null, add2D: false, add3D: false, visible2D: false, visible3D: false, groupId: null, geojson: { "type": "Feature", "properties": { title: null, radius: 0, //半径 米 color: '#ff0000', weight: 1, //cesium部分外边框宽度固定为1 opacity: 1, fillColor: '#ff6600', fillOpacity: 1, popupContent: null, extrude: 0, altitude: 0, altitudeMode: 1 }, "geometry": { "type": "Circle", "coordinates": [0, 0] } } }, circleMarker: { from: '23D', type: 'circleMarker', guid: null, add2D: false, add3D: false, visible2D: false, visible3D: false, groupId: null, geojson: { "type": "Feature", "properties": { title: null, radius: 0, //半径 米 color: '#ff0000', weight: 1, fillColor: '#ff6600', opacity: 1, fillOpacity: 1, popupContent: null, stroke: false, extrude: 0, altitude: 0, altitudeMode: 1 }, "geometry": { "type": "CircleMarker", "coordinates": [0, 0] } } }, model: { from: '23D', type: 'model', guid: null, groupId: null, add2D: false, add3D: false, visible2D: false, visible3D: false, geojson: { "type": "Feature", "properties": { title: null, popupContent: null, url: null, timeLine: [0], anination: false, altitudeMode: 1, //高度模式 0否1是 altitude: [0], //高度 scale: 1, path: true, pathColor: '#ffffff', pathWidth: 10, }, "geometry": { "type": "Model", "coordinates": [ [0, 0] ////经度,纬度(时间戳为秒级, 仅在anination为true时与时间戳) ], } }, }, radar: { from: '23D', type: 'radar', center: { lat: 39, lng: 116 }, radius: 10000, //雷达半径 circleTangle: 10, //雷达高度密度1,5,10·····90 circlePointDensity: 5, //雷达圆周密度1,5,10·····90 // height: 1000, //中心点高度 properties: { color: '#00ff00', weight: 1, opacity: 1, }, display: { show2D: true, show3D: true } } } window.map23DData = { mouseIn: '2D', //2D or 3D display: { map2D: false, map3D: false }, synch: false, //二三维是否同步 同步则同时加载,不同步则只加载一部分 view: { center: { lat: 39, lng: 116 }, zoom: 12, heading: 0, //摄像机平面角度 正北为0 pitch: 90, //摄像机倾斜角 distance: 0 //摄像机距地面高度 }, layers: {}, DEMLayers: {}, imageOverlays: {}, groups: {}, markers: {}, polylines: {}, circles: {}, circleMarkers: {}, polygons: {}, models: {}, timeLineData: {}, radar: {} }; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map23DData; } else if (typeof define === 'function' && define.amd) { define(map23DData); } }(window, document)); ; (function (window, document, undefined) { window.map23DControl = {}; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map23DControl; } else if (typeof define === 'function' && define.amd) { define(map23DControl); } map23DControl.init = function (options) { var _this = this; _.merge(map23DData, options); this.mapWrap = document.getElementById(map23DData.mapWrapId); this.map2DWrap = document.createElement('div'); this.map2DWrap.id = 'map2DWrap'; this.mapWrap.appendChild(this.map2DWrap); this.map3DWrap = document.createElement('div'); this.map3DWrap.id = 'map3DWrap'; this.mapWrap.appendChild(this.map3DWrap); if (map23DData.synch) { map2DViewer.init(); map3DViewer.init(); if (map23DData.display.map2D == true && map23DData.display.map3D == false) { this.mapWrap.className = 'show2DOnly'; } else if (map23DData.display.map3D == true && map23DData.display.map2D == false) { this.mapWrap.className = 'show3DOnly'; } } else { if (map23DData.display.map2D == true && map23DData.display.map3D == false) { this.mapWrap.className = 'show2DOnly'; map2DViewer.init(); } else if (map23DData.display.map3D == true && map23DData.display.map2D == false) { this.mapWrap.className = 'show3DOnly'; map3DViewer.init(); } else if (map23DData.display.map2D == false && map23DData.display.map3D == false) { } else { map2DViewer.init(); map3DViewer.init(); } } _this.map2DWrap.onmouseover = function (e) { map23DData.mouseIn = '2D'; _this.map2DWrap.focus(); } _this.map3DWrap.onmouseover = function (e) { map23DData.mouseIn = '3D'; if (map3DViewer.inited) { _this.map3DWrap.focus(); } } } map23DControl.show2D = function () { this.mapWrap = document.getElementById(map23DData.mapWrapId); this.mapWrap.className = 'show2DOnly'; _.merge(map23DData, { display: { map2D: true, map3D: false } }); PubSub.publish('map23D.show2D', { from: '23D' }); } map23DControl.show3D = function () { this.mapWrap = document.getElementById(map23DData.mapWrapId); this.mapWrap.className = 'show3DOnly'; _.merge(map23DData, { display: { map2D: false, map3D: true } }); PubSub.publish('map23D.show3D', { from: '23D' }); } map23DControl.show23D = function () { this.mapWrap = document.getElementById(map23DData.mapWrapId); this.mapWrap.className = ''; _.merge(map23DData, { display: { map2D: true, map3D: true } }); PubSub.publish('map23D.show23D', { from: '23D' }) } /** * 生成随机GUID * @param {[type]} options [description] * @return {[type]} [description] */ map23DControl.buildGuid = function (options) { var text = ""; var mar = options || 'default'; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for (var i = 0; i < 18; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return mar + '_' + (new Date()).getTime().toString() + text; } map23DControl.setView = function (options) { _.merge(map23DData.view, options); PubSub.publish('map23D.setView', { from: '23D' }) } map23DControl.flyTo = function (options, callback) { _.merge(map23DData.view, options); PubSub.publish('map23D.flyTo', { from: '23D', callback: null, }) } //高斯转经纬度 map23DControl.coordn_to_gauss = function (mapCenter_data, zoom, curZoingNum) { var mapxy = mapCenter_data; var longitude = mapCenter_data[0]; var latitude = mapCenter_data[1]; var f = 1.0 / 298.257222101; var a = 6378137; var ipi = Math.PI / 180; var X0 = 500000; var Y0 = 0; longitude = parseFloat(longitude); latitude = parseFloat(latitude); if (curZoingNum == 6) { ProjNo = parseInt((longitude) / 6); longitude0 = ProjNo * 6 + 3; } else if (curZoingNum == 3) { ProjNo = parseInt((longitude) / 3); longitude0 = ProjNo * 3; } else { if (zoom >= 16) { ProjNo = parseInt((longitude) / 3); longitude0 = ProjNo * 3; } else { ProjNo = parseInt((longitude) / 6); longitude0 = ProjNo * 6 + 3; } } longitude0 = longitude0 * ipi; latitude0 = 0; longitude1 = longitude * ipi; latitude1 = latitude * ipi; e2 = 2 * f - f * f; ee = e2 * (1.0 - e2); NN = a / Math.sqrt(1.0 - e2 * Math.sin(latitude1) * Math.sin(latitude1)); T = Math.tan(latitude1) * Math.tan(latitude1); C = ee * Math.cos(latitude1) * Math.cos(latitude1); A = (longitude1 - longitude0) * Math.cos(latitude1); M = a * ((1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256) * latitude1 - (3 * e2 / 8 + 3 * e2 * e2 / 32 + 45 * e2 * e2 * e2 / 1024) * Math.sin(2 * latitude1) + (15 * e2 * e2 / 256 + 45 * e2 * e2 * e2 / 1024) * Math.sin(4 * latitude1) - (35 * e2 * e2 * e2 / 3072) * Math.sin(6 * latitude1)); xval = NN * (A + (1 - T + C) * A * A * A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee) * A * A * A * A * A / 120); yval = M + NN * Math.tan(latitude1) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * ee) * A * A * A * A * A * A / 720); xval = xval + X0; yval = yval + Y0; X = xval; X = parseInt((X - 500000) * 0.9996 + 500000); Y = yval; Y = parseInt(Y * 0.9996); return [X, Y]; } //经纬度转高斯 map23DControl.gaussToGeo = function (X, Y, lng, zoom) { var f = 1.0 / 298.257222101; var X0 = 500000; var Y0 = 0; var iPI = Math.PI / 180; var a = 6378137; if (zoom >= 16) { var ZoneWide = 3; var ProjNo = parseInt((lng) / ZoneWide); var longitude0 = ProjNo * ZoneWide; } else { var ZoneWide = 6; var ProjNo = parseInt((lng) / ZoneWide); var longitude0 = ProjNo * ZoneWide + ZoneWide / 2 } longitude0 = longitude0 * iPI X = (X - 500000) / 0.9996 + 500000; Y = Y / 0.9996; var xval = X - X0; var yval = Y - Y0; var e2 = 2 * f - f * f; var e1 = (1.0 - Math.sqrt(1 - e2)) / (1.0 + Math.sqrt(1 - e2)); var ee = e2 / (1 - e2); var M = yval; var u = M / (a * (1 - e2 / 4 - 3 * e2 * e2 / 64 - 5 * e2 * e2 * e2 / 256)); var fai = u + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * u) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * u) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * u) + (1097 * e1 * e1 * e1 * e1 / 512) * Math.sin(8 * u); var C = ee * Math.cos(fai) * Math.cos(fai); var T = Math.tan(fai) * Math.tan(fai); var NN = a / Math.sqrt(1.0 - e2 * Math.sin(fai) * Math.sin(fai)); var R = a * (1 - e2) / Math.sqrt((1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai)) * (1 - e2 * Math.sin(fai) * Math.sin(fai))); var D = xval / NN; longitude1 = longitude0 + (D - (1 + 2 * T + C) * D * D * D / 6 + (5 - 2 * C + 28 * T - 3 * C * C + 8 * ee + 24 * T * T) * D * D * D * D * D / 120) / Math.cos(fai); latitude1 = fai - (NN * Math.tan(fai) / R) * (D * D / 2 - (5 + 3 * T + 10 * C - 4 * C * C - 9 * ee) * D * D * D * D / 24 + (61 + 90 * T + 298 * C + 45 * T * T - 256 * ee - 3 * C * C) * D * D * D * D * D * D / 720); longitude = longitude1 / iPI; latitude = latitude1 / iPI; return { longitude: longitude, latitude: latitude } } //墨卡托转经纬度 map23DControl.mercatorToLatlng = function (mercator) { var lonLat = {}; var x = mercator.X / 20037508.34 * 180; var y = mercator.Y / 20037508.34 * 180; y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2); lonLat.lng = x; lonLat.lat = y; return lonLat; } /** * 经纬度转墨卡托 */ map23DControl.transformMercator = function (lonLat) { var mercator = {}; var x = lonLat.x * 20037508.34 / 180; var y = Math.log(Math.tan((90 + lonLat.y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.x = x; mercator.y = y; return mercator; }; //经纬度十进制转六进制 map23DControl.formatDegree = function (value) { value = Math.abs(value); var v1 = Math.floor(value); //度 var v2 = Math.floor((value - v1) * 60); //分 var v3 = Math.round((value - v1) * 3600 % 60); //秒 return v1 + '°' + v2 + '\'' + v3 + '"'; } //经纬度六进制转十进制 map23DControl.DegreeConvertBack = function (value) { var du = value.split("°")[0]; var fen = value.split("°")[1].split("'")[0]; var miao = value.split("°")[1].split("'")[1].split('"')[0]; return Math.abs(du) + (Math.abs(fen) / 60 + Math.abs(miao) / 3600); } //颜色16进制转10进制 map23DControl.SLTransToS = function (color) { color = color.split("#"); colorS = color[1].slice(0, 2); colorS = parseInt("0x" + colorS); colorF = color[1].slice(2, 4); colorF = parseInt("0x" + colorF); colorT = color[1].slice(4); colorT = parseInt("0x" + colorT); return [colorS, colorF, colorT, 255] } //卫星增删改 map23DControl.satelliteModel = function (options) { switch (options.action) { case 'add': return addSatelliteModel(options.satellite); break; case 'update': return updateSatelliteModel(options); break; case 'remove': return removeSatelliteModel(options); break; } } /** * 添加卫星单元 * 经纬度、高度、角度 */ addSatelliteModel = function (options, atelliteTraData) { var satelliteId = { polygonId: null, modelId: null, polylineId: [], GDId: null, markerId: null }; var cahlatlng = options.breadth / 111000 / 2; var lng = options.lng; var lat = options.lat; var altitule = options.altitude; var angle = options.angle - 90; var weixingC = [lng, lat]; //添加卫星2D点 var markerId = map2DViewer.marker({ action: 'add', geojson: { "properties": { title: options.properties.WXtitle, iconUrl: options.model2DUrl, //当有fontIcon的时候 iconUrl无效 iconSize: options.properties.iconSize, iconAnchor: options.properties.iconAnchor, popupAnchor: options.properties.popupAnchor, popupContent: options.properties.popupContent, iconRorate: angle + 180, }, "geometry": { "coordinates": weixingC } } }) satelliteId.markerId = markerId; //添加卫星轨道 //添加23D线 var GDguid = map23DControl.polyline({ action: 'add', geojson: { "properties": { title: options.properties.GDtitle, color: options.properties.GDColor, weight: options.properties.GDWeight, opacity: options.properties.GDopacity, extrude: 0, //拉伸高度 altitude: options.satelliteTraData.height, //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": map23DUtil.lnglatsToDateLineLnglats(options.satelliteTraData.coordinates) } } }) satelliteId.GDId = GDguid; var model = map3DViewer.model({ action: 'add', geojson: { "properties": { title: options.properties.WXtitle, url: options.modelUrl, altitude: altitule, //高度 altitudeMode: 1, //高度模式 scale: options.properties.scale, //放大倍数 rotate: [0, 0, angle], //前倾角度,左右摆角,平面转角 visible: true }, "geometry": { "coordinates": weixingC //纬度,经度 } } }) satelliteId.modelId = model; //画面 var polygonCoors = map2DViewer.PointToPolygon([lng + cahlatlng, lat + cahlatlng], [lng - cahlatlng, lat - cahlatlng]); var modelpolygonguid = map23DControl.polygon({ action: 'add', geojson: { "properties": { title: options.properties.breadthPloygonTitle, color: options.properties.breadthColor, weight: options.properties.breadthWeight, fillColor: options.properties.breadthFillColor, opacity: options.properties.breadthOpacity, fillOpacity: options.properties.breadthFillOpacity, extrude: 0, //拉伸高度 altitude: [16000, 11000, 8000, 4000, 5000, 9000, 16000], //点海拔高度 altitudeMode: 0 //海拔模式 }, "geometry": { "type": "Polygon", "coordinates": [ polygonCoors.coordinates ] } } }) satelliteId.polygonId = modelpolygonguid; for (var i = 0; i < polygonCoors.coordinates.length; i++) { var guid = map23DControl.polyline({ action: 'add', geojson: { "properties": { title: options.properties.lineTitle, color: options.properties.lineColor, weight: options.properties.lineWeigth, opacity: options.properties.lineOpacity, altitude: [altitule, 0], //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": [ weixingC, polygonCoors.coordinates[i] ] } } }) satelliteId.polylineId.push(guid); } return satelliteId; } /** * 删除卫星单元 * 卫星单元GUID */ removeSatelliteModel = function (options) { //删除卫星轨道 map23DControl.polyline({ action: 'remove', guid: options.satelliteId.GDId }) //删除卫星模型 map3DViewer.model({ action: 'remove', guid: options.satelliteId.modelId }) //删除卫星扫描面 map23DControl.polygon({ action: 'remove', guid: options.satelliteId.polygonId }) //删除2D卫星点 map2DViewer.marker({ action: 'remove', guid: options.satelliteId.markerId }) //删除卫星扫描四根线 for (var i = 0; i < options.satelliteId.polylineId.length; i++) { map23DControl.polyline({ action: 'remove', guid: options.satelliteId.polylineId[i] }) } } /** * 更新卫星单元 */ updateSatelliteModel = function (options) { var cahlatlng = options.satellite.breadth / 111000 / 2; var lng = options.satellite.lng; var lat = options.satellite.lat; var altitule = options.satellite.altitude; var angle = options.satellite.angle - 90; var weixingC = [lng, lat]; //更新2D卫星点 var oldmarkerData = map23DData.markers[options.satelliteId.markerId]; var judgewx = weixingC[0] - oldmarkerData.geojson.geometry.coordinates[0]; if (judgewx < 0) { var curweixingC = [weixingC[0] + 360, weixingC[1]]; } else { var curweixingC = weixingC; } map2DViewer.marker({ action: 'update', guid: options.satelliteId.markerId, geojson: { "properties": { title: options.satellite.properties.WXtitle, iconUrl: options.satellite.model2DUrl, //当有fontIcon的时候 iconUrl无效 iconSize: options.satellite.properties.iconSize, iconAnchor: options.satellite.properties.iconAnchor, popupAnchor: options.satellite.properties.popupAnchor, popupContent: options.satellite.properties.popupContent, iconRorate: angle + 180, }, "geometry": { "coordinates": curweixingC } } }) //更新卫星轨道 if (options.satellite.updata2DOrbit) { map23DControl.polyline({ action: 'update', guid: options.satelliteId.GDId, geojson: { "properties": { title: options.satellite.properties.GDtitle, color: options.satellite.properties.GDColor, weight: options.satellite.properties.GDWeight, opacity: options.satellite.properties.GDopacity, extrude: 0, //拉伸高度 altitude: options.satellite.satelliteTraData.height, //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": map23DUtil.lnglatsToDateLineLnglats(options.satellite.satelliteTraData.coordinates) } } }) } else { map3DViewer.polyline({ action: 'update', guid: options.satelliteId.GDId, geojson: { "properties": { title: options.satellite.properties.GDtitle, color: options.satellite.properties.GDColor, weight: options.satellite.properties.GDWeight, opacity: options.satellite.properties.GDopacity, extrude: 0, //拉伸高度 altitude: options.satellite.satelliteTraData.height, //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": map23DUtil.lnglatsToDateLineLnglats(options.satellite.satelliteTraData.coordinates) } } }) } //更新卫星模型 map3DViewer.model({ action: 'update', guid: options.satelliteId.modelId, geojson: { "properties": { title: options.satellite.properties.WXtitle, url: options.satellite.modelUrl, altitude: altitule, //高度 altitudeMode: 1, //高度模式 scale: options.satellite.properties.scale, //放大倍数 rotate: [0, 0, angle], //前倾角度,左右摆角,平面转角 visible: true }, "geometry": { "coordinates": weixingC //纬度,经度 } } }) //更新卫星扫描面 var polygonCoors = map2DViewer.PointToPolygon([lng + cahlatlng, lat + cahlatlng], [lng - cahlatlng, lat - cahlatlng]); var curcoordinates = []; if (judgewx < 0) { for (var i = 0; i < polygonCoors.coordinates.length; i++) { curcoordinates.push([polygonCoors.coordinates[i][0] + 360, polygonCoors.coordinates[i][1]]); } } else { curcoordinates = polygonCoors.coordinates; } if (map23DData.display.map2D) { map2DViewer.polygon({ action: 'update', guid: options.satelliteId.polygonId, geojson: { "properties": { title: options.satellite.properties.breadthPloygonTitle, color: options.satellite.properties.breadthColor, weight: options.satellite.properties.breadthWeight, fillColor: options.satellite.properties.breadthFillColor, opacity: options.satellite.properties.breadthOpacity, fillOpacity: options.satellite.properties.breadthFillOpacity, extrude: 0, //拉伸高度 altitude: [16000, 11000, 8000, 4000, 5000, 9000, 16000], //点海拔高度 altitudeMode: 0 //海拔模式 }, "geometry": { "type": "Polygon", "coordinates": [ curcoordinates ] } } }) } else if (map23DData.display.map3D) { map3DViewer.polygon({ action: 'update', guid: options.satelliteId.polygonId, geojson: { "properties": { title: options.satellite.properties.breadthPloygonTitle, color: options.satellite.properties.breadthColor, weight: options.satellite.properties.breadthWeight, fillColor: options.satellite.properties.breadthFillColor, opacity: options.satellite.properties.breadthOpacity, fillOpacity: options.satellite.properties.breadthFillOpacity, extrude: 0, //拉伸高度 altitude: [16000, 11000, 8000, 4000, 5000, 9000, 16000], //点海拔高度 altitudeMode: 0 //海拔模式 }, "geometry": { "type": "Polygon", "coordinates": [ polygonCoors.coordinates ] } } }) } //更新卫星扫描四根线 for (var i = 0; i < polygonCoors.coordinates.length; i++) { if (map23DData.display.map2D) { map2DViewer.polyline({ action: 'update', guid: options.satelliteId.polylineId[i], geojson: { "properties": { title: options.satellite.properties.lineTitle, color: options.satellite.properties.lineColor, weight: options.satellite.properties.lineWeigth, opacity: options.satellite.properties.lineOpacity, altitude: [altitule, 0], //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": [ curweixingC, curcoordinates[i] ] } } }) } else if (map23DData.display.map3D) { map3DViewer.polyline({ action: 'update', guid: options.satelliteId.polylineId[i], geojson: { "properties": { title: options.satellite.properties.lineTitle, color: options.satellite.properties.lineColor, weight: options.satellite.properties.lineWeigth, opacity: options.satellite.properties.lineOpacity, altitude: [altitule, 0], //点海拔高度 altitudeMode: 1 //海拔模式 }, "geometry": { "coordinates": [ curweixingC, polygonCoors.coordinates[i] ] } } }) } } } }(window, document)); ; (function (window, document, undefined) { window.map2DViewer = { inited: false, markers: {}, layers: {}, polylines: {}, polygons: {}, circles: {}, circleMarkers: {}, models: {}, groups: {}, hide2D: false, syncTimeer: null, imageOverlays: {} }; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map2DViewer; } else if (typeof define === 'function' && define.amd) { define(map2DViewer); } PubSub.subscribe('map23D.show23D', function (msg, options) { if (options.from == '23D' && map23DData.display.map2D) { if (map2DViewer.inited) { map2DViewer.map.invalidateSize(); } else { map2DViewer.init(); } map2DViewer.hide2D = false; } }); PubSub.subscribe('map23D.show2D', function (msg, options) { if (options.from == '23D' && map23DData.display.map2D) { if (map2DViewer.inited) { map2DViewer.map.invalidateSize(); map2DViewer.map.setView([map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom); } else { map2DViewer.init(); //如果从隐藏到显示,添加所有因show3D隐藏的地图元素,添加同步 } map2DViewer.hide2D = false; } }); PubSub.subscribe('map23D.show3D', function (msg, options) { if (options.from == '23D') { if (map2DViewer.inited) { //移除所有显示的地图元素,并断开同步 map2DViewer.hide2D = true; } } }); //飞行定位 PubSub.subscribe('map23D.flyTo', function (msg, options) { //_.merge(map23DData.view, options); map2DViewer.map.flyTo( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); map23DData.mouseIn = '2D'; // PubSub.publish('map2D.setView', { // from: '2D' // }) }); map2DViewer.init = function (options) { var _this = map2DViewer; if (this.inited) { return; } else { this.inited = true; } var map2DDiv = document.createElement("div"); map2DDiv.id = "map2DDiv" document.getElementById("map2DWrap").appendChild(map2DDiv); this.map = L.map('map2DDiv', { editable: true, attributionControl: false, inertia: false, // fadeAnimation: false, // zoomAnimation: true, contextmenu: true, minZoom: map23DConfig.map2DMinZoom || 1, maxZoom: map23DConfig.map2DMaxZoom || 21, preferCanvas: false }).setView([map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom); this.polygonCanvasRenderer = L.canvas(); this.polylineCanvasRenderer = L.canvas(); this.rectangleCanvasRenderer = L.canvas(); this.circleleCanvasRenderer = L.canvas(); this.circleMarkerCanvasRenderer = L.canvas(); this.map.on('zoomend', function () { PubSub.publish('map2DViewerZoomend', { from: '2D' }) }) this.map.on('zoomend move', function (e) { if (map23DData.mouseIn != '2D') { return; } if (map2DViewer.syncTimeer) { return false; } map2DViewer.syncTimeer = setTimeout(function () { var mapState = { view: { center: { lat: e.target.getCenter().lat, lng: e.target.getCenter().lng }, zoom: _this.map.getZoom() } } _.merge(map23DData, mapState); PubSub.publish('map2D.setView', { from: '2D' }) clearTimeout(map2DViewer.syncTimeer); map2DViewer.syncTimeer = null; }, 300) }); PubSub.subscribe('map3D.setView', function (msg, options) { if (options.from == '3D' && map23DData.mouseIn == '3D' && !map2DViewer.hide2D) { _this.map.setView( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); } }); PubSub.subscribe('map3D.flyTo', function (msg, options) { if (options.from == '3D' && map23DData.mouseIn == '3D' && !map2DViewer.hide2D) { map2DViewer.map.flyTo( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); } }); PubSub.subscribe('map23D.setView', function (msg, options) { if (options.from == '23D' && !map2DViewer.hide2D) { _this.map.setView( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); } }); } /** * 根据两点坐标返回矩形坐标 * IN 进入坐标[lng,lat] * OUT 离开坐标[lng,lat] * 扫描宽度在1200KM内效果较好 */ map2DViewer.PointToPolygon = function (IN, OUT, inverse) { var polygonCoors = []; var zoom = map23DData.view.zoom; //两点之间距离 //var distanceIO = new L.LatLng(IN[0],IN[1]).distanceTo(new L.LatLng(OUT[0],OUT[1])); var distanceIO = Math.sqrt(Math.pow((IN[0] - OUT[0]), 2) + Math.pow((IN[1] - OUT[1]), 2)) //经纬度转换成高斯坐标 //var goosIN = window.map23DUtil.coordn_to_gauss(IN,zoom); //var goosOUT = window.map23DUtil.coordn_to_gauss(OUT,zoom); var goosIN = IN; var goosOUT = OUT; //中心点坐标 var centerLngLatGoos = [(goosIN[0] + goosOUT[0]) / 2, (goosIN[1] + goosOUT[1]) / 2]; var centerLngLat = [(IN[0] + OUT[0]) / 2, (IN[1] + OUT[1]) / 2]; if (goosIN[1] >= centerLngLatGoos[1]) { if (goosIN[0] > centerLngLatGoos[0]) { var tangle = L.Util.getAngleByLatLng(centerLngLat[0], centerLngLat[1], IN[0], IN[1]); } else { var tangle = 360 - L.Util.getAngleByLatLng(centerLngLat[0], centerLngLat[1], IN[0], IN[1]); } } else { if (goosIN[0] > centerLngLatGoos[0]) { var tangle = 360 - L.Util.getAngleByLatLng(IN[0], IN[1], centerLngLat[0], centerLngLat[1]); } else { var tangle = L.Util.getAngleByLatLng(IN[0], IN[1], centerLngLat[0], centerLngLat[1]); } } var curTangle = tangle; tangle = tangle / 180 * Math.PI; if (curTangle === 0) { var chaX = distanceIO / 2; var chaY = distanceIO / 2; var inverseGoos1 = [centerLngLatGoos[0] - chaX, centerLngLatGoos[1] + chaY]; var inverseGoos2 = [centerLngLatGoos[0] - chaX, centerLngLatGoos[1] - chaY]; var inverseGoos3 = [centerLngLatGoos[0] + chaX, centerLngLatGoos[1] - chaY]; var inverseGoos4 = [centerLngLatGoos[0] + chaX, centerLngLatGoos[1] + chaY]; } else if (curTangle === 90) { var chaX = distanceIO / 2; var chaY = distanceIO / 2; var inverseGoos1 = [centerLngLatGoos[0] - chaX, centerLngLatGoos[1] + chaY]; var inverseGoos2 = [centerLngLatGoos[0] - chaX, centerLngLatGoos[1] - chaY]; var inverseGoos3 = [centerLngLatGoos[0] + chaX, centerLngLatGoos[1] - chaY]; var inverseGoos4 = [centerLngLatGoos[0] + chaX, centerLngLatGoos[1] + chaY]; } else { var chaX = distanceIO * Math.cos(tangle); var chaY = distanceIO * Math.sin(tangle); if (!inverse) { chaY = chaY; chaX = chaX; } else { chaY = -chaY; chaX = -chaX; } var inverseGoos1 = goosIN; var inverseGoos2 = [goosIN[0] + chaX, goosIN[1] - chaY]; var inverseGoos3 = [goosOUT[0] + chaX, goosOUT[1] - chaY]; var inverseGoos4 = goosOUT; } var inverse1 = window.map23DUtil.gaussToGeo(inverseGoos1[0], inverseGoos1[1], IN[0], zoom); var inverse2 = window.map23DUtil.gaussToGeo(inverseGoos2[0], inverseGoos2[1], centerLngLat[0], zoom); var inverse3 = window.map23DUtil.gaussToGeo(inverseGoos3[0], inverseGoos3[1], centerLngLat[0], zoom); var inverse4 = window.map23DUtil.gaussToGeo(inverseGoos4[0], inverseGoos4[1], OUT[0], zoom); //polygonCoors.push([inverse1.longitude,inverse1.latitude]); //polygonCoors.push([inverse2.longitude,inverse2.latitude]); //polygonCoors.push([inverse3.longitude,inverse3.latitude]); //polygonCoors.push([inverse4.longitude,inverse4.latitude]); polygonCoors.push(inverseGoos1); polygonCoors.push(inverseGoos2); polygonCoors.push(inverseGoos3); polygonCoors.push(inverseGoos4); return ({ "coordinates": polygonCoors }) }; map2DViewer.setView = function (options) { _.merge(map23DData.view, options); map2DViewer.map.setView( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); map23DData.mouseIn = '2D'; PubSub.publish('map2D.setView', { from: '2D' }) } map2DViewer.flyTo = function (options) { _.merge(map23DData.view, options); map2DViewer.map.flyTo( [map23DData.view.center.lat, map23DData.view.center.lng], map23DData.view.zoom ); map23DData.mouseIn = '2D'; PubSub.publish('map2D.setView', { from: '2D' }) } //2D图层组 map2DViewer.group = function (options) { switch (options.action) { case 'add': return addGroup2D(options); break; case 'show': return showGroup2D(options); break; case 'hide': return hideGroup2D(options); break; case 'remove': return removeGroup2D(options); break; case 'cleanAll': return operationGroup2D(options, 'remove'); break; } } function addGroup2D(options) { var guid = options.guid || map23DControl.buildGuid('group2D'); var defaultData = _.cloneDeep(map23DDefaultData.group) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.groups[guid] = defaultData; PubSub.publishSync('map2D.group.add', guid); return guid; } function removeGroup2D(options) { if (map23DData.groups[options.guid]) { operationGroup2D(options, "remove"); PubSub.publishSync('map2D.group.remove', options.guid); if (map23DData.groups[options.guid].add3D == false) { delete map23DData.groups[options.guid]; } return options.guid; } else { return false; } } function showGroup2D(options) { if (map2DViewer.groups[options.guid]) { operationGroup2D(options, "show"); PubSub.publishSync('map2D.group.show', options.guid); return options.guid; } else { return false; } } function hideGroup2D(options) { if (map2DViewer.groups[options.guid]) { operationGroup2D(options, "hide"); PubSub.publishSync('map2D.group.hide', options.guid); return options.guid; } else { return false; } } function operationGroup2D(options, action) { if (map23DData.groups[options.guid]) { //移除点 _(map23DData.markers).forEach(function (item, key) { if (item.groupId == options.guid) { map2DViewer.marker({ action: action, guid: key }) } }); //移除线 _(map23DData.polylines).forEach(function (item, key) { if (item.groupId == options.guid) { map2DViewer.polyline({ action: action, guid: key }) } }); //移除面 _(map23DData.polygons).forEach(function (item, key) { if (item.groupId == options.guid) { map2DViewer.polygon({ action: action, guid: key }) } }); //移除圆 _(map23DData.circles).forEach(function (item, key) { if (item.groupId == options.guid) { map2DViewer.circle({ action: action, guid: key }) } }); //移除圆标记 _(map23DData.circleMarkers).forEach(function (item, key) { if (item.groupId == options.guid) { map2DViewer.circleMarker({ action: action, guid: key }) } }); return options.guid; } else { return false } } //2D 点 map2DViewer.marker = function (options) { switch (options.action) { case 'add': return addMarker2D(options); break; case 'remove': return removeMarker2D(options); break; case 'update': return updateMarker2D(options); break; case 'hide': return hideMarker2D(options); break; case 'show': return showMarker2D(options); break; } } function addMarker2D(options) { var guid = options.guid || map23DControl.buildGuid('marker2D'); if (!options.RBkey) { var markerTime = null; } else { var markerTime = map23DData.polylines[map2DViewer.routeBackGroup[options.RBkey].polyline].geojson.properties.times; } if (options.vectorMarker) { var dataSize = options.geojson.properties.baseSize; var curZoom = map23DData.view.zoom; if (curZoom >= options.geojson.properties.baseZoom) { var scaleX = dataSize[0] + dataSize[0] * (curZoom - options.geojson.properties.baseZoom); var scaleY = dataSize[1] + dataSize[1] * (curZoom - options.geojson.properties.baseZoom); } else { var scaleX = dataSize[0] * Math.pow(options.geojson.properties.baseZoom - curZoom + 1, -1); var scaleY = dataSize[1] * Math.pow(options.geojson.properties.baseZoom - curZoom + 1, -1); } options.geojson.properties.iconSize = [scaleX, scaleY]; options.geojson.properties.iconAnchor = [scaleX / 2, scaleY / 2]; options.geojson.properties.popupAnchor = [0, -scaleY]; } var defaultData = _.cloneDeep(map23DDefaultData.marker) defaultData.guid = guid; defaultData.from = '2D'; defaultData.geojson.geometry.markerTime = markerTime; _.merge(defaultData, options); map23DData.markers[guid] = defaultData; PubSub.publishSync('map2D.marker.add', guid); return guid; } function showMarker2D(options) { if (map2DViewer.markers[options.guid]) { PubSub.publishSync('map2D.marker.show', options.guid); return options.guid; } else { return false; } } function hideMarker2D(options) { if (map2DViewer.markers[options.guid]) { PubSub.publishSync('map2D.marker.hide', options.guid); return options.guid; } else { return false; } } function removeMarker2D(options) { if (map23DData.markers[options.guid]) { PubSub.publishSync('map2D.marker.remove', options.guid); if (map23DData.markers[options.guid].add3D == false) { delete map23DData.markers[options.guid]; } return options.guid; } else { return false; } } function updateMarker2D(options) { if (map23DData.markers[options.guid]) { _.merge(map23DData.markers[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.markers[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map2D.marker.update', options.guid); return options.guid; } else { return false; } } //2D 线 map2DViewer.polyline = function (options) { switch (options.action) { case 'add': return addPolyline2D(options); break; case 'show': return showPolyline2D(options); break; case 'hide': return hidePolyline2D(options); break; case 'remove': return removePolyline2D(options); break; case 'update': return updatePolyline2D(options); break; } } function addPolyline2D(options) { var guid = options.guid || map23DControl.buildGuid('polyline2D'); var defaultData = _.cloneDeep(map23DDefaultData.polyline) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.polylines[guid] = defaultData; PubSub.publishSync('map2D.polyline.add', guid); return guid; } function showPolyline2D(options) { if (map2DViewer.polylines[options.guid]) { PubSub.publishSync('map2D.polyline.show', options.guid); return options.guid; } else { return false; } } function hidePolyline2D(options) { if (map2DViewer.polylines[options.guid]) { PubSub.publishSync('map2D.polyline.hide', options.guid); return options.guid; } else { return false; } } function removePolyline2D(options) { if (map23DData.polylines[options.guid]) { PubSub.publishSync('map2D.polyline.remove', options.guid); if (map23DData.polylines[options.guid].add3D == false) { delete map23DData.polylines[options.guid]; } return options.guid; } else { return false; } } function updatePolyline2D(options) { if (map23DData.polylines[options.guid]) { _.merge(map23DData.polylines[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polylines[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map2D.polyline.update', options.guid); return options.guid; } else { return false; } } //2D 面 map2DViewer.polygon = function (options) { switch (options.action) { case 'add': return addPolygon2D(options); break; case 'show': return showPolygon2D(options); break; case 'hide': return hidePolygon2D(options); break; case 'remove': return removePolygon2D(options); break; case 'update': return updatePolygon2D(options); break; } } function addPolygon2D(options) { var guid = options.guid || map23DControl.buildGuid('polygon2D'); var defaultData = _.cloneDeep(map23DDefaultData.polyline) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.polygons[guid] = defaultData; PubSub.publishSync('map2D.polygon.add', guid); return guid; } function showPolygon2D(options) { if (map2DViewer.polygons[options.guid]) { PubSub.publishSync('map2D.polygon.show', options.guid); return options.guid; } else { return false; } } function hidePolygon2D(options) { if (map2DViewer.polygons[options.guid]) { PubSub.publishSync('map2D.polygon.hide', options.guid); return options.guid; } else { return false; } } function removePolygon2D(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map2D.polygon.remove', options.guid); if (map23DData.polygons[options.guid].add3D == false) { delete map23DData.polygons[options.guid]; } return options.guid; } else { return false; } } function updatePolygon2D(options) { if (map23DData.polygons[options.guid]) { _.merge(map23DData.polygons[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polygons[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map2D.polygon.update', options.guid); return options.guid; } else { return false; } } //2D 圆 map2DViewer.circle = function (options) { switch (options.action) { case 'add': return addCircle2D(options); break; case 'show': return showCircle2D(options); break; case 'hide': return hideCircle2D(options); break; case 'remove': return removeCircle2D(options); break; case 'update': return updateCircle2D(options); break; } } function addCircle2D(options) { var guid = options.guid || map23DControl.buildGuid('circle2D'); var defaultData = _.cloneDeep(map23DDefaultData.circle) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.circles[guid] = defaultData; PubSub.publishSync('map2D.circle.add', guid); return guid; } function showCircle2D(options) { if (map2DViewer.circles[options.guid]) { PubSub.publishSync('map2D.circle.show', options.guid); return options.guid; } else { return false; } } function hideCircle2D(options) { if (map2DViewer.circles[options.guid]) { PubSub.publishSync('map2D.circle.hide', options.guid); return options.guid; } else { return false; } } function removeCircle2D(options) { if (map23DData.circles[options.guid]) { PubSub.publishSync('map2D.circle.remove', options.guid); if (map23DData.circles[options.guid].add3D == false) { delete map23DData.circles[options.guid]; } return options.guid; } else { return false; } } function updateCircle2D(options) { if (map23DData.circles[options.guid]) { _.merge(map23DData.circles[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.circles[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map2D.circle.update', options.guid); return options.guid; } else { return false; } } //2D 圆标记 map2DViewer.circleMarker = function (options) { switch (options.action) { case 'add': return addCircleMarker2D(options); break; case 'show': return showCircleMarker2D(options); break; case 'hide': return hideCircleMarker2D(options); break; case 'remove': return removeCircleMarker2D(options); break; case 'update': return updateCircleMarker2D(options); break; } } function addCircleMarker2D(options) { var guid = options.guid || map23DControl.buildGuid('circleMarker2D'); var defaultData = _.cloneDeep(map23DDefaultData.circleMarker) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.circleMarkers[guid] = defaultData; PubSub.publishSync('map2D.circleMarker.add', guid); return guid; } function showCircleMarker2D(options) { if (map2DViewer.circleMarkers[options.guid]) { PubSub.publishSync('map2D.circleMarker.show', options.guid); return options.guid; } else { return false; } } function hideCircleMarker2D(options) { if (map2DViewer.circleMarkers[options.guid]) { PubSub.publishSync('map2D.circleMarker.hide', options.guid); return options.guid; } else { return false; } } function removeCircleMarker2D(options) { if (map23DData.circleMarkers[options.guid]) { PubSub.publishSync('map2D.circleMarker.remove', options.guid); if (map23DData.circleMarkers[options.guid].add3D == false) { delete map23DData.circleMarkers[options.guid]; } return options.guid; } else { return false; } } function updateCircleMarker2D(options) { if (map23DData.circleMarkers[options.guid]) { _.merge(map23DData.circleMarkers[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.circles[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map2D.circleMarker.update', options.guid); return options.guid; } else { return false; } } map2DViewer.imageOverlay = function (options) { switch (options.action) { case 'add': return addImageOverlay2D(options); break; case 'remove': return removeImageOverlay2D(options); break; case 'update': return updateImageOverlay2D(options); break; case 'hide': return hideImageOverlay2D(options); break; case 'show': return showImageOverlay2D(options); break; } } function addImageOverlay2D(options) { var guid = options.guid || map23DControl.buildGuid('imageOverlay23D'); var defaultData = _.cloneDeep(map23DDefaultData.imageOverlay) defaultData.guid = guid; _.merge(defaultData, options); map23DData.imageOverlays[guid] = defaultData; PubSub.publishSync('map2D.imageOverlay.add', guid); return guid; } /** * 移除图层组,移除前先清除图层组中的元素 * @param {[type]} options [description] * @return {[type]} [description] */ function removeImageOverlay2D(options) { if (map23DData.imageOverlays[options.guid]) { PubSub.publishSync('map2D.imageOverlay.remove', options.guid); delete map23DData.imageOverlays[options.guid]; return options.guid; } else { return false; } } function updateImageOverlay2D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map2D.imageOverlay.update', options.guid); return options.guid; } else { return false; } } function showImageOverlay2D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map2D.imageOverlay.show', options.guid); return options.guid; } else { return false; } } function hideImageOverlay2D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map2D.imageOverlay.hide', options.guid); return options.guid; } else { return false; } } /** * 设置系统自带图层 * @param {[type]} options [description] */ map2DViewer.setDefaultTileLayer = function (options) { PubSub.publish('map2D.defaultTileLayer.change', { mapName: options }) } /** * 2D图层控制 */ map2DViewer.tileLayer = function (options) { switch (options.action) { case 'add': return addTileLayer2D(options); break; case 'remove': return removeTileLayer2D(options); break; case 'update': return updateTileLayer2D(options); break; case 'show': return showTileLayer2D(options); break; case 'hide': return hideTileLayer2D(options); break; } } function addTileLayer2D(options) { var guid = options.guid || map23DControl.buildGuid('tileLayer2D'); var defaultData = _.cloneDeep(map23DDefaultData.layer) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.layers[guid] = defaultData; PubSub.publishSync('map2D.tileLayer.add', guid); return guid; } function showTileLayer2D(options) { if (map2DViewer.layers[options.guid]) { PubSub.publishSync('map2D.tileLayer.show', options.guid); return options.guid; } else { return false; } } function hideTileLayer2D(options) { if (map2DViewer.layers[options.guid]) { PubSub.publishSync('map2D.tileLayer.hide', options.guid); return options.guid; } else { return false; } } function updateTileLayer2D(options) { if (map23DData.layers[options.guid]) { _.merge(map23DData.layers[options.guid], options); PubSub.publishSync('map2D.tileLayer.update', options.guid); return options.guid; } else { return false; } } function removeTileLayer2D(options) { if (map23DData.layers[options.guid]) { PubSub.publishSync('map2D.tileLayer.remove', options.guid); if (map23DData.layers[options.guid].add3D == false) { delete map23DData.layers[options.guid]; } return options.guid; } else { return false; } } /** * 2DCartodb控制 */ map2DViewer.cartodbLayer = function (options) { switch (options.action) { case 'add': return addCartodbLayer2D(options); break; case 'remove': return removeCartodbLayer2D(options); break; } } function addCartodbLayer2D(options) { var guid = options.guid || map23DControl.buildGuid('cartodbLayer2D'); var defaultData = _.cloneDeep(map23DDefaultData.layer) defaultData.guid = guid; defaultData.from = '2D'; _.merge(defaultData, options); map23DData.layers[guid] = defaultData; PubSub.publishSync('map2D.cartodbLayer.add', guid); return guid; } function removeCartodbLayer2D(options) { if (map23DData.layers[options.guid]) { PubSub.publishSync('map2D.cartodbLayer.remove', options.guid); delete map23DData.layers[options.guid]; return options.guid; } else { return false; } } }(window, document)); ; (function (window, document, undefined) { window.map3DViewer = { inited: false, markers: {}, DEMLayers: {}, layers: {}, polylines: {}, polygons: {}, circles: {}, groups: {}, models: {}, hide3D: false, zoomAry: [90000, 50123, 31000, 16180, 8970, 5036, 2395, 1092, 580, 287, 146, 62.3, 33, 17.9, 9, 3.9, 2.1, 1.2, 0.53, 0.27, 0.01], syncTimeer: null, imageOverlays: {}, modelControlObj: {} }; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = map3DViewer; } else if (typeof define === 'function' && define.amd) { define(map3DViewer); } PubSub.subscribe('map23D.show23D', function (msg, options) { if (options.from == '23D' && map23DData.display.map3D) { if (map3DViewer.inited) {} else { map3DViewer.init(); } map3DViewer.hide3D = false; } }); PubSub.subscribe('map23D.show3D', function (msg, options) { if (options.from == '23D' && map23DData.display.map3D) { if (map3DViewer.inited) { var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); map3DViewer.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 } }) map23DData.mouseIn = '3D'; } else { map3DViewer.init(); //如果从隐藏到显示,添加所有因show2D隐藏的地图元素,添加同步 } map3DViewer.hide3D = false; } }); PubSub.subscribe('map23D.show2D', function (msg, options) { if (options.from == '23D') { if (map3DViewer.inited) { //移除所有显示的地图元素,并断开同步 map3DViewer.hide3D = true; } } }); PubSub.subscribe('map23D.flyTo', function (msg, options) { //_.merge(map23DData.view, options); var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); //longitude, latitude, altitude, dHeading, dTilt, dDistance, altMode map3DViewer.map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 }, duration: 5, complete: function () { if (options.callback) { options.callback(); } }, pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。 maximumHeight: 150000, // 相机最大飞行高度 //flyOverLongitude: 100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度 }) map23DData.mouseIn = '3D'; // PubSub.publish('map3D.flyTo', { // from: '3D' // }) }); map3DViewer.init = function () { var _this = this; if (this.inited) { return; } else { this.inited = true; } this.map = new Cesium.Viewer('map3DWrap', { animation: false, //是否创建动画小器件,左下角仪表 baseLayerPicker: false, //是否显示图层选择器 imageryProvider: new Cesium.WebMapServiceImageryProvider({ url: map23DConfig.tileServerUrl + '/gr?l={z}&x={x}&y={y}', format: "png" }), fullscreenButton: false, //是否显示全屏按钮 geocoder: false, //是否显示geocoder小器件,右上角查询按钮 homeButton: false, //是否显示Home按钮 infoBox: false, //是否显示信息框 sceneModePicker: false, //是否显示3D/2D选择器 selectionIndicator: false, //是否显示选取指示器组件 timeline: false, //是否显示时间轴 navigationHelpButton: false, //是否显示右上角的帮助按钮 navigationInstructionsInitiallyVisible: false, scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源 mapProjection: new Cesium.WebMercatorProjection(), infoBox: false, //是否显示点击要素之后显示的信息 shouldAnimate: true, //是否自动播放 }); this.map.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 0); this.map.scene.imageryLayers.removeAll(); this.map._cesiumWidget._creditContainer.style.display = "none"; //初始位置 var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); this.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(map23DData.view.center.lng, map23DData.view.center.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 } }) //监听事件 var handler = new Cesium.ScreenSpaceEventHandler(this.map.scene.canvas); this.map.scene.camera.moveEnd.addEventListener(function () { var center = map3DViewer.getCurCameraInfos(); if (map23DData.mouseIn != '3D') { return; } if (map3DViewer.syncTimeer) { return; } map3DViewer.syncTimeer = setTimeout(function () { var map23DDataHeading = map3DViewer.getHeadingForTangle(map3DViewer.map.camera.heading); var map23DDataPitch = map3DViewer.getPitchForTangle(map3DViewer.map.camera.pitch); var mapState = { view: { center: { lat: center.lat, lng: center.lng }, zoom: map3DViewer.getZoomFrom3DZoom(center.alt), heading: map23DDataHeading, pitch: map23DDataPitch, distance: center.alt } } //console.log(cameraState.Tilt); _.merge(map23DData, mapState); PubSub.publish('map3D.setView', { from: '3D' }) //locaSpaceMap.Refresh(); clearTimeout(map3DViewer.syncTimeer); map3DViewer.syncTimeer = null; }, 30) }) handler.setInputAction(function (e) { var feature = map3DViewer.map.scene.pick(e.position); PubSub.publish('map3D.featureClick', { from: '3D', evt: e, feature: feature }) }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //鼠标滑过元素 handler.setInputAction(function (e) { var feature = map3DViewer.map.scene.pick(e.position); PubSub.publish('map3D.featureMouseHover', { from: '3D', evt: e, feature: feature }) }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); //鼠标移动 handler.setInputAction(function (e) { PubSub.publish('map3D.mouseMove', { from: '3D', x: e.endPosition.x, y: e.endPosition.y }) }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); //鼠标左键 handler.setInputAction(function (e) { PubSub.publish('map3D.marker.showPopup', { type: 'LEFT_CLICK', infos: e, }) PubSub.publish('map3D.click', { from: '3D', x: e.position.x, y: e.position.y }) }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //鼠标右键 handler.setInputAction(function (e) { PubSub.publish('map3D.right_click', { from: '3D', x: e.position.x, y: e.position.y }) }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); //鼠标双击 handler.setInputAction(function (e) { PubSub.publish('map3D.dblClick', { from: '3D', x: e.position.x, y: e.position.y }) }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); PubSub.subscribe('map2D.setView', function (msg, options) { var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); if (map23DData.view.zoom < 6) { map23DData.view.pitch = 90; } map3DViewer.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 } }) var center = map3DViewer.get3DViewCenter(); map23DData.view.distance = center.alt; }); PubSub.subscribe('map2D.flyTo', function (msg, options) { if (options.from == '2D' && map23DData.mouseIn == '2D' && !map2DViewer.hide3D) { //_.merge(map23DData.view, options); var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); //longitude, latitude, altitude, dHeading, dTilt, dDistance, altMode map3DViewer.map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 }, duration: 5, complete: function () { if (options.callback) { options.callback(); } }, pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。 maximumHeight: 150000, // 相机最大飞行高度 //flyOverLongitude: 100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度 }) } // PubSub.publish('map3D.flyTo', { // from: '3D' // }) }); PubSub.subscribe('map23D.setView', function (msg, options) { if (options.from == '23D' && !map3DViewer.hide3D) { var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); if (map23DData.view.zoom < 6) { map23DData.view.pitch = 90; } map3DViewer.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 } }) } }); } //显示支持文本的冒泡窗 map3DViewer.showTextTips = function (options) { } //显示支持html的冒泡窗 map3DViewer.showPopup = function (options) { } //跳转到指定位置 map3DViewer.setView = function (options) { _.merge(map23DData.view, options); var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); if (map23DData.view.zoom < 6) { map23DData.view.pitch = 90; } map3DViewer.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 } }) map23DData.mouseIn = '3D'; PubSub.publish('map3D.setView', { from: '3D' }) } //飞行到指定位置 map3DViewer.flyTo = function (options, callback) { _.merge(map23DData.view, options); var newlatlng = map23DData.view.center; var map3DHeading = map3DViewer.getHeadingForPi(map23DData.view.heading); //longitude, latitude, altitude, dHeading, dTilt, dDistance, altMode map3DViewer.map.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(newlatlng.lng, newlatlng.lat, map3DViewer.getZoomFrom2DZoom(map23DData.view.zoom)), // 设置位置 orientation: { heading: map3DHeading, // 方向 pitch: map3DViewer.getPitchForPi(map23DData.view.pitch), // 倾斜角度 roll: 0 }, duration: 5, complete: function () { if (callback) { callback(); } }, pitchAdjustHeight: -90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。 maximumHeight: 150000, // 相机最大飞行高度 //flyOverLongitude: 100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度 }) map23DData.mouseIn = '3D'; PubSub.publish('map3D.setView', { from: '3D' }) } map3DViewer.getHeadingForPi = function (num) { num = 360 - Math.abs(num); num = num / 180 * Math.PI; return num; } map3DViewer.getHeadingForTangle = function (num) { num = parseInt(num * 180 / Math.PI); return num; } map3DViewer.getPitchForPi = function (num) { num = 0 - Math.abs(num); num = num / 180 * Math.PI; return num; } map3DViewer.getPitchForTangle = function (num) { num = num * 180 / Math.PI; return num; } map3DViewer.getZoomFrom2DZoom = function (zoom) { var RoraTilt = map23DData.view.pitch; return Math.abs(this.zoomAry[map23DData.view.zoom] * 1000 * Math.sin(RoraTilt)); } map3DViewer.getZoomFrom3DZoom = function (distance) { distance = distance / 1000; for (var i = 0, len = this.zoomAry.length; i < len; i++) { var max = (this.zoomAry[i] + this.zoomAry[i - 1]) / 2; var min = (this.zoomAry[i] + this.zoomAry[i + 1]) / 2; if (distance < max && distance > min) { return i; } } } /** * 获取3D视角中心点 */ map3DViewer.get3DViewCenter = function () { var S2dx = $('#map3DWrap').width() / 2; //3D视图容器宽度的二分之一 var S2dy = $('#map3DWrap').height() / 2; //3D视图容器高度的二分之一 var x = parseInt(S2dx); var y = parseInt(S2dy); var curPosition = map3DViewer.screenToLatLng(x, y); var camera = map3DViewer.map.camera.position; var height = map3DViewer.Cartesian3ToLatLng(camera.x, camera.y, camera.z); height = height.alt if (curPosition) { return { lng: curPosition.lng, lat: curPosition.lat, alt: height }; } else { return false; } } map3DViewer.screenToLatLng = function (x, y) { var pick1 = new Cesium.Cartesian2(x, y); var cartesian = map3DViewer.map.scene.globe.pick(map3DViewer.map.camera.getPickRay(pick1), map3DViewer.map.scene); if (cartesian) { var cartographic = map3DViewer.map.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } } else { var position = false } return position; } //世界坐标转经纬度坐标 map3DViewer.Cartesian3ToLatLng = function (x, y, z) { var ellipsoid = map3DViewer.map.scene.globe.ellipsoid; var Cartesian3 = new Cesium.Cartesian3(x, y, z); var cartographic = ellipsoid.cartesianToCartographic(Cartesian3); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } return position; } //获取视角高度及经纬度 map3DViewer.getCurCameraInfos = function () { var curPosition = map3DViewer.map.camera.position; curPosition = map3DViewer.Cartesian3ToLatLng(curPosition.x, curPosition.y, curPosition.z); return curPosition; }; map3DViewer.Cartesian3ToScreen = function (cartesian) { var pick = Cesium.SceneTransforms.wgs84ToWindowCoordinates(map3DViewer.map.scene, cartesian); return pick; } //设置当前时区 map3DViewer.setClock = function (viewer) { var d = new Date(); var hour = 0 - d.getTimezoneOffset(); viewer.animation.viewModel.timeFormatter = function (date, viewModel) { var dateZone8 = Cesium.JulianDate.addMinutes(date, hour, new Cesium.JulianDate()); var gregorianDate = Cesium.JulianDate.toGregorianDate(dateZone8); if (Math.abs(viewModel._clockViewModel.multiplier) < 1) { return Cesium.sprintf("%02d:%02d:%02d.%03d;", gregorianDate.hour, gregorianDate.minute, gregorianDate.second); } return Cesium.sprintf("%02d:%02d:%02d GMT+8", gregorianDate.hour, gregorianDate.minute, gregorianDate.second); }; } // //3D绑定Label // map3DViewer.label = function (options) { // switch (options.action) { // case 'add': // return PubSub.publishSync('map3D.label.add', options); // break; // case 'remove': // return PubSub.publishSync('map3D.label.remove', options); // break; // case 'update': // return PubSub.publishSync('map3D.label.update', options); // break; // } // } //3D 组 map3DViewer.group = function (options) { switch (options.action) { case 'add': return addGroup3D(options); break; case 'remove': return removeGroup3D(options); break; case 'hide': return hideGroup3D(options); break; case 'show': return showGroup3D(options); break; case 'cleanAll': return operationGroup3D(options, 'remove'); break; } } function addGroup3D(options) { var guid = options.guid || map23DControl.buildGuid('group3D'); var defaultData = _.cloneDeep(map23DDefaultData.group) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.groups[guid] = defaultData; PubSub.publishSync('map3D.group.add', guid); return guid; } function removeGroup3D(options) { if (map23DData.groups[options.guid]) { operationGroup3D(options, "remove"); PubSub.publishSync('map3D.group.remove', options.guid); if (map23DData.groups[options.guid].add2D == false) { delete map23DData.groups[options.guid]; } return options.guid; } else { return false; } } function showGroup3D(options) { if (map23DData.groups[options.guid]) { operationGroup3D(options, "show"); PubSub.publishSync('map3D.group.show', options.guid); return options.guid; } else { return false; } } function hideGroup3D(options) { if (map23DData.groups[options.guid]) { operationGroup3D(options, "hide"); PubSub.publishSync('map3D.group.hide', options.guid); return options.guid; } else { return false; } } function operationGroup3D(options, action) { if (map23DData.groups[options.guid]) { //点 _(map23DData.markers).forEach(function (item, key) { if (item.groupId == options.guid) { map3DViewer.marker({ action: action, guid: key }) } }); //线 _(map23DData.polylines).forEach(function (item, key) { if (item.groupId == options.guid) { map3DViewer.polyline({ action: action, guid: key }) } }); //移除面 _(map23DData.polygons).forEach(function (item, key) { if (item.groupId == options.guid) { map3DViewer.polygon({ action: action, guid: key }) } }); //圆 _(map23DData.circles).forEach(function (item, key) { if (item.groupId == options.guid) { map3DViewer.circle({ action: action, guid: key }) } }); //模型 _(map23DData.models).forEach(function (item, key) { if (item.groupId == options.guid) { map3DViewer.model({ action: action, guid: key }) } }); return options.guid; } else { return false } } //3D 点 map3DViewer.marker = function (options) { switch (options.action) { case 'add': return addMarker3D(options); break; case 'remove': return removeMarker3D(options); break; case 'update': return updateMarker3D(options); break; case 'show': return showMarker3D(options); break; case 'hide': return hideMarker3D(options); break; } } function addMarker3D(options) { var guid = options.guid || map23DControl.buildGuid('marker3D'); var defaultData = _.cloneDeep(map23DDefaultData.marker) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.markers[guid] = defaultData; PubSub.publishSync('map3D.marker.add', guid); return guid; } function removeMarker3D(options) { if (map23DData.markers[options.guid]) { PubSub.publishSync('map3D.marker.remove', options.guid); if (map23DData.markers[options.guid].add2D == false) { delete map23DData.markers[options.guid]; } return options.guid; } else { return false; } } function updateMarker3D(options) { if (map23DData.markers[options.guid]) { _.merge(map23DData.markers[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.markers[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map3D.marker.update', options.guid); return options.guid; } else { return false; } } function showMarker3D(options) { if (map23DData.markers[options.guid]) { PubSub.publishSync('map3D.marker.show', options.guid); return options.guid; } else { return false; } } function hideMarker3D(options) { if (map23DData.markers[options.guid]) { PubSub.publishSync('map3D.marker.hide', options.guid); return options.guid; } else { return false; } } //3D 线 map3DViewer.polyline = function (options) { switch (options.action) { case 'add': return addPolyline3D(options); break; case 'remove': return removePolyline3D(options); break; case 'update': return updatePolyline3D(options); break; case 'show': return showPolyline3D(options); break; case 'hide': return hidePolyline3D(options); break; } } function addPolyline3D(options) { var guid = options.guid || map23DControl.buildGuid('polyline3D'); var defaultData = _.cloneDeep(map23DDefaultData.polyline) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.polylines[guid] = defaultData; PubSub.publishSync('map3D.polyline.add', guid); return guid; } function removePolyline3D(options) { if (map23DData.polylines[options.guid]) { PubSub.publishSync('map3D.polyline.remove', options.guid); if (map23DData.polylines[options.guid].add2D == false) { delete map23DData.polylines[options.guid]; } return options.guid; } else { return false; } } function updatePolyline3D(options) { if (map23DData.polylines[options.guid]) { _.merge(map23DData.polylines[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polylines[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map3D.polyline.update', options.guid); return options.guid; } else { return false; } } function showPolyline3D(options) { if (map23DData.polylines[options.guid]) { PubSub.publishSync('map3D.polyline.show', options.guid); return options.guid; } else { return false; } } function hidePolyline3D(options) { if (map23DData.polylines[options.guid]) { PubSub.publishSync('map3D.polyline.hide', options.guid); return options.guid; } else { return false; } } //3D 面 map3DViewer.polygon = function (options) { switch (options.action) { case 'add': return addPolygon3D(options); break; case 'remove': return removePolygon3D(options); break; case 'update': return updatePolygon3D(options); break; case 'show': return showPolygon3D(options); break; case 'hide': return hidePolygon3D(options); break; } } function addPolygon3D(options) { var guid = options.guid || map23DControl.buildGuid('polygon3D'); var defaultData = _.cloneDeep(map23DDefaultData.polyline) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.polygons[guid] = defaultData; PubSub.publishSync('map3D.polygon.add', guid); return guid; } function removePolygon3D(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map3D.polygon.remove', options.guid); if (map23DData.polygons[options.guid].add2D == false) { delete map23DData.polygons[options.guid]; } return options.guid; } else { return false; } } function updatePolygon3D(options) { if (map23DData.polygons[options.guid]) { _.merge(map23DData.polygons[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polygons[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map3D.polygon.update', options.guid); return options.guid; } else { return false; } } function showPolygon3D(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map3D.polygon.show', options.guid); return options.guid; } else { return false; } } function hidePolygon3D(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map3D.polygon.hide', options.guid); return options.guid; } else { return false; } } //3D 圆 map3DViewer.circle = function (options) { switch (options.action) { case 'add': return addCircle3D(options); break; case 'remove': return removeCircle3D(options); break; case 'update': return updateCircle3D(options); break; case 'show': return showCircle3D(options); break; case 'hide': return hideCircle3D(options); break; } } function addCircle3D(options) { var guid = options.guid || map23DControl.buildGuid('circle3D'); var defaultData = _.cloneDeep(map23DDefaultData.circle) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.circles[guid] = defaultData; PubSub.publishSync('map3D.circle.add', guid); return guid; } function removeCircle3D(options) { if (map23DData.circles[options.guid]) { PubSub.publishSync('map3D.circle.remove', options.guid); if (map23DData.circles[options.guid].add2D == false) { delete map23DData.circles[options.guid]; } return options.guid; } else { return false; } } function updateCircle3D(options) { if (map23DData.circles[options.guid]) { _.merge(map23DData.circles[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.circles[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map3D.circle.update', options.guid); return options.guid; } else { return false; } } function showCircle3D(options) { if (map23DData.circles[options.guid]) { PubSub.publishSync('map3D.circle.show', options.guid); return options.guid; } else { return false; } } function hideCircle3D(options) { if (map23DData.circles[options.guid]) { PubSub.publishSync('map3D.circle.hide', options.guid); return options.guid; } else { return false; } } //三维模型 map3DViewer.model = function (options) { switch (options.action) { case 'add': return addModel3D(options); break; case 'update': return updateModel3D(options); break; case 'remove': return removeModel3D(options); break; case 'show': return showModel3D(options); break; case 'hide': return hideModel3D(options); break; } } function addModel3D(options) { var guid = options.guid || map23DControl.buildGuid('model3D'); var defaultData = _.cloneDeep(map23DDefaultData.model) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.models[guid] = defaultData; PubSub.publishSync('map3D.model.add', guid); return guid; } function removeModel3D(options) { if (map23DData.models[options.guid]) { _.merge(map23DData.models[options.guid], options); PubSub.publish('map3D.model.remove', options.guid); return options.guid; } else { return false; } } function updateModel3D(options) { if (map23DData.models[options.guid]) { _.merge(map23DData.models[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.models[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } if (options.geojson.properties) { if (options.geojson.properties.timeLine) map23DData.models[options.guid].geojson.properties.timeLine = options.geojson.properties.timeLine if (options.geojson.properties.altitude) map23DData.models[options.guid].geojson.properties.altitude = options.geojson.properties.altitude } PubSub.publishSync('map3D.model.update', options.guid); return options.guid; } else { return false; } } function showModel3D(options) { if (map23DData.models[options.guid]) { PubSub.publishSync('map3D.model.show', options.guid); return options.guid; } else { return false; } } function hideModel3D(options) { if (map23DData.models[options.guid]) { PubSub.publishSync('map3D.model.hide', options.guid); return options.guid; } else { return false; } } //图片 map3DViewer.imageOverlay = function (options) { switch (options.action) { case 'add': return addImageOverlay3D(options); break; case 'remove': return removeImageOverlay3D(options); break; case 'update': return updateImageOverlay3D(options); break; case 'hide': return hideImageOverlay3D(options); break; case 'show': return showImageOverlay3D(options); break; } } function addImageOverlay3D(options) { var guid = options.guid || map23DControl.buildGuid('imageOverlay23D'); var defaultData = _.cloneDeep(map23DDefaultData.imageOverlay) defaultData.guid = guid; _.merge(defaultData, options); map23DData.imageOverlays[guid] = defaultData; PubSub.publishSync('map3D.imageOverlay.add', guid); return guid; } /** * 移除图层组,移除前先清除图层组中的元素 * @param {[type]} options [description] * @return {[type]} [description] */ function removeImageOverlay3D(options) { if (map23DData.imageOverlays[options.guid]) { PubSub.publishSync('map3D.imageOverlay.remove', options.guid); delete map23DData.imageOverlays[options.guid]; return options.guid; } else { return false; } } function updateImageOverlay3D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map3D.imageOverlay.update', options.guid); return options.guid; } else { return false; } } function showImageOverlay3D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map3D.imageOverlay.show', options.guid); return options.guid; } else { return false; } } function hideImageOverlay3D(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map3D.imageOverlay.hide', options.guid); return options.guid; } else { return false; } } /** * 设置系统自带图层 * @param {[type]} options [description] */ map3DViewer.setDefaultTileLayer = function (options) { PubSub.publish('map3D.defaultTileLayer.change', { mapName: options }) } //3D瓦片图层 map3DViewer.tileLayer = function (options) { switch (options.action) { case 'add': return addTileLayer3D(options); break; case 'remove': return removeTileLayer3D(options); break; case 'update': return updateTileLayer3D(options); break; case 'hide': return hideTileLayer3D(options); break; case 'show': return showTileLayer3D(options); break; } } function addTileLayer3D(options) { var guid = options.guid || map23DControl.buildGuid('tileLayer3D'); var defaultData = _.cloneDeep(map23DDefaultData.layer) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.layers[guid] = defaultData; PubSub.publishSync('map3D.tileLayer.add', guid); return guid; } function removeTileLayer3D(options) { if (map23DData.layers[options.guid]) { PubSub.publishSync('map3D.tileLayer.remove', options.guid); if (map23DData.layers[options.guid].add2D == false) { delete map23DData.layers[options.guid]; } return options.guid; } else { return false; } } function updateTileLayer3D(options) { if (map23DData.layers[options.guid]) { _.merge(map23DData.layers[options.guid], options); PubSub.publishSync('map3D.tileLayer.update', options.guid); return options.guid; } else { return false; } } function showTileLayer3D(options) { if (map3DViewer.layers[options.guid]) { PubSub.publishSync('map3D.tileLayer.show', options.guid); return options.guid; } else { return false; } } function hideTileLayer3D(options) { if (map3DViewer.layers[options.guid]) { PubSub.publishSync('map3D.tileLayer.hide', options.guid); return options.guid; } else { return false; } } //3D DEM map3DViewer.DEMTileLayer = function (options) { switch (options.action) { case 'add': return addDEMTileLayer3D(options); break; case 'remove': return removeDEMTileLayer3D(options); break; } } function addDEMTileLayer3D(options) { var guid = options.guid || map23DControl.buildGuid('DEMTileLayer3D'); var defaultData = _.cloneDeep(map23DDefaultData.DEMLayer) defaultData.guid = guid; defaultData.from = '3D'; _.merge(defaultData, options); map23DData.DEMLayers[guid] = defaultData; PubSub.publishSync('map3D.DEMTileLayer.add', guid); return guid; } function removeDEMTileLayer3D(options) { if (map23DData.DEMLayers[options.guid]) { PubSub.publishSync('map3D.DEMTileLayer.remove', options.guid); if (map23DData.DEMLayers[options.guid].add2D == false) { delete map23DData.DEMLayers[options.guid]; } return options.guid; } else { return false; } } //3D 测距 //callback 完成绘制后是否继续保持激活该工具 默认保持 map3DViewer.measureDistance = function (options) { switch (options.action) { case 'add': return addMeasureDistance3D(options); break; case 'remove': return removeMeasureDistance3D(options); break; case 'clear': return clearMeasureDistance3D(options); break; } } function addMeasureDistance3D(options) { PubSub.publishSync('map3D.measureDistance.add', { action: options.action, viewer: map3DViewer.map }); } function removeMeasureDistance3D(options) { PubSub.publishSync('map3D.measureDistance.remove', false); } function clearMeasureDistance3D(options) { PubSub.publishSync('map3D.measureDistance.clear'); } //3D 测面 map3DViewer.measureArea = function (options) { switch (options.action) { case 'add': return addMeasureArea3D(options); break; case 'remove': return removeMeasureArea3D(options); break; case 'clear': return clearMeasureArea3D(options); break; } } function addMeasureArea3D(options) { PubSub.publishSync('map3D.measureArea.add', { action: options.action, viewer: map3DViewer.map }); } function removeMeasureArea3D(options) { PubSub.publishSync('map3D.measureArea.remove', false); } function clearMeasureArea3D(options) { PubSub.publishSync('map3D.measureArea.clear'); } // //3D 测高 // map3DViewer.measureHeight = function (options) { // switch (options.action) { // case 'add': // return addMeasureHeight3D(options); // break; // case 'remove': // return removeMeasureHeight3D(options); // break; // case 'clear': // return clearMeasureHeight3D(options); // break; // } // } function addMeasureHeight3D(options) { PubSub.publishSync('map3D.measureHeight.add', { action: options.action, viewer: map3DViewer.map }); } function removeMeasureHeight3D(options) { PubSub.publishSync('map3D.measureHeight.remove', false); } function clearMeasureHeight3D(options) { PubSub.publishSync('map3D.measureHeight.clear'); } // 3D 通视分析 map3DViewer.visualAnalysis = function (options) { switch (options.action) { case 'add': return addVisualAnalysis3D(options); break; case 'start': return startVisualAnalysis3D(options); break; case 'stop': return stopVisualAnalysis3D(options); break; case 'remove': return removeVisualAnalysis3D(options); break; case 'clear': return clearVisualAnalysis3D(options); break; } } function addVisualAnalysis3D(options) { PubSub.publishSync('map3D.visualAnalysis.add', { viewer: map3DViewer.map, callback: options.callback }); } function startVisualAnalysis3D(options) { PubSub.publishSync('map3D.visualAnalysis.start', { viewHeight: options.viewHeight }); } function stopVisualAnalysis3D(options) { PubSub.publishSync('map3D.visualAnalysis.stop', {}); } function removeVisualAnalysis3D(options) { PubSub.publishSync('map3D.visualAnalysis.remove', {}); } function clearVisualAnalysis3D(options) { PubSub.publishSync('map3D.visualAnalysis.clear', {}); } // 3D 环视分析 map3DViewer.lookAroundAnalysis = function (options) { switch (options.action) { case 'add': return addLookAroundAnalysis3D(options); break; case 'draw': return drawLookAroundAnalysis3D(options); break; case 'start': return startLookAroundAnalysis3D(options); break; case 'stop': return stopLookAroundAnalysis3D(options); break; case 'remove': return removeLookAroundAnalysis3D(options); break; case 'clear': return clearLookAroundAnalysis3D(options); break; } } function addLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.add', { viewer: map3DViewer.map, callback: options.callback }); } function drawLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.draw', { lng: options.lng, lat: options.lat, distance: options.distance, viewHeight: options.viewHeight, angleInterval: options.angleInterval }); } function startLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.start', { viewHeight: options.viewHeight, angleInterval: options.angleInterval }); } function stopLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.stop', {}); } function removeLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.remove', {}); } function clearLookAroundAnalysis3D(options) { PubSub.publishSync('map3D.lookAroundAnalysis.clear', {}); } // 模拟飞行 map3DViewer.flightSimulation = function (options) { switch (options.action) { case 'add': return addFlightSimulation3D(options); break; case 'changeView': return changeViewFlightSimulation3D(options); break; } } function addFlightSimulation3D(options) { delete options.action var obj = Object.assign({}, { viewer: map3DViewer.map }, options); PubSub.publishSync('map3D.flightSimulation.add', obj); } function changeViewFlightSimulation3D(options) { delete options.action PubSub.publishSync('map3D.flightSimulation.changeView', options); } // 3D 环视分析 map3DViewer.measureElevation = function (options) { switch (options.action) { case 'add': return addMeasureElevation3D(options); break; case 'remove': return removeMeasureElevation3D(options); break; case 'clear': return clearMeasureElevation3D(options); break; } } function addMeasureElevation3D(options) { var obj = Object.assign({}, { viewer: map3DViewer.map }, options); PubSub.publishSync('map3D.measureElevation.add', obj); } function removeMeasureElevation3D(options) { PubSub.publishSync('map3D.measureElevation.remove', {}); } function clearMeasureElevation3D(options) { PubSub.publishSync('map3D.measureElevation.clear', {}); } }(window, document)); ; (function (window, document, undefined) { var group = map23DControl.group; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = group; } else if (typeof define === 'function' && define.amd) { define(group); } map23DControl.group = function (options) { switch (options.action) { case 'add': return addgroup(options); break; case 'hide': return hidegroup(options); break; case 'show': return showgroup(options); break; case 'remove': return removegroup(options); break; case 'cleanAll': return operationGroup(options, 'remove'); break; } } function addgroup(options) { var guid = options.guid || map23DControl.buildGuid('group23D'); var defaultData = _.cloneDeep(map23DDefaultData.group) defaultData.guid = guid; defaultData.from = '23D'; _.merge(defaultData, options); map23DData.groups[guid] = defaultData; PubSub.publishSync('map23D.group.add', guid); return guid; } /** * 移除图层组,移除前先清除图层组中的元素 * @param {[type]} options [description] * @return {[type]} [description] */ function removegroup(options) { if (map23DData.groups[options.guid]) { operationGroup(options, "remove"); PubSub.publishSync('map23D.group.remove', options.guid); delete map23DData.groups[options.guid]; return options.guid; } else { return false; } } function showgroup(options) { if (map23DData.groups[options.guid]) { operationGroup(options, "show"); PubSub.publishSync('map23D.group.show', options.guid); return options.guid; } else { return false; } } function hidegroup(options) { if (map23DData.groups[options.guid]) { operationGroup(options, "hide"); PubSub.publishSync('map23D.group.hide', options.guid); return options.guid; } else { return false; } } /** * 清除图层组元素 * @param {[type]} options [description] * @return {[type]} [description] */ function operationGroup(options, action) { if (map23DData.groups[options.guid]) { //移除点 _(map23DData.markers).forEach(function (item, key) { if (item.groupId == options.guid) { map23DControl.marker({ action: action, guid: key }) } }); //移除线 _(map23DData.polylines).forEach(function (item, key) { if (item.groupId == options.guid) { map23DControl.polyline({ action: action, guid: key }) } }); //移除面 _(map23DData.polygons).forEach(function (item, key) { if (item.groupId == options.guid) { map23DControl.polygon({ action: action, guid: key }) } }); //移除圆 _(map23DData.circles).forEach(function (item, key) { if (item.groupId == options.guid) { map23DControl.circle({ action: action, guid: key }) } }); return options.guid; } else { return false } } }(window, document)); ; (function (window, document, undefined) { var imageOverlay = map23DControl.imageOverlay; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = imageOverlay; } else if (typeof define === 'function' && define.amd) { define(imageOverlay); } map23DControl.imageOverlay = function (options) { switch (options.action) { case 'add': return addImageOverlay(options); break; case 'remove': return removeImageOverlay(options); break; case 'update': return updateImageOverlay(options); break; case 'hide': return hideImageOverlay(options); break; case 'show': return showImageOverlay(options); break; } } function addImageOverlay(options) { var guid = options.guid || map23DControl.buildGuid('imageOverlay23D'); var defaultData = _.cloneDeep(map23DDefaultData.imageOverlay) defaultData.guid = guid; _.merge(defaultData, options); map23DData.imageOverlays[guid] = defaultData; PubSub.publishSync('map23D.imageOverlay.add', guid); return guid; } /** * 移除图层组,移除前先清除图层组中的元素 * @param {[type]} options [description] * @return {[type]} [description] */ function removeImageOverlay(options) { if (map23DData.imageOverlays[options.guid]) { PubSub.publishSync('map23D.imageOverlay.remove', options.guid); delete map23DData.imageOverlays[options.guid]; return options.guid; } else { return false; } } function updateImageOverlay(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map23D.imageOverlay.update', options.guid); return options.guid; } else { return false; } } function showImageOverlay(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map23D.imageOverlay.show', options.guid); return options.guid; } else { return false; } } function hideImageOverlay(options) { if (map23DData.imageOverlays[options.guid]) { _.merge(map23DData.imageOverlays[options.guid], options); PubSub.publishSync('map23D.imageOverlay.hide', options.guid); return options.guid; } else { return false; } } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.imageOverlay.add', add2DimageOverlay); PubSub.subscribe('map23D.imageOverlay.remove', remove2DimageOverlay); PubSub.subscribe('map23D.imageOverlay.update', update2DimageOverlay); PubSub.subscribe('map23D.imageOverlay.show', show2DimageOverlay); PubSub.subscribe('map23D.imageOverlay.hide', hide2DimageOverlay); PubSub.subscribe('map2D.imageOverlay.add', add2DimageOverlay); PubSub.subscribe('map2D.imageOverlay.remove', remove2DimageOverlay); PubSub.subscribe('map2D.imageOverlay.update', update2DimageOverlay); PubSub.subscribe('map2D.imageOverlay.show', show2DimageOverlay); PubSub.subscribe('map2D.imageOverlay.hide', hide2DimageOverlay); /** * 根据GUID添加图层 * @param {[type]} msg [description] * @param {[type]} guid [description] */ function add2DimageOverlay(msg, guid) { if (!map2DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '3D') { return false; } var corner1 = L.latLng(imageOverlayData.layers.layerBounds[0][1], imageOverlayData.layers.layerBounds[0][0]); var corner2 = L.latLng(imageOverlayData.layers.layerBounds[1][1], imageOverlayData.layers.layerBounds[1][0]); layerBounds = L.latLngBounds(corner1, corner2); var imageOverlay = L.imageOverlay(imageOverlayData.layers.imageUrl2D, layerBounds, { opacity: imageOverlayData.layers.opacity }); imageOverlay.guid = guid; imageOverlay.addTo(map2DViewer.map); map2DViewer.imageOverlays[guid] = imageOverlay; imageOverlayData.add2D = true; imageOverlayData.visible2D = true; } /** * 移除指定GUID的图层 * @param {[type]} msg [description] * @param {[type]} guid [description] * @return {[type]} [description] */ function remove2DimageOverlay(msg, guid) { if (!map2DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '3D') { return false; } map2DViewer.map.removeLayer(map2DViewer.imageOverlays[guid]); delete map2DViewer.imageOverlays[guid]; imageOverlayData.add2D = false; } /** * 更新指定GUID的图层 * @param {[type]} msg [description] * @param {[type]} guid [description] * @return {[type]} [description] */ function update2DimageOverlay(msg, guid) { if (!map2DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '3D') { return false; } var imageOverlay = map2DViewer.imageOverlays[guid]; if (imageOverlay.options.opacity != imageOverlayData.layers.opacity) { imageOverlay.setOpacity(imageOverlayData.layers.opacity); } //if (imageOverlay.options._bounds != imageOverlayData.layers.layerBounds) { var corner1 = L.latLng(imageOverlayData.layers.layerBounds[0][1], imageOverlayData.layers.layerBounds[0][0]); var corner2 = L.latLng(imageOverlayData.layers.layerBounds[1][1], imageOverlayData.layers.layerBounds[1][0]); layerBounds = L.latLngBounds(corner1, corner2); imageOverlay.setBounds(layerBounds); //} if (imageOverlay._url != imageOverlayData.layers.imageUrl2D) { imageOverlay.setUrl(imageOverlayData.layers.imageUrl2D); } } function show2DimageOverlay(msg, guid) { if (!map2DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '3D') { return false; } if (imageOverlayData.visible2D) { return false; } map2DViewer.imageOverlays[guid].addTo(map2DViewer.map); imageOverlayData.visible2D = true; } function hide2DimageOverlay(msg, guid) { if (!map2DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '3D') { return false; } if (!imageOverlayData.visible2D) { return false; } map2DViewer.map.removeLayer(map2DViewer.imageOverlays[guid]); imageOverlayData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.imageOverlay.add', add3DimageOverlay); PubSub.subscribe('map23D.imageOverlay.remove', remove3DimageOverlay); PubSub.subscribe('map23D.imageOverlay.hide', hide3DimageOverlay); PubSub.subscribe('map23D.imageOverlay.show', show3DimageOverlay); PubSub.subscribe('map23D.imageOverlay.update', update3DimageOverlay); PubSub.subscribe('map3D.imageOverlay.add', add3DimageOverlay); PubSub.subscribe('map3D.imageOverlay.remove', remove3DimageOverlay); PubSub.subscribe('map3D.imageOverlay.hide', hide3DimageOverlay); PubSub.subscribe('map3D.imageOverlay.show', show3DimageOverlay); PubSub.subscribe('map3D.imageOverlay.update', update3DimageOverlay); function add3DimageOverlay(msg, guid) { if (!map3DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '2D') { return false; } var imageLayer = map3DViewer.map.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url: imageOverlayData.layers.imageUrl3D, rectangle: Cesium.Rectangle.fromDegrees(imageOverlayData.layers.layerBounds[0][0], imageOverlayData.layers.layerBounds[1][1], imageOverlayData.layers.layerBounds[1][0], imageOverlayData.layers.layerBounds[0][1]) })) imageLayer.alpha = imageOverlayData.layers.opacity; delete imageOverlayData.action; map3DViewer.imageOverlays[guid] = imageLayer; imageOverlayData.add3D = true; imageOverlayData.visible3D = true; }; function remove3DimageOverlay(msg, guid) { if (!map3DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '2D') { return false; } if (!map3DViewer.imageOverlays[guid]) { return false; } var imageLayer = map3DViewer.imageOverlays[guid]; map3DViewer.map.imageryLayers.remove(imageLayer); delete map3DViewer.imageOverlays[guid]; imageOverlayData.add3D = false; }; function update3DimageOverlay(msg, guid) { if (!map3DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '2D') { return false; } if (!map3DViewer.imageOverlays[guid]) { return false; } var imageLayer = map3DViewer.imageOverlays[guid]; if (map3DViewer.map.scene.imageryLayers.contains(imageLayer)) map3DViewer.map.scene.imageryLayers.remove(imageLayer, true) // (要移除的图层,是否摧毁图层) var imageLayer = map3DViewer.map.scene.imageryLayers.addImageryProvider(new Cesium.SingleTileImageryProvider({ url: imageOverlayData.layers.imageUrl3D, rectangle: Cesium.Rectangle.fromDegrees(imageOverlayData.layers.layerBounds[0][0], imageOverlayData.layers.layerBounds[1][1], imageOverlayData.layers.layerBounds[1][0], imageOverlayData.layers.layerBounds[0][1]) })) imageLayer.alpha = imageOverlayData.layers.opacity; map3DViewer.imageOverlays[guid] = imageLayer; delete map23DData.imageOverlays[guid].action; }; function show3DimageOverlay(msg, guid) { if (!map3DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '2D') { return false; } if (!map3DViewer.imageOverlays[guid]) { return false; } var imageLayer = map3DViewer.imageOverlays[guid]; imageLayer.show = true; imageOverlayData.visible3D = true; } function hide3DimageOverlay(msg, guid) { if (!map3DViewer.inited) { return false; } var imageOverlayData = map23DData.imageOverlays[guid]; if (imageOverlayData.from === '2D') { return false; } if (!map3DViewer.imageOverlays[guid]) { return false; } var imageLayer = map3DViewer.imageOverlays[guid]; imageLayer.show = false; imageOverlayData.visible3D = false; } }(window, document)); ; (function (window, document, undefined) { var circle = map23DControl.circle; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = circle; } else if (typeof define === 'function' && define.amd) { define(circle); } map23DControl.circle = function (options) { switch (options.action) { case 'add': return addCircle(options); break; case 'remove': return removeCircle(options); break; case 'update': return updateCircle(options); break; case 'show': return showCircle(options); break; case 'hide': return hideCircle(options); break; } } function addCircle(options) { var guid = options.guid || map23DControl.buildGuid('circle23D'); var defaultData = _.cloneDeep(map23DDefaultData.circle) defaultData.guid = guid; _.merge(defaultData, options); map23DData.circles[guid] = defaultData; PubSub.publishSync('map23D.circle.add', guid); return guid; } function removeCircle(options) { if (map23DData.circles[options.guid]) { PubSub.publishSync('map23D.circle.remove', options.guid); delete map23DData.circles[options.guid]; return options.guid; } else { return false; } } function updateCircle(options) { if (map23DData.circles[options.guid]) { _.merge(map23DData.circles[options.guid], options); PubSub.publishSync('map23D.circle.update', options.guid); return options.guid; } else { return false } } function showCircle(options) { if (map23DData.circles[options.guid]) { _.merge(map23DData.circles[options.guid], options); PubSub.publishSync('map23D.circle.show', options.guid); return options.guid; } else { return false } } function hideCircle(options) { if (map23DData.circles[options.guid]) { _.merge(map23DData.circles[options.guid], options); PubSub.publishSync('map23D.circle.hide', options.guid); return options.guid; } else { return false } } }(window, document)); ; (function (window, document, undefined) { var marker = map23DControl.marker; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = marker; } else if (typeof define === 'function' && define.amd) { define(marker); } map23DControl.marker = function (options) { switch (options.action) { case 'add': return addMarker(options); break; case 'remove': return removeMarker(options); break; case 'update': return updateMarker(options); break; case 'show': return showMarker(options); break; case 'hide': return hideMarker(options); break; } } function addMarker(options) { var guid = options.guid || map23DControl.buildGuid('marker23D'); if (!options.RBkey) { var markerTime = null; } else { var markerTime = map23DData.polylines[map2DViewer.routeBackGroup[options.RBkey].polyline].geojson.properties.times; } if (options.vectorMarker) { var dataSize = options.geojson.properties.baseSize; var curZoom = map23DData.view.zoom; var scale = Math.pow(2, curZoom - options.geojson.properties.baseZoom); options.geojson.properties.iconSize = [dataSize[0] * scale, dataSize[1] * scale]; options.geojson.properties.iconAnchor = [dataSize[0] * scale / 2, dataSize[1] * scale / 2]; options.geojson.properties.popupAnchor = [0, -dataSize[1] * scale]; } var defaultData = _.cloneDeep(map23DDefaultData.marker) defaultData.guid = guid; defaultData.geojson.properties.markerTime = markerTime; _.merge(defaultData, options); map23DData.markers[guid] = defaultData; PubSub.publishSync('map23D.marker.add', guid); return guid; } function removeMarker(options) { if (map23DData.markers[options.guid]) { PubSub.publishSync('map23D.marker.remove', options.guid); delete map23DData.markers[options.guid]; return options.guid; } else { return false; } } function updateMarker(options) { if (map23DData.markers[options.guid]) { _.merge(map23DData.markers[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.markers[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map23D.marker.update', options.guid); return options.guid; } else { return false } } function showMarker(options) { var guid = options.guid; PubSub.publishSync('map23D.marker.show', guid); }; function hideMarker(options) { var guid = options.guid; PubSub.publishSync('map23D.marker.hide', guid); }; }(window, document)); ; (function (window, document, undefined) { var polyline = map23DControl.polyline; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = polyline; } else if (typeof define === 'function' && define.amd) { define(polyline); } map23DControl.polyline = function (options) { switch (options.action) { case 'add': return addPolyline(options); break; case 'remove': return removePolyline(options); break; case 'update': return updatePolyline(options); break; case 'show': return showPolyline(options); break; case 'hide': return hidePolyline(options); break; } } function addPolyline(options) { var guid = options.guid || map23DControl.buildGuid('polyline23D'); var defaultData = _.cloneDeep(map23DDefaultData.polyline) defaultData.guid = guid; _.merge(defaultData, options); map23DData.polylines[guid] = defaultData; PubSub.publishSync('map23D.polyline.add', guid); return guid; } function removePolyline(options) { if (map23DData.polylines[options.guid]) { PubSub.publishSync('map23D.polyline.remove', options.guid); delete map23DData.polylines[options.guid]; return options.guid; } else { return false; } } function updatePolyline(options) { if (map23DData.polylines[options.guid]) { _.merge(map23DData.polylines[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polylines[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map23D.polyline.update', options.guid); return options.guid; } else { return false } } function showPolyline(options) { if (map23DData.polylines[options.guid]) { _.merge(map23DData.polylines[options.guid], options); PubSub.publishSync('map23D.polyline.show', options.guid); return options.guid; } else { return false } } function hidePolyline(options) { if (map23DData.polylines[options.guid]) { _.merge(map23DData.polylines[options.guid], options); PubSub.publishSync('map23D.polyline.hide', options.guid); return options.guid; } else { return false } } }(window, document)); ; (function (window, document, undefined) { var polygon = map23DControl.polygon; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = polygon; } else if (typeof define === 'function' && define.amd) { define(polygon); } map23DControl.polygon = function (options) { switch (options.action) { case 'add': return addPolygon(options); break; case 'remove': return removePolygon(options); break; case 'update': return updatePolygon(options); break; case 'hide': return hidePolygon(options); break; case 'show': return showPolygon(options); break; } } function addPolygon(options) { var guid = options.guid || map23DControl.buildGuid('polygon23D'); var defaultData = _.cloneDeep(map23DDefaultData.polygon) defaultData.guid = guid; _.merge(defaultData, options); map23DData.polygons[guid] = defaultData; PubSub.publishSync('map23D.polygon.add', guid); delete map23DData.polygons[guid].action return guid; } function removePolygon(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map23D.polygon.remove', options.guid); delete map23DData.polygons[options.guid]; return options.guid; } else { return false; } } function updatePolygon(options) { if (map23DData.polygons[options.guid]) { _.merge(map23DData.polygons[options.guid], options); if (options.geojson.geometry) { if (options.geojson.geometry.coordinates) map23DData.polygons[options.guid].geojson.geometry.coordinates = options.geojson.geometry.coordinates } PubSub.publishSync('map23D.polygon.update', options.guid); return options.guid; } else { return false } } function hidePolygon(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map23D.polygon.hide', options.guid); return options.guid; } else { return false; } } function showPolygon(options) { if (map23DData.polygons[options.guid]) { PubSub.publishSync('map23D.polygon.show', options.guid); return options.guid; } else { return false; } } }(window, document)); ; (function (window, document, undefined) { var modValue = {} map3DViewer.radar = function (options) { switch (options.action) { case 'add': return init(options); break; case 'draw': return draw(options); break; case 'start': return start(options); break; case 'stop': return stop(options); break; case 'remove': return remove(options); break; case 'clear': return clear(options); break; } } function init(options) { clear(); modValue.callback = options.callback; modValue.handler = null; modValue.tempEntities = {} } function start(options) { modValue.center = []; modValue.guid = options.guid || map23DControl.buildGuid('radar23D'); modValue.tempEntities[modValue.guid] = []; modValue.radius = options.radius modValue.circleTangle = options.circleTangle || 5; if (!modValue.handler) { modValue.handler = new Cesium.ScreenSpaceEventHandler(map3DViewer.map.scene.canvas); modValue.handler.setInputAction(function (evt) { var pick = new Cesium.Cartesian2(evt.position.x, evt.position.y); var cartesian = map3DViewer.map.scene.globe.pick(map3DViewer.map.camera.getPickRay(pick), map3DViewer.map.scene); if (cartesian) { var obj = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian) var center_lon = Cesium.Math.toDegrees(obj.longitude) var center_lat = Cesium.Math.toDegrees(obj.latitude) modValue.center = [ center_lon, center_lat, modValue.radius ] draw(); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } } function draw() { //圆心 var allCirclePoint = []; var extrudes = []; //半径 var radius = modValue.radius; //米 var circleTangle = modValue.circleTangle // //计算圆心到极点的距离 // if (center_lat < 0) { // var centerToPole = turf.distance(turf.point([center_lon, center_lat]), turf.point([center_lon, -90])) // new L.LatLng(center_lat, center_lon).distanceTo(new L.LatLng(-90, center_lon)); // } else { // var centerToPole = turf.distance(turf.point([center_lon, center_lat]), turf.point([center_lon, 90])) // } var minExtrudes = getLDCircleExtrude(radius); for (var i = 0; i <= 90; i += circleTangle) { if (i == 90) { var curHeight = radius; } else { var ral = (i * Math.PI) / 180; var curHeight = radius * Math.sin(ral); } if (i != 0) { if (curHeight < minExtrudes) { curHeight = minExtrudes; } } var curBRedius = Math.sqrt(Math.pow(radius, 2) - Math.pow(curHeight, 2)); var center = turf.point([modValue.center[0], modValue.center[1]]); if (i == 90) { curBRedius = 0.1; } var circle = turf.circle(center, curBRedius, { steps: 360 / 5, units: 'meters', }); var circlePoints = circle.geometry.coordinates[0]; extrudes.push(curHeight); allCirclePoint.push(circlePoints) if (i == 90) { addCircleToPolygon(allCirclePoint, extrudes); } } } function stop() { detach(); } function remove() { detach(); clear(); } function detach() { if (modValue.handler) { modValue.handler.destroy(); modValue.handler = null } } function clear(guid) { if (guid) { if (modValue.tempEntities) { if (modValue.tempEntities.hasOwnProperty(guid)) { var arr = modValue.tempEntities[guid]; for (var i = 0; i < arr.length; i++) { map3DViewer.map.entities.removeById(arr[i]._id) } delete modValue.tempEntities[guid] } } } else { if (modValue.tempEntities) for (var key in modValue.tempEntities) { if (modValue.tempEntities.hasOwnProperty(key)) { var arr = modValue.tempEntities[key]; for (var i = 0; i < arr.length; i++) { map3DViewer.map.entities.removeById(arr[i]._id) } } } modValue.tempEntities = {}; } modValue.center = []; } /** * 计算雷达半球最低拉伸高度 */ function getLDCircleExtrude(radius) { var earthRadius = 6371000; //地球半径 var tangle = (360 * radius) / (4 * Math.PI * earthRadius); tangle = tangle * Math.PI / 180; var minExtrude = 2 * earthRadius * Math.sin(tangle) * Math.sin(tangle); return minExtrude; } function addCircleToPolygon(allCirclePoint, extrudes) { var pos = {}; for (var n = 0; n < allCirclePoint.length; n++) { var curExtrude = extrudes[n]; var positions = []; for (var i = 0; i < allCirclePoint[n].length; i++) { positions.push(allCirclePoint[n][i][0], allCirclePoint[n][i][1], curExtrude); if (i < (allCirclePoint[n].length - 1) / 2) { if (!pos[i]) { pos[i] = { push_item: [], unshift_item: [], all: [], } } pos[i].push_item.push(allCirclePoint[n][i][0], allCirclePoint[n][i][1], curExtrude); pos[i].unshift_item.unshift(allCirclePoint[n][(allCirclePoint[n].length - 1) / 2 + i][0], allCirclePoint[n][(allCirclePoint[n].length - 1) / 2 + i][1], curExtrude); if (n == allCirclePoint.length - 1) { pos[i].all = pos[i].all.concat(pos[i].push_item, modValue.center[0], modValue.center[1], modValue.center[2], pos[i].unshift_item) var entity = map3DViewer.map.entities.add({ polyline: { positions: Cesium.Cartesian3.fromDegreesArrayHeights(pos[i].all), arcType: Cesium.ArcType.NONE, width: 2, material: Cesium.Color.GREEN, // depthFailMaterial: Cesium.Color.RED } }) modValue.tempEntities[modValue.guid] = modValue.tempEntities[modValue.guid].concat([entity]) } } } position = Cesium.Cartesian3.fromDegreesArrayHeights(positions); var entity = map3DViewer.map.entities.add({ polyline: { positions: position, arcType: Cesium.ArcType.NONE, width: 2, material: Cesium.Color.GREEN, // depthFailMaterial: Cesium.Color.RED } }) modValue.tempEntities[modValue.guid] = modValue.tempEntities[modValue.guid].concat([entity]) } if (modValue.callback) modValue.callback(); } }(window, document)); ; (function (window, document, undefined) { var tileLayer = map23DControl.tileLayer; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = tileLayer; } else if (typeof define === 'function' && define.amd) { define(tileLayer); } /** * 设置系统自带图层 * @param {[type]} options [description] */ map23DControl.setDefaultTileLayer = function (options) { PubSub.publish('map23D.defaultTileLayer.change', { mapName: options }) } map23DControl.tileLayer = function (options) { switch (options.action) { case 'add': return addTileLayer(options); break; case 'remove': return removeTileLayer(options); break; case 'update': return updateTileLayer(options); break; case 'hide': return hideTileLayer(options); break; case 'show': return showTileLayer(options); break; } } function addTileLayer(options) { var guid = options.guid || map23DControl.buildGuid('tileLayer23D'); var defaultData = _.cloneDeep(map23DDefaultData.layer) defaultData.guid = guid; _.merge(defaultData, options); map23DData.layers[guid] = defaultData; PubSub.publishSync('map23D.tileLayer.add', guid); return guid; } /** * 移除图层组,移除前先清除图层组中的元素 * @param {[type]} options [description] * @return {[type]} [description] */ function removeTileLayer(options) { if (map23DData.layers[options.guid]) { PubSub.publishSync('map23D.tileLayer.remove', options.guid); delete map23DData.layers[options.guid]; return options.guid; } else { return false; } } function updateTileLayer(options) { if (map23DData.layers[options.guid]) { _.merge(map23DData.layers[options.guid], options); PubSub.publishSync('map23D.tileLayer.update', options.guid); return options.guid; } else { return false; } } function showTileLayer(options) { if (map23DData.layers[options.guid]) { _.merge(map23DData.layers[options.guid], options); PubSub.publishSync('map23D.tileLayer.show', options.guid); return options.guid; } else { return false; } } function hideTileLayer(options) { if (map23DData.layers[options.guid]) { _.merge(map23DData.layers[options.guid], options); PubSub.publishSync('map23D.tileLayer.hide', options.guid); return options.guid; } else { return false; } } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.group.add', add2Dgroup); PubSub.subscribe('map23D.group.remove', remove2Dgroup); PubSub.subscribe('map23D.group.show', show2Dgroup); PubSub.subscribe('map23D.group.hide', hide2Dgroup); PubSub.subscribe('map2D.group.add', add2Dgroup); PubSub.subscribe('map2D.group.remove', remove2Dgroup); PubSub.subscribe('map2D.group.show', show2Dgroup); PubSub.subscribe('map2D.group.hide', hide2Dgroup); function add2Dgroup(msg, guid) { if (!map2DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '3D') { return false; } var group = L.featureGroup(); if (groupData.clustering) group = L.markerClusterGroup(groupData.clusterOptions); group.guid = guid; group.addTo(map2DViewer.map); map2DViewer.groups[guid] = group; groupData.add2D = true; groupData.visible2D = true; } function remove2Dgroup(msg, guid) { if (!map2DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '3D') { return false; } map2DViewer.map.removeLayer(map2DViewer.groups[guid]); delete map2DViewer.groups[guid]; groupData.add2D = false; } function show2Dgroup(msg, guid) { if (!map2DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '3D') { return false; } if (groupData.visible2D) { return false; } map2DViewer.groups[guid].addTo(map2DViewer.map); groupData.visible2D = true; } function hide2Dgroup(msg, guid) { if (!map2DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '3D') { return false; } if (!groupData.visible2D) { return false; } map2DViewer.map.removeLayer(map2DViewer.groups[guid]); groupData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.group.add', add3Dgroup); PubSub.subscribe('map23D.group.remove', remove3Dgroup); PubSub.subscribe('map23D.group.show', show3Dgroup); PubSub.subscribe('map23D.group.hide', hide3Dgroup); PubSub.subscribe('map3D.group.add', add3Dgroup); PubSub.subscribe('map3D.group.remove', remove3Dgroup); PubSub.subscribe('map3D.group.show', show3Dgroup); PubSub.subscribe('map3D.group.hide', hide3Dgroup); function add3Dgroup(msg, guid) { if (!map3DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '2D') { return false; } var group = new Cesium.EntityCollection({ id: guid, show: true }) map3DViewer.groups[guid] = group; groupData.add3D = true; }; function remove3Dgroup(msg, guid) { if (!map3DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '2D') { return false; } if (!map3DViewer.groups[guid]) { return false } // 三维图层组未添加到viewer中 // map3DViewer.groups[guid].removeAll(); delete map3DViewer.groups[guid]; groupData.add3D = false; }; function hide3Dgroup(msg, guid) { if (!map3DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '2D') { return false; } }; function show3Dgroup(msg, guid) { if (!map3DViewer.inited) { return false; } var groupData = map23DData.groups[guid]; if (groupData.from === '2D') { return false; } }; }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.marker.add', add2Dmarker); PubSub.subscribe('map23D.marker.show', show2Dmarker); PubSub.subscribe('map23D.marker.hide', hide2Dmarker); PubSub.subscribe('map23D.marker.remove', remove2Dmarker); PubSub.subscribe('map23D.marker.update', update2Dmarker); PubSub.subscribe('map2D.marker.add', add2Dmarker); PubSub.subscribe('map2D.marker.show', show2Dmarker); PubSub.subscribe('map2D.marker.hide', hide2Dmarker); PubSub.subscribe('map2D.marker.remove', remove2Dmarker); PubSub.subscribe('map2D.marker.update', update2Dmarker); function creatPopup(options) { var popupHtml = '' return popupHtml; } function marker_icon(markerData) { if (markerData.geojson.properties.fontIcon) { var icon_html = '
' + markerData.geojson.properties.fontIcon + '
'; } else { var icon_html = ''; } return icon_html; } function add2Dmarker(msg, guid) { if (!map2DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '3D') { return false; } if (markerData['animate']) { var icon_html = marker_icon(markerData); var setDivIcon = L.divIcon({ className: 'rorate_div', html: icon_html, iconAnchor: markerData.geojson.properties.iconAnchor, iconSize: markerData.geojson.properties.iconSize, popupAnchor: markerData.geojson.properties.popupAnchor }); var marker = L.animatedMarker(map2DViewer.polylines[map2DViewer.routeBackGroup[markerData.RBkey].polyline].getLatLngs(), { icon: setDivIcon, autoStart: markerData.geojson.properties.autoStart, interval: markerData.geojson.properties.interval, distance: markerData.geojson.properties.distance, onEnd: function () { marker.stop(); } }); } else { var icon_html = marker_icon(markerData); var setDivIcon = L.divIcon({ className: 'rorate_div', html: icon_html, iconAnchor: markerData.geojson.properties.iconAnchor, iconSize: markerData.geojson.properties.iconSize, popupAnchor: markerData.geojson.properties.popupAnchor }); var marker = L.marker( map23DUtil.latLngsToReverse(markerData.geojson.geometry.coordinates), { icon: setDivIcon, title: markerData.geojson.properties.title } ) PubSub.subscribe('map2DViewerZoomend', function () { if (markerData.vectorMarker) { setTimeout(function () { var dataSize = markerData.geojson.properties.baseSize; var curZoom = map2DViewer.map.getZoom(); if (curZoom >= markerData.geojson.properties.baseZoom) { var scaleX = dataSize[0] + dataSize[0] * (curZoom - markerData.geojson.properties.baseZoom); var scaleY = dataSize[1] + dataSize[1] * (curZoom - markerData.geojson.properties.baseZoom); } else { var scaleX = dataSize[0] * Math.pow(markerData.geojson.properties.baseZoom - curZoom + 1, -1); var scaleY = dataSize[1] * Math.pow(markerData.geojson.properties.baseZoom - curZoom + 1, -1); } markerData.geojson.properties.iconSize = [scaleX, scaleY]; markerData.geojson.properties.iconAnchor = [scaleX / 2, scaleY / 2]; markerData.geojson.properties.popupAnchor = [0, -scaleY]; var icon_html = marker_icon(markerData); var setDivIcon = L.divIcon({ className: 'rorate_div', html: icon_html, iconAnchor: markerData.geojson.properties.iconAnchor, iconSize: markerData.geojson.properties.iconSize, popupAnchor: markerData.geojson.properties.popupAnchor }); marker.setIcon(setDivIcon); }, 3) } }) } marker.guid = guid; //markerData.geojson.properties.title //markerData.geojson.properties.popupContent //creatPopup(markerData.geojson.properties) if (markerData.geojson.properties.popupContent) { marker.bindPopup(markerData.geojson.properties.popupContent, { closeButton: false, autoPan: false, }) } if (markerData.groupId) { marker.addTo(map2DViewer.groups[markerData.groupId]); } else { marker.addTo(map2DViewer.map); } map2DViewer.markers[guid] = marker; markerData.add2D = true; markerData.visible2D = true; }; function remove2Dmarker(msg, guid) { if (!map2DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '3D') { return false; } if (markerData.groupId) { map2DViewer.groups[markerData.groupId].removeLayer(map2DViewer.markers[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.markers[guid]); } delete map2DViewer.markers[guid]; markerData.add2D = false; }; function update2Dmarker(msg, guid) { if (!map2DViewer.inited) { return false; } if (map23DData.markers[guid]) { var markerData = map23DData.markers[guid]; if (markerData.from === '3D') { return false; } var marker = map2DViewer.markers[guid]; marker.setLatLng(map23DUtil.latLngsToReverse(markerData.geojson.geometry.coordinates)); var icon_html = marker_icon(markerData); var setDivIcon = L.divIcon({ className: 'rorate_div', html: icon_html, iconAnchor: markerData.geojson.properties.iconAnchor, iconSize: markerData.geojson.properties.iconSize, popupAnchor: markerData.geojson.properties.popupAnchor }); marker.setIcon(setDivIcon); if (markerData.geojson.properties.popupContent) { marker.bindPopup(markerData.geojson.properties.popupContent, { closeButton: false, autoPan: false, }) } delete markerData.action; } }; function show2Dmarker(msg, guid) { if (!map2DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '3D') { return false; } if (markerData.visible2D) { return false; } if (markerData.groupId) { map2DViewer.markers[guid].addTo(map2DViewer.groups[markerData.groupId]); } else { map2DViewer.markers[guid].addTo(map2DViewer.map); } markerData.visible2D = true; } function hide2Dmarker(msg, guid) { if (!map2DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '3D') { return false; } if (!markerData.visible2D) { return false; } if (markerData.groupId) { map2DViewer.groups[markerData.groupId].removeLayer(map2DViewer.markers[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.markers[guid]); } markerData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.marker.showPopup', showMarkerPopup); PubSub.subscribe('map23D.marker.add', add3Dmarker); PubSub.subscribe('map23D.marker.remove', remove3Dmarker); PubSub.subscribe('map23D.marker.update', update3Dmarker); PubSub.subscribe('map23D.marker.hide', hide3Dmarker); PubSub.subscribe('map23D.marker.show', show3Dmarker); PubSub.subscribe('map3D.marker.add', add3Dmarker); PubSub.subscribe('map3D.marker.remove', remove3Dmarker); PubSub.subscribe('map3D.marker.update', update3Dmarker); PubSub.subscribe('map3D.marker.hide', hide3Dmarker); PubSub.subscribe('map3D.marker.show', show3Dmarker); function add3Dmarker(msg, guid) { if (!map3DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '2D') { return false; } if (markerData.geojson.properties.altitudeMode == 0) { var position = Cesium.Cartesian3.fromDegrees(markerData.geojson.geometry.coordinates[0], markerData.geojson.geometry.coordinates[1]); } else { var position = Cesium.Cartesian3.fromDegrees(markerData.geojson.geometry.coordinates[0], markerData.geojson.geometry.coordinates[1], markerData.geojson.properties.altitude); } var markerDataObj = { id: guid, name: markerData.geojson.properties.title, position: position, billboard: { // image: markerData.geojson.properties.iconUrl, width: markerData.geojson.properties.iconSize[0], height: markerData.geojson.properties.iconSize[1], verticalOrigin: Cesium.VerticalOrigin.BOTTOM, rotation: markerData.geojson.properties.iconRorate, heightReference: 1, pixelOffset: new Cesium.Cartesian2(0, 0), distanceDisplayCondition: new Cesium.DistanceDisplayCondition(markerData.geojson.properties.distanceDisplayCondition[0], markerData.geojson.properties.distanceDisplayCondition[1]), }, label: { text: name, font: markerData.geojson.properties.titleFontSize + 'px Microsoft YaHei', verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // pixelOffset: new Cesium.Cartesian2(0, -markerData.geojson.properties.iconSize[1] - 2), heightReference: 1, fillColor: Cesium.Color.fromCssColorString(markerData.geojson.properties.titleColor), distanceDisplayCondition: new Cesium.DistanceDisplayCondition(markerData.geojson.properties.distanceDisplayCondition[0], markerData.geojson.properties.distanceDisplayCondition[1]), } } var marker = map3DViewer.map.entities.add(markerDataObj); delete markerData.action; map3DViewer.markers[guid] = marker; if (markerData.groupId) { map3DViewer.groups[markerData.groupId].add(marker); } markerData.add3D = true; markerData.visible3D = true; }; function remove3Dmarker(msg, guid) { if (!map3DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (!markerData.from === '2D') { return false; } if (!map3DViewer.markers[guid]) { return false; } var marker = map3DViewer.markers[guid]; map3DViewer.map.entities.remove(marker); if (markerData.groupId) { map3DViewer.groups[markerData.groupId].remove(marker) } delete map3DViewer.markers[guid]; markerData.add3D = false; }; function update3Dmarker(msg, guid) { if (!map3DViewer.inited) { return false; } if (map23DData.markers[guid]) { var markerData = map23DData.markers[guid]; if (markerData.from === '2D') { return false; } if (!map3DViewer.markers[guid]) { return false; } var marker = map3DViewer.markers[guid]; var properties = markerData.geojson.properties; var geometry = markerData.geojson.geometry; if (geometry) { var altitude = properties.altitude || markerData.geojson.properties.altitude; if (properties.altitudeMode == 0) { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1]); } else { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1], properties.altitude); } marker.position = position; } if (properties.iconUrl) { marker.billboard.image = properties.iconUrl; } if (properties.iconSize) { marker.billboard.width = properties.iconSize[0]; marker.billboard.height = properties.iconSize[1]; } if (properties.iconAnchor) { marker.label.pixelOffset = new Cesium.Cartesian2(0, -properties.iconSize[1] - 2); // var x = markerData.geojson.properties.iconAnchor[0] - markerData.geojson.properties.iconSize[0] // var y = markerData.geojson.properties.iconAnchor[1] - markerData.geojson.properties.iconSize[1] marker.billboard.pixelOffset = new Cesium.Cartesian2(0, 0); } if (properties.titleFontSize) { marker.label.font = properties.titleFontSize + 'pt monospace'; } marker.label.text = properties.title || ''; if (properties.titleColor) { marker.label.fillColor = Cesium.Color.fromCssColorString(properties.titleColor); } if (markerData.groupId) { //已更新,无需下步 //map3DViewer.groups[markerData.groupId].getById(guid) = marker; } delete markerData.action; } }; function show3Dmarker(msg, guid) { if (!map3DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '2D') { return false; } if (markerData.visible3D) { return false; } if (!map3DViewer.markers[guid]) { return false; } var marker = map3DViewer.markers[guid]; marker.show = true; if (markerData.groupId) { map3DViewer.groups[markerData.groupId].getById(guid).show = true } markerData.visible3D = true; } function hide3Dmarker(msg, guid) { if (!map3DViewer.inited) { return false; } var markerData = map23DData.markers[guid]; if (markerData.from === '2D') { return false; } if (!markerData.visible3D) { return false; } if (!map3DViewer.markers[guid]) { return false; } var marker = map3DViewer.markers[guid]; marker.show = false; if (markerData.groupId) { map3DViewer.groups[markerData.groupId].getById(guid).show = false } markerData.visible3D = false; } var marker3DInterVal = null; function creatPopup(options) { var popupHtml = '' return popupHtml; } function showMarkerPopup(msg, options) { if (options.type == "LEFT_CLICK") { if ($("#markerPopup")) { $("#markerPopup").remove(); } clearInterval(marker3DInterVal); var evt = options.infos; var pickedObject = map3DViewer.map.scene.pick(evt.position); if (pickedObject && pickedObject.id) { var clickMarkerId = pickedObject.id._id; if (map23DData.markers[clickMarkerId]) { var data = map23DData.markers[clickMarkerId]; data.geojson.properties.popupContent = data.geojson.properties.popupContent || ''; data.geojson.properties.title = data.geojson.properties.title || ''; var popupAnchor = data.geojson.properties.popupAnchor; var cartesian = map3DViewer.markers[clickMarkerId].position.getValue(); var pick = map3DViewer.Cartesian3ToScreen(cartesian); if (data.geojson.properties.popupContent.length > 0) { //var popupItem = '
' + creatPopup(data.geojson.properties) + '
'; var popupItem = '
' + data.geojson.properties.popupContent + '
'; $(popupItem).appendTo($("#map3DWrap")); var width = $("#markerPopup").width(); var height = $("#markerPopup").height(); $("#markerPopup").css({ 'left': pick.x - width / 2 - popupAnchor[0], 'top': pick.y - height - popupAnchor[1] }) marker3DInterVal = setInterval(function () { if (Object.getOwnPropertyNames(map3DViewer.markers).length <= 0) { clearInterval(marker3DInterVal); return; } var cartesian = map3DViewer.markers[clickMarkerId].position.getValue(); var pick = map3DViewer.Cartesian3ToScreen(cartesian); $("#markerPopup").css({ 'left': pick.x - width / 2 - popupAnchor[0], 'top': pick.y - height - popupAnchor[1] }) }, 10) } } } else { return false; } } } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.polyline.add', add2Dpolyline); PubSub.subscribe('map23D.polyline.remove', remove2Dplyline); PubSub.subscribe('map23D.polyline.update', update2Dpolyline); PubSub.subscribe('map23D.polyline.show', show2Dpolyline); PubSub.subscribe('map23D.polyline.hide', hide2Dpolyline); PubSub.subscribe('map2D.polyline.add', add2Dpolyline); PubSub.subscribe('map2D.polyline.remove', remove2Dplyline); PubSub.subscribe('map2D.polyline.update', update2Dpolyline); PubSub.subscribe('map2D.polyline.show', show2Dpolyline); PubSub.subscribe('map2D.polyline.hide', hide2Dpolyline); function add2Dpolyline(msg, guid) { if (!map2DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '3D') { return false; } /*for(var i=0;i 1) { map2DViewer.polylines[guid].setLatLngs(map23DUtil.latLngsToReverse(polylineData.geojson.geometry.coordinates)); } } if (polylineData.geojson.properties.popupContent) { polyline.bindPopup(polylineData.geojson.properties.popupContent) } }; function show2Dpolyline(msg, guid) { if (!map2DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '3D') { return false; } if (polylineData.visible2D) { return false; } if (polylineData.groupId) { map2DViewer.polylines[guid].addTo(map2DViewer.groups[polylineData.groupId]); } else { map2DViewer.polylines[guid].addTo(map2DViewer.map); } polylineData.visible2D = true; } function hide2Dpolyline(msg, guid) { if (!map2DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '3D') { return false; } if (!polylineData.visible2D) { return false; } if (polylineData.groupId) { map2DViewer.groups[polylineData.groupId].removeLayer(map2DViewer.polylines[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.polylines[guid]); } polylineData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.polyline.add', add3Dpolyline); PubSub.subscribe('map23D.polyline.remove', remove3Dpolyline); PubSub.subscribe('map23D.polyline.update', update3Dpolyline); PubSub.subscribe('map23D.polyline.show', show3Dpolyline); PubSub.subscribe('map23D.polyline.hide', hide3Dpolyline); PubSub.subscribe('map3D.polyline.add', add3Dpolyline); PubSub.subscribe('map3D.polyline.remove', remove3Dpolyline); PubSub.subscribe('map3D.polyline.update', update3Dpolyline); PubSub.subscribe('map3D.polyline.show', show3Dpolyline); PubSub.subscribe('map3D.polyline.hide', hide3Dpolyline); function add3Dpolyline(msg, guid) { if (!map3DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '2D') { return false; } var properties = polylineData.geojson.properties; var geometry = polylineData.geojson.geometry; var position = []; var clampToGround = true; if (properties.altitudeMode == 0) { for (var i = 0; i < geometry.coordinates.length; i++) { position.push(geometry.coordinates[i][0], geometry.coordinates[i][1]); } clampToGround = true position = Cesium.Cartesian3.fromDegreesArray(position); } else { clampToGround = false for (var i = 0; i < geometry.coordinates.length; i++) { position.push(geometry.coordinates[i][0], geometry.coordinates[i][1], properties.altitude[i]); } position = Cesium.Cartesian3.fromDegreesArrayHeights(position); } var materialObj = { color: Cesium.Color.fromCssColorString(properties.color), outlineWidth: 0, outlineColor: Cesium.Color.fromCssColorString('#FFFFFF') } materialObj.color.alpha = properties.opacity; if (properties.lineType == 0) { var material = new Cesium.PolylineOutlineMaterialProperty(materialObj) } else { var material = new Cesium.PolylineDashMaterialProperty(materialObj) } var name = properties.title || '' var polyline = map3DViewer.map.entities.add({ id: guid, name: name, polyline: { clampToGround: clampToGround, positions: position, width: properties.weight, material: material, } }); delete polylineData.action; map3DViewer.polylines[guid] = polyline; if (polylineData.groupId) { map3DViewer.groups[polylineData.groupId].add(polyline); } polylineData.add3D = true; polylineData.visible3D = true; }; function remove3Dpolyline(msg, guid) { if (!map3DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '2D') { return false; } if (!map3DViewer.polylines[guid]) { return false; } var polyline = map3DViewer.polylines[guid]; map3DViewer.map.entities.remove(polyline); if (polylineData.groupId) { map3DViewer.groups[polylineData.groupId].remove(polyline) } delete map3DViewer.polylines[guid]; polylineData.add3D = false; }; function update3Dpolyline(msg, guid) { if (!map3DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '2D') { return false; } if (!map3DViewer.polylines[guid]) { return false; } var properties = polylineData.geojson.properties; var geometry = polylineData.geojson.geometry; var position = []; if (properties.altitudeMode == 0) { for (var i = 0; i < geometry.coordinates.length; i++) { position.push(geometry.coordinates[i][0], geometry.coordinates[i][1]); } position = Cesium.Cartesian3.fromDegreesArray(position); } else { for (var i = 0; i < geometry.coordinates.length; i++) { position.push(geometry.coordinates[i][0], geometry.coordinates[i][1], properties.altitude[i]); } position = Cesium.Cartesian3.fromDegreesArrayHeights(position); } var materialObj = { color: Cesium.Color.fromCssColorString(properties.color), outlineWidth: 0, outlineColor: Cesium.Color.fromCssColorString("#ffffff") } materialObj.color.alpha = properties.opacity; if (properties.lineType == 0) { var material = new Cesium.PolylineOutlineMaterialProperty(materialObj) } else { var material = new Cesium.PolylineDashMaterialProperty(materialObj) } var polyline = map3DViewer.polylines[guid].polyline; polyline.positions.setValue(position); polyline.material = material; polyline.width = properties.weight; if (polylineData.groupId) { //已更新,无需下步 //map3DViewer.groups[polygonData.groupId].getById(guid) = polygons; } delete polylineData.action; }; function show3Dpolyline(msg, guid) { if (!map3DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '2D') { return false; } if (polylineData.visible3D) { return false; } if (!map3DViewer.polylines[guid]) { return false; } var polyline = map3DViewer.polylines[guid]; polyline.show = true; if (polylineData.groupId) { map3DViewer.groups[polylineData.groupId].getById(guid).show = true } polylineData.visible3D = true; } function hide3Dpolyline(msg, guid) { if (!map3DViewer.inited) { return false; } var polylineData = map23DData.polylines[guid]; if (polylineData.from === '2D') { return false; } if (!polylineData.visible3D) { return false; } if (!map3DViewer.polylines[guid]) { return false; } var polyline = map3DViewer.polylines[guid]; polyline.show = false; if (polylineData.groupId) { map3DViewer.groups[polylineData.groupId].getById(guid).show = false } polylineData.visible3D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.polygon.add', add2Dpolygon); PubSub.subscribe('map23D.polygon.remove', remove2Dpolygon); PubSub.subscribe('map23D.polygon.update', update2Dpolygon); PubSub.subscribe('map23D.polygon.hide', hide2Dpolygon); PubSub.subscribe('map23D.polygon.show', show2Dpolygon); PubSub.subscribe('map2D.polygon.add', add2Dpolygon); PubSub.subscribe('map2D.polygon.remove', remove2Dpolygon); PubSub.subscribe('map2D.polygon.update', update2Dpolygon); PubSub.subscribe('map2D.polygon.show', show2Dpolygon); PubSub.subscribe('map2D.polygon.hide', hide2Dpolygon); function add2Dpolygon(msg, guid) { if (!map2DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '3D') { return false; } var polygon = L.polygon( map23DUtil.latLngsToReverse(polygonData.geojson.geometry.coordinates[0]), { color: polygonData.geojson.properties.color, //边框颜色 weight: polygonData.geojson.properties.weight, //边框宽度 fillColor: polygonData.geojson.properties.fillColor, //填充色 opacity: polygonData.geojson.properties.opacity, //线的透明度 fillOpacity: polygonData.geojson.properties.fillOpacity, //填充透明度 title: polygonData.geojson.properties.title } ) if (polygonData.polygontype === "circlepolygon") { L.Util.circleDrawLatlng(polygon); } polygon.guid = guid; polygon.polygontype = polygonData.polygontype; if (polygonData.geojson.properties.popupContent) { polygon.bindPopup(polygonData.geojson.properties.popupContent) } if (polygonData.groupId) { polygon.addTo(map2DViewer.groups[polygonData.groupId]); } else { polygon.addTo(map2DViewer.map); } map2DViewer.polygons[guid] = polygon; polygonData.add2D = true; polygonData.visible2D = true; }; function remove2Dpolygon(msg, guid) { if (!map2DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '3D') { return false; } if (polygonData.groupId) { map2DViewer.groups[polygonData.groupId].removeLayer(map2DViewer.polygons[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.polygons[guid]); } delete map2DViewer.polygons[guid]; polygonData.add2D = false; }; function update2Dpolygon(msg, guid) { if (!map2DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '3D') { return false; } map2DViewer.polygons[guid].setStyle( polygonData.geojson.properties ); if (polygonData.geojson.hasOwnProperty('geometry')) { if (polygonData.geojson.geometry.coordinates[0].length > 1) { map2DViewer.polygons[guid].setLatLngs(map23DUtil.latLngsToReverse(polygonData.geojson.geometry.coordinates[0])); } } if (polygonData.geojson.properties.popupContent) { polygon.bindPopup(polygonData.geojson.properties.popupContent) } delete polygonData.action; }; function show2Dpolygon(msg, guid) { if (!map2DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '3D') { return false; } if (polygonData.visible2D) { return false; } if (polygonData.groupId) { map2DViewer.polygons[guid].addTo(map2DViewer.groups[polygonData.groupId]); } else { map2DViewer.polygons[guid].addTo(map2DViewer.map); } polygonData.visible2D = true; } function hide2Dpolygon(msg, guid) { if (!map2DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '3D') { return false; } if (!polygonData.visible2D) { return false; } if (polygonData.groupId) { map2DViewer.groups[polygonData.groupId].removeLayer(map2DViewer.polygons[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.polygons[guid]); } polygonData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.polygon.add', add3Dpolygon); PubSub.subscribe('map23D.polygon.remove', remove3Dpolygon); PubSub.subscribe('map23D.polygon.update', update3Dpolygon); PubSub.subscribe('map23D.polygon.hide', hide3Dpolygon); PubSub.subscribe('map23D.polygon.show', show3Dpolygon); PubSub.subscribe('map3D.polygon.add', add3Dpolygon); PubSub.subscribe('map3D.polygon.remove', remove3Dpolygon); PubSub.subscribe('map3D.polygon.update', update3Dpolygon); PubSub.subscribe('map3D.polygon.hide', hide3Dpolygon); PubSub.subscribe('map3D.polygon.show', show3Dpolygon); function add3Dpolygon(msg, guid) { if (!map3DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '2D') { return false; } var properties = polygonData.geojson.properties; var geometry = polygonData.geojson.geometry; var position = []; if (properties.video) { var material = document.getElementById(properties.videoContent) } else { var material = Cesium.Color.fromCssColorString(properties.fillColor); } if (properties.weight > 0 || !properties.weight.toString()) { var outlineJudge = true; } else { var outlineJudge = false; } var polygonObj = { outline: outlineJudge, extrudedHeight: properties.extrudedHeight || 0, material: material, outlineWidth: properties.weight, outlineColor: Cesium.Color.fromCssColorString(properties.color) }; polygonObj.material.alpha = properties.fillOpacity; polygonObj.outlineColor.alpha = properties.opacity; polygonObj.height = 0 if (properties.altitudeMode == 0 || !properties.altitudeMode) { for (var i = 0; i < geometry.coordinates[0].length; i++) { position.push(geometry.coordinates[0][i][0], geometry.coordinates[0][i][1]); } position = Cesium.Cartesian3.fromDegreesArray(position); } else { polygonObj.perPositionHeight = true; for (var i = 0; i < geometry.coordinates[0].length; i++) { position.push(geometry.coordinates[0][i][0], geometry.coordinates[0][i][1], properties.altitude[i]); } position = Cesium.Cartesian3.fromDegreesArrayHeights(position); } polygonObj.hierarchy = position; var name = properties.title || '' var polygon = map3DViewer.map.entities.add({ id: guid, name: name, polygon: polygonObj }); delete polygonData.action; map3DViewer.polygons[guid] = polygon; if (polygonData.groupId) { map3DViewer.groups[polygonData.groupId].add(polygon); } polygonData.add3D = true; polygonData.visible3D = true; }; function remove3Dpolygon(msg, guid) { if (!map3DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '2D') { return false; } if (!map3DViewer.polygons[guid]) { return false; } var polygon = map3DViewer.polygons[guid]; map3DViewer.map.entities.remove(polygon); if (polygonData.groupId) { map3DViewer.groups[polygonData.groupId].remove(polygon) } delete map3DViewer.polygons[guid]; polygonData.add3D = false; }; function update3Dpolygon(msg, guid) { if (!map3DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '2D') { return false; } if (!map3DViewer.polygons[guid]) { return false; } var properties = polygonData.geojson.properties; var geometry = polygonData.geojson.geometry; var position = []; var fillColor = Cesium.Color.fromCssColorString(properties.fillColor) fillColor.alpha = properties.fillOpacity; var outlineColor = Cesium.Color.fromCssColorString(properties.color); outlineColor.alpha = properties.opacity; if (properties.altitudeMode == 0 || !properties.altitudeMode) { for (var i = 0; i < geometry.coordinates[0].length; i++) { position.push(geometry.coordinates[0][i][0], geometry.coordinates[0][i][1]); } position = Cesium.Cartesian3.fromDegreesArray(position); } else { for (var i = 0; i < geometry.coordinates[0].length; i++) { position.push(geometry.coordinates[0][i][0], geometry.coordinates[0][i][1], properties.altitude[i]); } position = Cesium.Cartesian3.fromDegreesArrayHeights(position); } var name = properties.title || ''; if (properties.weight > 0 || !properties.weight.toString()) { var outlineJudge = true; } else { var outlineJudge = false; } var polygon = map3DViewer.polygons[guid].polygon polygon.outline = outlineJudge; polygon.hierarchy = position; polygon.material.color = fillColor; polygon.outlineColor = outlineColor; polygon.outlineWidth.setValue(properties.weight) polygon.extrudedHeight = properties.extrudedHeight; if (polygonData.groupId) { //已更新,无需下步 //map3DViewer.groups[polygonData.groupId].getById(guid) = polygons; } delete polygonData.action; }; function show3Dpolygon(msg, guid) { if (!map3DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '2D') { return false; } if (polygonData.visible3D) { return false; } if (!map3DViewer.polygons[guid]) { return false; } var polygon = map3DViewer.polygons[guid]; polygon.show = true; if (polygonData.groupId) { map3DViewer.groups[polygonData.groupId].getById(guid).show = true } polygonData.visible3D = true; }; function hide3Dpolygon(msg, guid) { if (!map3DViewer.inited) { return false; } var polygonData = map23DData.polygons[guid]; if (polygonData.from === '2D') { return false; } if (!polygonData.visible3D) { return false; } if (!map3DViewer.polygons[guid]) { return false; } var polygon = map3DViewer.polygons[guid]; polygon.show = false; if (polygonData.groupId) { map3DViewer.groups[polygonData.groupId].getById(guid).show = false } polygonData.visible3D = false; }; }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.tileLayer.add', add2Dlayer); PubSub.subscribe('map23D.tileLayer.remove', remove2Dlayer); PubSub.subscribe('map23D.tileLayer.update', update2Dlayer); PubSub.subscribe('map23D.tileLayer.show', show2Dlayer); PubSub.subscribe('map23D.tileLayer.hide', hide2Dlayer); PubSub.subscribe('map23D.defaultTileLayer.change', default2DtileLayer); PubSub.subscribe('map2D.tileLayer.add', add2Dlayer); PubSub.subscribe('map2D.tileLayer.remove', remove2Dlayer); PubSub.subscribe('map2D.tileLayer.update', update2Dlayer); PubSub.subscribe('map2D.tileLayer.show', show2Dlayer); PubSub.subscribe('map2D.tileLayer.hide', hide2Dlayer); PubSub.subscribe('map2D.defaultTileLayer.change', default2DtileLayer); function default2DtileLayer(msg, options) { var guid = 'tileLayer2DDefault'; if (options.mapName.length == 0) { if (map2DViewer.layers[guid]) { map2DViewer.map.removeLayer(map2DViewer.layers[guid]); delete map23DData.layers[guid]; } return guid; } if (map2DViewer.layers[guid]) { map2DViewer.map.removeLayer(map2DViewer.layers[guid]); } var tileLayerData = { from: '2D', type: 'tileLayer', guid: guid, layer: { url2D: map23DConfig.tileServerUrl + '/' + options.mapName + '?l={z}&x={x}&y={y}', minZoom: map23DConfig.map2DMinZoom || 1, maxZoom: map23DConfig.map2DMaxZoom || 21, maxNativeZoom: map23DConfig.map2DMaxZoom || 21, attribution: '', opacity: 1 } } map23DData.layers[guid] = tileLayerData; var tileLayer = L.tileLayer(tileLayerData.layer.url2D, { minZoom: tileLayerData.layer.minZoom, maxZoom: tileLayerData.layer.maxZoom, opacity: tileLayerData.layer.opacity, maxNativeZoom: tileLayerData.layer.maxNativeZoom, attribution: tileLayerData.layer.attribution, subdomains: map23DConfig.tileSubdomains || '', noWrap: false }); tileLayer.guid = guid; tileLayer.addTo(map2DViewer.map); tileLayer.bringToBack(); map2DViewer.layers[guid] = tileLayer; return guid; } /** * 根据GUID添加图层 * @param {[type]} msg [description] * @param {[type]} guid [description] */ function add2Dlayer(msg, guid) { if (!map2DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '3D') { return false; } var tileLayer = L.tileLayer(tileLayerData.layer.url2D, { minZoom: tileLayerData.layer.minZoom, maxZoom: tileLayerData.layer.maxZoom, opacity: tileLayerData.layer.opacity, attribution: tileLayerData.layer.attribution, subdomains: map23DConfig.tileSubdomains || '', noWrap: false }); var startTime, stopTime; tileLayer.on('tileloadstart', function () { startTime = new Date(); }) tileLayer.on('load', function () { stop = new Date(); console.log(stop - startTime) }) tileLayer.guid = guid; tileLayer.addTo(map2DViewer.map); map2DViewer.layers[guid] = tileLayer; tileLayerData.add2D = true; tileLayerData.visible2D = true; } /** * 移除指定GUID的图层 * @param {[type]} msg [description] * @param {[type]} guid [description] * @return {[type]} [description] */ function remove2Dlayer(msg, guid) { if (!map2DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '3D') { return false; } map2DViewer.map.removeLayer(map2DViewer.layers[guid]); delete map2DViewer.layers[guid]; tileLayerData.add2D = false; } /** * 更新指定GUID的图层 * @param {[type]} msg [description] * @param {[type]} guid [description] * @return {[type]} [description] */ function update2Dlayer(msg, guid) { if (!map2DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '3D') { return false; } var tileLayer = map2DViewer.layers[guid]; if (tileLayer.options.opacity != tileLayerData.layer.opacity) { tileLayer.setOpacity(tileLayerData.layer.opacity); } if (tileLayer._url != tileLayerData.layer.url2D) { tileLayer.setUrl(tileLayerData.layer.url2D); } } function show2Dlayer(msg, guid) { if (!map2DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '3D') { return false; } if (tileLayerData.visible2D) { return false; } map2DViewer.layers[guid].addTo(map2DViewer.map); tileLayerData.visible2D = true; } function hide2Dlayer(msg, guid) { if (!map2DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '3D') { return false; } if (!tileLayerData.visible2D) { return false; } map2DViewer.map.removeLayer(map2DViewer.layers[guid]); tileLayerData.visible2D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.tileLayer.add', add3DtileLayer); PubSub.subscribe('map23D.tileLayer.remove', remove3DtileLayer); PubSub.subscribe('map23D.tileLayer.update', update3DtileLayer); PubSub.subscribe('map23D.tileLayer.hide', hide3DtileLayer); PubSub.subscribe('map23D.tileLayer.show', show3DtileLayer); PubSub.subscribe('map23D.defaultTileLayer.change', default3DtileLayer); PubSub.subscribe('map3D.tileLayer.add', add3DtileLayer); PubSub.subscribe('map3D.tileLayer.remove', remove3DtileLayer); PubSub.subscribe('map3D.tileLayer.update', update3DtileLayer); PubSub.subscribe('map3D.tileLayer.hide', hide3DtileLayer); PubSub.subscribe('map3D.tileLayer.show', show3DtileLayer); PubSub.subscribe('map3D.defaultTileLayer.change', default3DtileLayer); function default3DtileLayer(msg, options) { var guid = 'tileLayer3DDefault'; if (options.mapName.length == 0) { if (map3DViewer.layers[guid]) { map3DViewer.map.scene.imageryLayers.remove(map3DViewer.layers[guid]); delete map23DData.layers[guid]; } return guid; } if (map3DViewer.layers[guid]) { map3DViewer.map.scene.imageryLayers.remove(map3DViewer.layers[guid]); } if(options.mapName == "gr"){ var url3D = "http://121.43.55.7:10011/proxy?servertype=World_Imagery&token=622067E9-93E5-D8EC-E677-85B58A63C0C7" }else if(options.mapName == "gt"){ var url3D = "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer" }else if(options.mapName == "gm"){ var url3D = "http://121.43.55.7:10011/proxy?servertype=World_Street_Map&token=622067E9-93E5-D8EC-E677-85B58A63C0C7" } var tileLayerData = { from: '3D', type: 'tileLayer', guid: guid, layer: { url3D: url3D, minZoom: map23DConfig.map23DMinZoom || 1, maxZoom: map23DConfig.map23DMaxZoom || 21, imageType: map23DConfig.imageType, //3D瓦片图片类型 layerBounds: map23DConfig.layerBounds, subdomains: map23DConfig.tileSubdomains || '0123456789', opacity: 1 } } map23DData.layers[guid] = tileLayerData; var tileLayer = map3DViewer.map.scene.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({ //默认加载影像图 url: tileLayerData.layer.url3D, minimumLevel: tileLayerData.layer.minZoom, maximumLevel: tileLayerData.layer.maxZoom, format: tileLayerData.layer.imageType || "png", subdomains: tileLayerData.layer.subdomains, rectangle: Cesium.Rectangle.fromDegrees(tileLayerData.layer.layerBounds[0][1], tileLayerData.layer.layerBounds[1][0], tileLayerData.layer.layerBounds[1][1], tileLayerData.layer.layerBounds[0][0]) })) tileLayer.alpha = tileLayerData.layer.opacity; map3DViewer.layers[guid] = tileLayer; tileLayerData.add3D = true; tileLayerData.visible3D = true; } function add3DtileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '2D') { return false; } var tileLayer = map3DViewer.map.scene.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({ //默认加载影像图 url: tileLayerData.layer.url3D, minimumLevel: tileLayerData.layer.minZoom, maximumLevel: tileLayerData.layer.maxZoom, format: tileLayerData.layer.imageType, subdomains: tileLayerData.layer.tileSubdomains || '0123456789', rectangle: Cesium.Rectangle.fromDegrees(tileLayerData.layer.layerBounds[0][1], tileLayerData.layer.layerBounds[1][0], tileLayerData.layer.layerBounds[1][1], tileLayerData.layer.layerBounds[0][0]) })) tileLayer.alpha = tileLayerData.layer.opacity; map3DViewer.layers[guid] = tileLayer; tileLayerData.add3D = true; tileLayerData.visible3D = true; }; function remove3DtileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '2D') { return false; } if (!map3DViewer.layers[guid]) { return false; } if (map3DViewer.layers[guid] != null) { map3DViewer.map.scene.imageryLayers.remove(map3DViewer.layers[guid]); } delete map3DViewer.layers[guid]; tileLayerData.add3D = false; }; function update3DtileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '2D') { return false; } if (!map3DViewer.layers[guid]) { return false; } var layer = map3DViewer.layers[guid] if (map3DViewer.map.scene.imageryLayers.contains(layer)) map3DViewer.map.scene.imageryLayers.remove(layer, true) // (要移除的图层,是否摧毁图层) var tileLayer = map3DViewer.map.scene.imageryLayers.addImageryProvider(new Cesium.UrlTemplateImageryProvider({ //默认加载影像图 url: tileLayerData.layer.url3D, minimumLevel: tileLayerData.layer.minZoom, maximumLevel: tileLayerData.layer.maxZoom, format: tileLayerData.layer.imageType, subdomains: tileLayerData.layer.tileSubdomains || '0123456789', rectangle: Cesium.Rectangle.fromDegrees(tileLayerData.layer.layerBounds[0][1], tileLayerData.layer.layerBounds[1][0], tileLayerData.layer.layerBounds[1][1], tileLayerData.layer.layerBounds[0][0]) })) tileLayer.alpha = tileLayerData.layer.opacity; map3DViewer.layers[guid] = tileLayer; } function show3DtileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '2D') { return false; } if (tileLayerData.visible3D) { return false; } if (!map3DViewer.layers[guid]) { return false; } map3DViewer.layers[guid].show = true; tileLayerData.visible3D = true; } function hide3DtileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var tileLayerData = map23DData.layers[guid]; if (tileLayerData.from === '2D') { return false; } if (!tileLayerData.visible3D) { return false; } if (!map3DViewer.layers[guid]) { return false; } map3DViewer.layers[guid].show = false; tileLayerData.visible3D = false; } }(window, document)); ; (function (window, document, undefined) { map3DViewer.DEMBil = {} PubSub.subscribe('map3D.DEMTileLayer.addEvent', add3DDEMTileLayerEvent); PubSub.subscribe('map3D.DEMTileLayer.add', add3DDEMTileLayer); PubSub.subscribe('map3D.DEMTileLayer.remove', remove3DDEMTileLayer); /** * options={name:"",func:function} */ function add3DDEMTileLayerEvent(msg, options) { map3DViewer.DEMBil[options.name] = options.func } function add3DDEMTileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var DEMTileLayerData = map23DData.DEMLayers[guid]; if (DEMTileLayerData.from === '2D') { return false; } var terrain = null; map3DViewer.map.scene.globe.depthTestAgainstTerrain = false; if (DEMTileLayerData.layer.DEMFormat == 'bil') { terrain = new map3DViewer.DEMBil.InfoCesiumTerrainProvider({ url: DEMTileLayerData.layer.url3D, maxLevel: DEMTileLayerData.layer.DEMMaxZoom, subDomains: DEMTileLayerData.layer.subDomains }) map3DViewer.map.scene.terrainProvider = terrain; } else if (DEMTileLayerData.layer.DEMFormat == 'terrain') { terrain = new Cesium.CesiumTerrainProvider({ url: DEMTileLayerData.layer.url3D, }); map3DViewer.map.scene.terrainProvider = terrain; } }; function remove3DDEMTileLayer(msg, guid) { if (!map3DViewer.inited) { return false; } var DEMTileLayerData = map23DData.DEMLayers[guid]; if (DEMTileLayerData.from === '2D') { return false; } var terrain = new Cesium.EllipsoidTerrainProvider({}); map3DViewer.map.scene.terrainProvider = terrain }; }(window, document)); ; (function (window, document, undefined) { 'use strict'; if (typeof (Cesium) == "undefined") { return; } var Uri = Cesium.Uri; var when = Cesium.when; var BoundingSphere = Cesium.BoundingSphere; var Cartesian3 = Cesium.Cartesian3; var Credit = Cesium.Credit; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var defineProperties = Cesium.defineProperties; var DeveloperError = Cesium.DeveloperError; var Event = Cesium.Event; var GeographicTilingScheme = Cesium.GeographicTilingScheme; var HeightmapTerrainData = Cesium.HeightmapTerrainData; var IndexDatatype = Cesium.IndexDatatype; var joinUrls = Cesium.joinUrls; var loadJson = Cesium.loadJson; var CesiumMath = Cesium.CesiumMath; var Matrix3 = Cesium.Matrix3; var OrientedBoundingBox = Cesium.OrientedBoundingBox; var QuantizedMeshTerrainData = Cesium.QuantizedMeshTerrainData; var RuntimeError = Cesium.RuntimeError; var TerrainProvider = Cesium.TerrainProvider; //var throttleRequestByServer = Cesium.throttleRequestByServer; var TileProviderError = Cesium.TileProviderError; var domainsIndex = 0; /** * A {@link TerrainProvider} that access terrain data in a Cesium terrain format. * The format is described on the * {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Cesium-Terrain-Server|Cesium wiki}. * * @alias CesiumTerrainProvider * @constructor * * @param {Object} options Object with the following properties: * @param {String} options.url The URL of the Cesium terrain server. * @param {Proxy} [options.proxy] A proxy to use for requests. This object is expected to have a getURL function which returns the proxied URL, if needed. * @param {Boolean} [options.requestVertexNormals=false] Flag that indicates if the client should request additional lighting information from the server, in the form of per vertex normals if available. * @param {Boolean} [options.requestWaterMask=false] Flag that indicates if the client should request per tile water masks from the server, if available. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used. * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas. * * * @example * // Construct a terrain provider that uses per vertex normals for lighting * // to add shading detail to an imagery provider. * var terrainProvider = new Cesium.CesiumTerrainProvider({ * url : 'https://assets.agi.com/stk-terrain/world', * requestVertexNormals : true * }); * * // Terrain geometry near the surface of the globe is difficult to view when using NaturalEarthII imagery, * // unless the TerrainProvider provides additional lighting information to shade the terrain (as shown above). * var imageryProvider = Cesium.createTileMapServiceImageryProvider({ * url : 'http://localhost:8080/Source/Assets/Textures/NaturalEarthII', * fileExtension : 'jpg' * }); * * var viewer = new Cesium.Viewer('cesiumContainer', { * imageryProvider : imageryProvider, * baseLayerPicker : false, * terrainProvider : terrainProvider * }); * * // The globe must enable lighting to make use of the terrain's vertex normals * viewer.scene.globe.enableLighting = true; * * @see TerrainProvider */ function InfoCesiumTerrainProvider(options) { //>>includeStart('debug', pragmas.debug) if (!defined(options) || !defined(options.url)) { throw new DeveloperError('options.url is required.'); } //>>includeEnd('debug'); this.maxLevel = defaultValue(options.maxLevel, 0); this._url = _.clone(options.url); this.subDomains = options.subDomains; this._proxy = options.proxy; this._tilingScheme = new GeographicTilingScheme({ numberOfLevelZeroTilesX: 2, numberOfLevelZeroTilesY: 1, ellipsoid: options.ellipsoid }); this._heightmapWidth = 65; this._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(this._tilingScheme.ellipsoid, this._heightmapWidth, this._tilingScheme.getNumberOfXTilesAtLevel(0)); this._heightmapStructure = undefined; this._hasWaterMask = false; /** * Boolean flag that indicates if the Terrain Server can provide vertex normals. * @type {Boolean} * @default false * @private */ this._hasVertexNormals = false; /** * Boolean flag that indicates if the client should request vertex normals from the server. * @type {Boolean} * @default false * @private */ this._requestVertexNormals = defaultValue(options.requestVertexNormals, false); this._littleEndianExtensionSize = true; /** * Boolean flag that indicates if the client should request tile watermasks from the server. * @type {Boolean} * @default false * @private */ this._requestWaterMask = defaultValue(options.requestWaterMask, false); this._errorEvent = new Event(); var credit = options.credit; if (typeof credit === 'string') { credit = new Credit(credit); } this._credit = credit; this._ready = false; this._readyPromise = when.defer(); var metadataUrl = this._url; if (defined(this._proxy)) { metadataUrl = this._proxy.getURL(metadataUrl); } var that = this; var metadataError; function metadataSuccess(data) { var message; if (!data.format) { message = 'The tile format is not specified in the layer.json file.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); return; } if (!data.tiles || data.tiles.length === 0) { message = 'The layer.json file does not specify any tile URL templates.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); return; } if (data.format === 'heightmap-1.0') { that._heightmapStructure = { heightScale: 1.0, heightOffset: 5, elementsPerHeight: 1, stride: 1, elementMultiplier: 256.0, isBigEndian: false, lowestEncodedHeight: 0, highestEncodedHeight: 256 * 256 - 1 }; that._hasWaterMask = false; that._requestWaterMask = false; } else if (data.format.indexOf('quantized-mesh-1.') !== 0) { message = 'The tile format "' + data.format + '" is invalid or not supported.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); return; } that._tileUrlTemplates = that._url; //已更改 that._availableTiles = data.available; if (!defined(that._credit) && defined(data.attribution) && data.attribution !== null) { that._credit = new Credit(data.attribution); } // The vertex normals defined in the 'octvertexnormals' extension is identical to the original // contents of the original 'vertexnormals' extension. 'vertexnormals' extension is now // deprecated, as the extensionLength for this extension was incorrectly using big endian. // We maintain backwards compatibility with the legacy 'vertexnormal' implementation // by setting the _littleEndianExtensionSize to false. Always prefer 'octvertexnormals' // over 'vertexnormals' if both extensions are supported by the server. if (defined(data.extensions) && data.extensions.indexOf('octvertexnormals') !== -1) { that._hasVertexNormals = true; } else if (defined(data.extensions) && data.extensions.indexOf('vertexnormals') !== -1) { that._hasVertexNormals = true; that._littleEndianExtensionSize = false; } if (defined(data.extensions) && data.extensions.indexOf('watermask') !== -1) { that._hasWaterMask = true; } that._ready = true; that._readyPromise.resolve(true); } /****源码更改,不读配置文件,直接初始数据***/ function metadataIni() { metadataSuccess({ tilejson: '2.1.0', format: 'heightmap-1.0', version: '1.0.0', scheme: 'wtms', tiles: [ '?' ] }); return; } /* function metadataFailure(data) { // If the metadata is not found, assume this is a pre-metadata heightmap tileset. if (defined(data) && data.statusCode === 404) { metadataSuccess({ tilejson: '2.1.0', format: 'heightmap-1.0', version: '1.0.0', scheme: 'tms', tiles: [ '{z}/{x}/{y}.terrain?v={version}' ] }); return; } var message = 'An error occurred while accessing ' + metadataUrl + '.'; metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata); } function requestMetadata() { var metadata = loadJson(metadataUrl); when(metadata, metadataSuccess, metadataFailure); } requestMetadata();*/ metadataIni(); } /** * When using the Quantized-Mesh format, a tile may be returned that includes additional extensions, such as PerVertexNormals, watermask, etc. * This enumeration defines the unique identifiers for each type of extension data that has been appended to the standard mesh data. * * @exports QuantizedMeshExtensionIds * @see CesiumTerrainProvider * @private */ var QuantizedMeshExtensionIds = { /** * Oct-Encoded Per-Vertex Normals are included as an extension to the tile mesh * * @type {Number} * @constant * @default 1 */ OCT_VERTEX_NORMALS: 1, /** * A watermask is included as an extension to the tile mesh * * @type {Number} * @constant * @default 2 */ WATER_MASK: 2 }; function getRequestHeader(extensionsList) { if (!defined(extensionsList) || extensionsList.length === 0) { return { Accept: 'application/vnd.quantized-mesh,application/octet-stream;q=0.9,*/*;q=0.01' }; } else { var extensions = extensionsList.join('-'); return { Accept: 'application/vnd.quantized-mesh;extensions=' + extensions + ',application/octet-stream;q=0.9,*/*;q=0.01' }; } } function createHeightmapTerrainData(provider, buffer, level, x, y, tmsY) { var hasChildOrNot; if (level < provider.maxLevel) { hasChildOrNot = new Uint8Array([15])[0]; } else { hasChildOrNot = new Uint8Array([0])[0]; } var yTiles1 = provider._tilingScheme.getNumberOfXTilesAtLevel(level); // var yy1 = (yTiles1 - y - 1); var yy1 = y; var bley = yy1 % 2 == 0 ? true : false; var blex = x % 2 == 0 ? true : false; if (buffer.byteLength > 0) { // var intBuffer0 = new Int16Array(buffer, 0, provider._heightmapWidth * provider._heightmapWidth); var intBuffer0 = new Int16Array(129 * 129); // var intBuffer0 = new Uint16Array(129* 129); //数据高地位字节转换 /* var dataview = new DataView(buffer); for(var ii=0;ii<(129*129);){ var val1=dataview.getInt8(ii); var val2=dataview.getInt8(ii+1); var val3 = ((val1 & 0xFF)|((val2 & 0xFF)<<8)); ii = ii+2; intBuffer0[ii-1] = val3 intBuffer0[ii] = val3; } */ var dataview = new DataView(buffer); for (var ii = 0; ii < (129 * 129 * 2);) { var val1 = dataview.getInt8(ii); var val2 = dataview.getInt8(ii + 1); var val3 = ((val1 & 0xFF) | ((val2 & 0xFF) << 8)); ii = ii + 2; //var val4=[]; //val4[0]=val3; //intBuffer0.set(val4,ii/2-1); intBuffer0[ii / 2 - 1] = val3; } var aabdsk = intBuffer0.subarray(100, 103); var intBuffer1; var intBuffer = intBuffer0.subarray(0, 65 * 65); if (bley) { intBuffer1 = intBuffer0.subarray(0, 65 * 129); } else { intBuffer1 = intBuffer0.subarray(64 * 129, 129 * 129); } if (blex) { for (var i = 0; i < 66; i++) { intBuffer.set(intBuffer1.subarray(129 * i, 129 * i + 65), 65 * i); } } else { for (var i = 0; i < 66; i++) { intBuffer.set(intBuffer1.subarray(129 * i + 64, 129 * (i + 1)), 65 * i); } } /* var temp = 0; //temp用来存储当前高程区块中的最小负值 for (var i = 0; i < intBuffer.length; i++) { if (temp > intBuffer[i]) { temp = intBuffer[i]; } } var heightBuffer = new Uint16Array(intBuffer.length); //该循环将所读取的高程数据中的所有值减去所获取到的高程最小值(该最小值为负值) for (var i = 0; i < intBuffer.length; i++) { heightBuffer[i] = intBuffer[i] - temp; } */ var heightBuffer = intBuffer; var heightmapStructure = { heightScale: 1, heightOffset: 5, elementsPerHeight: 1, stride: 1, elementMultiplier: 256.0, isBigEndian: false, lowestEncodedHeight: 0, highestEncodedHeight: 256 * 256 - 1 }; //console.log(temp); return new HeightmapTerrainData({ buffer: heightBuffer, childTileMask: hasChildOrNot, waterMask: new Uint8Array([0]), width: provider._heightmapWidth, height: provider._heightmapWidth, structure: heightmapStructure }); } else { var heightBuffer = new Uint16Array(provider._heightmapWidth * provider._heightmapWidth); for (var i = 0; i < heightBuffer.byteLength; i++) { heightBuffer[i] = 0; } return new HeightmapTerrainData({ buffer: heightBuffer, childTileMask: hasChildOrNot, waterMask: new Uint8Array([0]), width: provider._heightmapWidth, height: provider._heightmapWidth, structure: provider._heightmapStructure }); } } function createQuantizedMeshTerrainData(provider, buffer, level, x, y, tmsY) { var pos = 0; var cartesian3Elements = 3; var boundingSphereElements = cartesian3Elements + 1; var cartesian3Length = Float64Array.BYTES_PER_ELEMENT * cartesian3Elements; var boundingSphereLength = Float64Array.BYTES_PER_ELEMENT * boundingSphereElements; var encodedVertexElements = 3; var encodedVertexLength = Uint16Array.BYTES_PER_ELEMENT * encodedVertexElements; var triangleElements = 3; var bytesPerIndex = Uint16Array.BYTES_PER_ELEMENT; var triangleLength = bytesPerIndex * triangleElements; var view = new DataView(buffer); var center = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)); pos += cartesian3Length; var minimumHeight = view.getFloat32(pos, true); pos += Float32Array.BYTES_PER_ELEMENT; var maximumHeight = view.getFloat32(pos, true); pos += Float32Array.BYTES_PER_ELEMENT; var boundingSphere = new BoundingSphere( new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)), view.getFloat64(pos + cartesian3Length, true)); pos += boundingSphereLength; var horizonOcclusionPoint = new Cartesian3(view.getFloat64(pos, true), view.getFloat64(pos + 8, true), view.getFloat64(pos + 16, true)); pos += cartesian3Length; var vertexCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var encodedVertexBuffer = new Uint16Array(buffer, pos, vertexCount * 3); pos += vertexCount * encodedVertexLength; if (vertexCount > 64 * 1024) { // More than 64k vertices, so indices are 32-bit. bytesPerIndex = Uint32Array.BYTES_PER_ELEMENT; triangleLength = bytesPerIndex * triangleElements; } // Decode the vertex buffer. var uBuffer = encodedVertexBuffer.subarray(0, vertexCount); var vBuffer = encodedVertexBuffer.subarray(vertexCount, 2 * vertexCount); var heightBuffer = encodedVertexBuffer.subarray(vertexCount * 2, 3 * vertexCount); var i; var u = 0; var v = 0; var height = 0; function zigZagDecode(value) { return (value >> 1) ^ (-(value & 1)); } for (i = 0; i < vertexCount; ++i) { u += zigZagDecode(uBuffer[i]); v += zigZagDecode(vBuffer[i]); height += zigZagDecode(heightBuffer[i]); uBuffer[i] = u; vBuffer[i] = v; heightBuffer[i] = height; } // skip over any additional padding that was added for 2/4 byte alignment if (pos % bytesPerIndex !== 0) { pos += (bytesPerIndex - (pos % bytesPerIndex)); } var triangleCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var indices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, triangleCount * triangleElements); pos += triangleCount * triangleLength; // High water mark decoding based on decompressIndices_ in webgl-loader's loader.js. // https://code.google.com/p/webgl-loader/source/browse/trunk/samples/loader.js?r=99#55 // Copyright 2012 Google Inc., Apache 2.0 license. var highest = 0; for (i = 0; i < indices.length; ++i) { var code = indices[i]; indices[i] = highest - code; if (code === 0) { ++highest; } } var westVertexCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var westIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, westVertexCount); pos += westVertexCount * bytesPerIndex; var southVertexCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var southIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, southVertexCount); pos += southVertexCount * bytesPerIndex; var eastVertexCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var eastIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, eastVertexCount); pos += eastVertexCount * bytesPerIndex; var northVertexCount = view.getUint32(pos, true); pos += Uint32Array.BYTES_PER_ELEMENT; var northIndices = IndexDatatype.createTypedArrayFromArrayBuffer(vertexCount, buffer, pos, northVertexCount); pos += northVertexCount * bytesPerIndex; var encodedNormalBuffer; var waterMaskBuffer; while (pos < view.byteLength) { var extensionId = view.getUint8(pos, true); pos += Uint8Array.BYTES_PER_ELEMENT; var extensionLength = view.getUint32(pos, provider._littleEndianExtensionSize); pos += Uint32Array.BYTES_PER_ELEMENT; if (extensionId === QuantizedMeshExtensionIds.OCT_VERTEX_NORMALS && provider._requestVertexNormals) { encodedNormalBuffer = new Uint8Array(buffer, pos, vertexCount * 2); } else if (extensionId === QuantizedMeshExtensionIds.WATER_MASK && provider._requestWaterMask) { waterMaskBuffer = new Uint8Array(buffer, pos, extensionLength); } pos += extensionLength; } var skirtHeight = provider.getLevelMaximumGeometricError(level) * 5.0; var rectangle = provider._tilingScheme.tileXYToRectangle(x, y, level); var orientedBoundingBox; if (rectangle.width < CesiumMath.PI_OVER_TWO + CesiumMath.EPSILON5) { // Here, rectangle.width < pi/2, and rectangle.height < pi // (though it would still work with rectangle.width up to pi) // The skirt is not included in the OBB computation. If this ever // causes any rendering artifacts (cracks), they are expected to be // minor and in the corners of the screen. It's possible that this // might need to be changed - just change to `minimumHeight - skirtHeight` // A similar change might also be needed in `upsampleQuantizedTerrainMesh.js`. orientedBoundingBox = OrientedBoundingBox.fromRectangle(rectangle, minimumHeight, maximumHeight, provider._tilingScheme.ellipsoid); } return new QuantizedMeshTerrainData({ center: center, minimumHeight: minimumHeight, maximumHeight: maximumHeight, boundingSphere: boundingSphere, orientedBoundingBox: orientedBoundingBox, horizonOcclusionPoint: horizonOcclusionPoint, quantizedVertices: encodedVertexBuffer, encodedNormals: encodedNormalBuffer, indices: indices, westIndices: westIndices, southIndices: southIndices, eastIndices: eastIndices, northIndices: northIndices, westSkirtHeight: skirtHeight, southSkirtHeight: skirtHeight, eastSkirtHeight: skirtHeight, northSkirtHeight: skirtHeight, childTileMask: getChildMaskForTile(provider, level, x, tmsY), waterMask: waterMaskBuffer }); } /** * Requests the geometry for a given tile. This function should not be called before * {@link CesiumTerrainProvider#ready} returns true. The result must include terrain data and * may optionally include a water mask and an indication of which child tiles are available. * * @param {Number} x The X coordinate of the tile for which to request geometry. * @param {Number} y The Y coordinate of the tile for which to request geometry. * @param {Number} level The level of the tile for which to request geometry. * @param {Boolean} [throttleRequests=true] True if the number of simultaneous requests should be limited, * or false if the request should be initiated regardless of the number of requests * already in progress. * @returns {Promise.|undefined} A promise for the requested geometry. If this method * returns undefined instead of a promise, it is an indication that too many requests are already * pending and the request will be retried later. * * @exception {DeveloperError} This function must not be called before {@link CesiumTerrainProvider#ready} * returns true. */ InfoCesiumTerrainProvider.prototype.requestTileGeometry = function (x, y, level, throttleRequests) { //>>includeStart('debug', pragmas.debug) if (!this._ready) { throw new DeveloperError('requestTileGeometry must not be called before the terrain provider is ready.'); } //>>includeEnd('debug'); var urlTemplates = _.clone(this._tileUrlTemplates); if(this.subDomains){ var domainLength = this.subDomains.length; var domainsIndex = Math.ceil(Math.random()*(domainLength - 1)); var domainval = this.subDomains[domainsIndex] urlTemplates = urlTemplates.replace('{s}',domainval); } if (urlTemplates.length === 0) { return undefined; } var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level); // var tmsY = (yTiles - y - 1); var tmsY = y; // var tmsY = y; // var url = urlTemplates + '?l=' + level + '&x=' + x + '&y=' + tmsY + '&ticket=999999'; // console.log("--->"+y); if (level > 1) { //tmsY = Math.round(tmsY/2) + Math.pow(2,level-2); tmsY = parseInt(y / 2 + yTiles / (4)); } var tmsx = parseInt(x / 2); //var url = urlTemplates[(x + tmsY + level) % urlTemplates.length].replace('{z}', level).replace('{x}', x).replace('{y}', x+"_"+tmsY); var url = urlTemplates + '?l=' + level + '&x=' + tmsx + '&y=' + tmsY + '&ticket=999999'; //console.log(yTiles); // console.log(tmsY); // console.log(level); // var url = urlTemplates + '?l=' + level + '&x=' + y + '&y=' + x + '&ticket=999999'; //console.log(url); var proxy = this._proxy; if (defined(proxy)) { url = proxy.getURL(url); } var promise; var extensionList = []; if (this._requestVertexNormals && this._hasVertexNormals) { extensionList.push(this._littleEndianExtensionSize ? "octvertexnormals" : "vertexnormals"); } if (this._requestWaterMask && this._hasWaterMask) { extensionList.push("watermask"); } function tileLoader(tileUrl) { return map3DViewer.DEMBil.loadArrayBuffer(tileUrl, getRequestHeader(extensionList)); } throttleRequests = defaultValue(throttleRequests, true); if (throttleRequests) { promise = map3DViewer.DEMBil.throttleRequestByServer(url, tileLoader); if (!defined(promise)) { return undefined; } } else { promise = tileLoader(url); } var that = this; return when(promise, function (buffer) { // console.log(buffer.byteLength); if (defined(that._heightmapStructure)) { return createHeightmapTerrainData(that, buffer, level, x, y, tmsY); } else { return createQuantizedMeshTerrainData(that, buffer, level, x, y, tmsY); } }); }; defineProperties(InfoCesiumTerrainProvider.prototype, { /** * Gets an event that is raised when the terrain provider encounters an asynchronous error. By subscribing * to the event, you will be notified of the error and can potentially recover from it. Event listeners * are passed an instance of {@link TileProviderError}. * @memberof CesiumTerrainProvider.prototype * @type {Event} */ errorEvent: { get: function () { return this._errorEvent; } }, /** * Gets the credit to display when this terrain provider is active. Typically this is used to credit * the source of the terrain. This function should not be called before {@link CesiumTerrainProvider#ready} returns true. * @memberof CesiumTerrainProvider.prototype * @type {Credit} */ credit: { get: function () { //>>includeStart('debug', pragmas.debug) if (!this._ready) { throw new DeveloperError('credit must not be called before the terrain provider is ready.'); } //>>includeEnd('debug'); return this._credit; } }, /** * Gets the tiling scheme used by this provider. This function should * not be called before {@link CesiumTerrainProvider#ready} returns true. * @memberof CesiumTerrainProvider.prototype * @type {GeographicTilingScheme} */ tilingScheme: { get: function () { //>>includeStart('debug', pragmas.debug) if (!this._ready) { throw new DeveloperError('tilingScheme must not be called before the terrain provider is ready.'); } //>>includeEnd('debug'); return this._tilingScheme; } }, /** * Gets a value indicating whether or not the provider is ready for use. * @memberof CesiumTerrainProvider.prototype * @type {Boolean} */ ready: { get: function () { return this._ready; } }, /** * Gets a promise that resolves to true when the provider is ready for use. * @memberof CesiumTerrainProvider.prototype * @type {Promise.} * @readonly */ readyPromise: { get: function () { return this._readyPromise.promise; } }, /** * Gets a value indicating whether or not the provider includes a water mask. The water mask * indicates which areas of the globe are water rather than land, so they can be rendered * as a reflective surface with animated waves. This function should not be * called before {@link CesiumTerrainProvider#ready} returns true. * @memberof CesiumTerrainProvider.prototype * @type {Boolean} * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready} */ hasWaterMask: { get: function () { //>>includeStart('debug', pragmas.debug) if (!this._ready) { throw new DeveloperError('hasWaterMask must not be called before the terrain provider is ready.'); } //>>includeEnd('debug'); return this._hasWaterMask && this._requestWaterMask; } }, /** * Gets a value indicating whether or not the requested tiles include vertex normals. * This function should not be called before {@link CesiumTerrainProvider#ready} returns true. * @memberof CesiumTerrainProvider.prototype * @type {Boolean} * @exception {DeveloperError} This property must not be called before {@link CesiumTerrainProvider#ready} */ hasVertexNormals: { get: function () { //>>includeStart('debug', pragmas.debug) if (!this._ready) { throw new DeveloperError('hasVertexNormals must not be called before the terrain provider is ready.'); } //>>includeEnd('debug'); // returns true if we can request vertex normals from the server return this._hasVertexNormals && this._requestVertexNormals; } }, /** * Boolean flag that indicates if the client should request vertex normals from the server. * Vertex normals data is appended to the standard tile mesh data only if the client requests the vertex normals and * if the server provides vertex normals. * @memberof CesiumTerrainProvider.prototype * @type {Boolean} */ requestVertexNormals: { get: function () { return this._requestVertexNormals; } }, /** * Boolean flag that indicates if the client should request a watermask from the server. * Watermask data is appended to the standard tile mesh data only if the client requests the watermask and * if the server provides a watermask. * @memberof CesiumTerrainProvider.prototype * @type {Boolean} */ requestWaterMask: { get: function () { return this._requestWaterMask; } } }); /** * Gets the maximum geometric error allowed in a tile at a given level. * * @param {Number} level The tile level for which to get the maximum geometric error. * @returns {Number} The maximum geometric error. */ InfoCesiumTerrainProvider.prototype.getLevelMaximumGeometricError = function (level) { return this._levelZeroMaximumGeometricError / (1 << level); }; function getChildMaskForTile(terrainProvider, level, x, y) { var available = terrainProvider._availableTiles; if (!available || available.length === 0) { return 15; } var childLevel = level + 1; if (childLevel >= available.length) { return 0; } var levelAvailable = available[childLevel]; var mask = 0; mask |= isTileInRange(levelAvailable, 2 * x, 2 * y) ? 1 : 0; mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y) ? 2 : 0; mask |= isTileInRange(levelAvailable, 2 * x, 2 * y + 1) ? 4 : 0; mask |= isTileInRange(levelAvailable, 2 * x + 1, 2 * y + 1) ? 8 : 0; return mask; } function isTileInRange(levelAvailable, x, y) { for (var i = 0, len = levelAvailable.length; i < len; ++i) { var range = levelAvailable[i]; if (x >= range.startX && x <= range.endX && y >= range.startY && y <= range.endY) { return true; } } return false; } /** * Determines whether data for a tile is available to be loaded. * * @param {Number} x The X coordinate of the tile for which to request geometry. * @param {Number} y The Y coordinate of the tile for which to request geometry. * @param {Number} level The level of the tile for which to request geometry. * @returns {Boolean} Undefined if not supported, otherwise true or false. */ InfoCesiumTerrainProvider.prototype.getTileDataAvailable = function (x, y, level) { var available = this._availableTiles; if (!available || available.length === 0) { return undefined; } else { if (level >= available.length) { return false; } var levelAvailable = available[level]; var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level); var tmsY = (yTiles - y - 1); return isTileInRange(levelAvailable, x, tmsY); } }; PubSub.publishSync('map3D.DEMTileLayer.addEvent', { name: 'InfoCesiumTerrainProvider', func: InfoCesiumTerrainProvider }); }(window, document)); ; (function (window, document, undefined) { "use strict"; if (typeof (Cesium) == "undefined") { return; } var Uri = Cesium.Uri; var when = Cesium.when; var defaultValue = Cesium.defaultValue; var activeRequests = {}; var pageUri = typeof document !== 'undefined' ? new Uri(document.location.href) : new Uri(); function getServer(url) { var uri = new Uri(url).resolve(pageUri); uri.normalize(); var server = uri.authority; if (!/:/.test(server)) { server = server + ':' + (uri.scheme === 'https' ? '443' : '80'); } return server; } /** * Because browsers throttle the number of parallel requests allowed to each server, * this function tracks the number of active requests in progress to each server, and * returns undefined immediately if the request would exceed the maximum, allowing * the caller to retry later, instead of queueing indefinitely under the browser's control. * * @exports throttleRequestByServer * * @param {String} url The URL to request. * @param {throttleRequestByServer~RequestFunction} requestFunction The actual function that * makes the request. * @returns {Promise.|undefined} Either undefined, meaning the request would exceed the maximum number of * parallel requests, or a Promise for the requested data. * * * @example * // throttle requests for an image * var url = 'http://madeupserver.example.com/myImage.png'; * function requestFunction(url) { * // in this simple example, loadImage could be used directly as requestFunction. * return Cesium.loadImage(url); * }; * var promise = Cesium.throttleRequestByServer(url, requestFunction); * if (!Cesium.defined(promise)) { * // too many active requests in progress, try again later. * } else { * promise.then(function(image) { * // handle loaded image * }); * } * * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A} */ function throttleRequestByServer(url, requestFunction) { var server = getServer(url); var activeRequestsForServer = defaultValue(activeRequests[server], 0); if (activeRequestsForServer >= throttleRequestByServer.maximumRequestsPerServer) { return undefined; } activeRequests[server] = activeRequestsForServer + 1; return when(requestFunction(url), function (result) { activeRequests[server]--; return result; }).otherwise(function (error) { activeRequests[server]--; return when.reject(error); }); } /** * Specifies the maximum number of requests that can be simultaneously open to a single server. If this value is higher than * the number of requests per server actually allowed by the web browser, Cesium's ability to prioritize requests will be adversely * affected. * @type {Number} * @default 6 */ throttleRequestByServer.maximumRequestsPerServer = 6; /** * A function that will make a request if there are available slots to the server. * @callback throttleRequestByServer~RequestFunction * * @param {String} url The url to request. * @returns {Promise.} A promise for the requested data. */ PubSub.publishSync('map3D.DEMTileLayer.addEvent', { name: 'throttleRequestByServer', func: throttleRequestByServer }); }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.DEMTileLayer.loadArrayBuffer', loadArrayBuffer); /** * Asynchronously loads the given URL as raw binary data. Returns a promise that will resolve to * an ArrayBuffer once loaded, or reject if the URL failed to load. The data is loaded * using XMLHttpRequest, which means that in order to make requests to another origin, * the server must have Cross-Origin Resource Sharing (CORS) headers enabled. * * @exports loadArrayBuffer * * @param {String|Promise.} url The URL of the binary data, or a promise for the URL. * @param {Object} [headers] HTTP headers to send with the requests. * @returns {Promise.} a promise that will resolve to the requested data when loaded. * * * @example * // load a single URL asynchronously * Cesium.loadArrayBuffer('some/url').then(function(arrayBuffer) { * // use the data * }).otherwise(function(error) { * // an error occurred * }); * * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing} * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A} */ function loadArrayBuffer(url, headers) { return map3DViewer.DEMBil.loadWithXhr({ url: url, responseType: 'arraybuffer', headers: headers }) } PubSub.publishSync('map3D.DEMTileLayer.addEvent', { name: 'loadArrayBuffer', func: loadArrayBuffer }); }(window, document)); ; (function (window, document, undefined) { "use strict"; if (typeof (Cesium) == "undefined") { return; } var when = Cesium.when; var defaultValue = Cesium.defaultValue; var defined = Cesium.defined; var DeveloperError = Cesium.DeveloperError; var RequestErrorEvent = Cesium.RequestErrorEvent; var RuntimeError = Cesium.RuntimeError; /** * Asynchronously loads the given URL. Returns a promise that will resolve to * the result once loaded, or reject if the URL failed to load. The data is loaded * using XMLHttpRequest, which means that in order to make requests to another origin, * the server must have Cross-Origin Resource Sharing (CORS) headers enabled. * * @exports loadWithXhr * * @param {Object} options Object with the following properties: * @param {String|Promise.} options.url The URL of the data, or a promise for the URL. * @param {String} [options.responseType] The type of response. This controls the type of item returned. * @param {String} [options.method='GET'] The HTTP method to use. * @param {String} [options.data] The data to send with the request, if any. * @param {Object} [options.headers] HTTP headers to send with the request, if any. * @param {String} [options.overrideMimeType] Overrides the MIME type returned by the server. * @returns {Promise.} a promise that will resolve to the requested data when loaded. * * * @example * // Load a single URL asynchronously. In real code, you should use loadBlob instead. * Cesium.loadWithXhr({ * url : 'some/url', * responseType : 'blob' * }).then(function(blob) { * // use the data * }).otherwise(function(error) { * // an error occurred * }); * * @see loadArrayBuffer * @see loadBlob * @see loadJson * @see loadText * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing} * @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A} */ function loadWithXhr(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); //>>includeStart('debug', pragmas.debug); if (!defined(options.url)) { throw new DeveloperError('options.url is required.'); } //>>includeEnd('debug'); var responseType = options.responseType; var method = defaultValue(options.method, 'GET'); var data = options.data; var headers = options.headers; var overrideMimeType = options.overrideMimeType; return when(options.url, function (url) { var deferred = when.defer(); loadWithXhr.load(url, responseType, method, data, headers, deferred, overrideMimeType); return deferred.promise; }); } var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; function decodeDataUriText(isBase64, data) { var result = decodeURIComponent(data); if (isBase64) { return atob(result); } return result; } function decodeDataUriArrayBuffer(isBase64, data) { var byteString = decodeDataUriText(isBase64, data); var buffer = new ArrayBuffer(byteString.length); var view = new Uint8Array(buffer); for (var i = 0; i < byteString.length; i++) { view[i] = byteString.charCodeAt(i); } return buffer; } function decodeDataUri(dataUriRegexResult, responseType) { responseType = defaultValue(responseType, ''); var mimeType = dataUriRegexResult[1]; var isBase64 = !!dataUriRegexResult[2]; var data = dataUriRegexResult[3]; switch (responseType) { case '': case 'text': return decodeDataUriText(isBase64, data); case 'arraybuffer': return decodeDataUriArrayBuffer(isBase64, data); case 'blob': var buffer = decodeDataUriArrayBuffer(isBase64, data); return new Blob([buffer], { type: mimeType }); case 'document': var parser = new DOMParser(); return parser.parseFromString(decodeDataUriText(isBase64, data), mimeType); case 'json': return JSON.parse(decodeDataUriText(isBase64, data)); default: throw new DeveloperError('Unhandled responseType: ' + responseType); } } // This is broken out into a separate function so that it can be mocked for testing purposes. loadWithXhr.load = function (url, responseType, method, data, headers, deferred, overrideMimeType) { var dataUriRegexResult = dataUriRegex.exec(url); if (dataUriRegexResult !== null) { deferred.resolve(decodeDataUri(dataUriRegexResult, responseType)); return; } var xhr = new XMLHttpRequest(); if (defined(overrideMimeType) && defined(xhr.overrideMimeType)) { xhr.overrideMimeType(overrideMimeType); } xhr.open(method, url, true); if (defined(headers)) { for (var key in headers) { if (headers.hasOwnProperty(key)) { xhr.setRequestHeader(key, headers[key]); } } } if (defined(responseType)) { xhr.responseType = responseType; } xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { if (defined(xhr.response)) { deferred.resolve(xhr.response); } else { // busted old browsers. if (defined(xhr.responseXML) && xhr.responseXML.hasChildNodes()) { deferred.resolve(xhr.responseXML); } else if (defined(xhr.responseText)) { deferred.resolve(xhr.responseText); } else { deferred.reject(new RuntimeError('unknown XMLHttpRequest response type.')); } } } else { deferred.reject(new RequestErrorEvent(xhr.status, xhr.response, xhr.getAllResponseHeaders())); } }; xhr.onerror = function (e) { deferred.reject(new RequestErrorEvent()); }; xhr.send(data); }; loadWithXhr.defaultLoad = loadWithXhr.load; PubSub.publishSync('map3D.DEMTileLayer.addEvent', { name: 'loadWithXhr', func: loadWithXhr }); }(window, document)); ; (function(window, document, undefined) { PubSub.subscribe('map23D.circle.add', add2Dcircle); PubSub.subscribe('map23D.circle.remove', remove2Dcircle); PubSub.subscribe('map23D.circle.update', update2Dcircle); PubSub.subscribe('map23D.circle.show', show2Dcircle); PubSub.subscribe('map23D.circle.hide', hide2Dcircle); PubSub.subscribe('map2D.circle.add', add2Dcircle); PubSub.subscribe('map2D.circle.remove', remove2Dcircle); PubSub.subscribe('map2D.circle.update', update2Dcircle); PubSub.subscribe('map2D.circle.show', show2Dcircle); PubSub.subscribe('map2D.circle.hide', hide2Dcircle); function add2Dcircle(msg, guid) { if (!map2DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '3D') { return false; } var circle = L.circle( map23DUtil.latLngsToReverse(circleData.geojson.geometry.coordinates), circleData.geojson.properties.radius,{ color: circleData.geojson.properties.color, weight: circleData.geojson.properties.weight, fillColor: circleData.geojson.properties.fillColor, opacity: circleData.geojson.properties.opacity, fillOpacity: circleData.geojson.properties.fillOpacity, title: circleData.geojson.properties.title } ) circle.guid = guid; if (circleData.geojson.properties.popupContent) { circle.bindPopup(circleData.geojson.properties.popupContent) } if (circleData.groupId) { circle.addTo(map2DViewer.groups[circleData.groupId]); } else { circle.addTo(map2DViewer.map); } map2DViewer.circles[guid] = circle; circleData.add2D = true; circleData.visible2D = true; }; function show2Dcircle(msg, guid) { if (!map2DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '3D') { return false; } if(circleData.visible2D){ return false; } if (circleData.groupId) { map2DViewer.circles[guid].addTo(map2DViewer.groups[circleData.groupId]); } else { map2DViewer.circles[guid].addTo(map2DViewer.map); } circleData.visible2D = true; }; function hide2Dcircle(msg, guid) { if (!map2DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '3D') { return false; } if(!circleData.visible2D){ return false; } if (circleData.groupId) { map2DViewer.groups[circleData.groupId].removeLayer(map2DViewer.circles[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.circles[guid]); } circleData.visible2D = false; }; function remove2Dcircle(msg, guid) { if (!map2DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '3D') { return false; } if (circleData.groupId) { map2DViewer.groups[circleData.groupId].removeLayer(map2DViewer.circles[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.circles[guid]); } delete map2DViewer.circles[guid]; circleData.add2D = false; }; function update2Dcircle(msg, guid) { if (!map2DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '3D') { return false; } map2DViewer.circles[guid].setStyle( circleData.geojson.properties ); if (circleData.geojson.properties.popupContent) { map2DViewer.circles[guid].bindPopup(circleData.geojson.properties.popupContent) } if(circleData.geojson.hasOwnProperty('geometry')){ map2DViewer.circles[guid].setLatLng(map23DUtil.latLngsToReverse(circleData.geojson.geometry.coordinates)); map2DViewer.circles[guid].setRadius(circleData.geojson.properties.radius); } }; }(window, document)); ; (function(window, document, undefined) { PubSub.subscribe('map2D.circleMarker.add', add2DcircleMarker); PubSub.subscribe('map2D.circleMarker.remove', remove2DcircleMarker); PubSub.subscribe('map2D.circleMarker.update', update2DcircleMarker); PubSub.subscribe('map2D.circleMarker.show', show2DcircleMarker); PubSub.subscribe('map2D.circleMarker.hide', hide2DcircleMarker); function add2DcircleMarker(msg, guid) { if (!map2DViewer.inited) { return false; } var circleMarkerData = map23DData.circleMarkers[guid]; if (circleMarkerData.from === '3D') { return false; } var circleMarker = L.circleMarker( map23DUtil.latLngsToReverse(circleMarkerData.geojson.geometry.coordinates),{ radius: circleMarkerData.geojson.properties.radius, color: circleMarkerData.geojson.properties.color, weight: circleMarkerData.geojson.properties.weight, fillColor: circleMarkerData.geojson.properties.fillColor, opacity: circleMarkerData.geojson.properties.opacity, fillOpacity: circleMarkerData.geojson.properties.fillOpacity, title: circleMarkerData.geojson.properties.title } ) circleMarker.guid = guid; if (circleMarkerData.geojson.properties.popupContent) { circleMarker.bindPopup(circleMarkerData.geojson.properties.popupContent) } if (circleMarkerData.groupId) { circleMarker.addTo(map2DViewer.groups[circleMarkerData.groupId]); } else { circleMarker.addTo(map2DViewer.map); } map2DViewer.circleMarkers[guid] = circleMarker; circleMarkerData.add2D = true; circleMarkerData.visible2D = true; }; function show2DcircleMarker(msg, guid) { if (!map2DViewer.inited) { return false; } var circleMarkerData = map23DData.circleMarkers[guid]; if (circleMarkerData.from === '3D') { return false; } if(circleMarkerData.visible2D){ return false; } if (circleMarkerData.groupId) { map2DViewer.circleMarkers[guid].addTo(map2DViewer.groups[circleMarkerData.groupId]); } else { map2DViewer.circleMarkers[guid].addTo(map2DViewer.map); } circleMarkerData.visible2D = true; }; function hide2DcircleMarker(msg, guid) { if (!map2DViewer.inited) { return false; } var circleMarkerData = map23DData.circleMarkers[guid]; if (circleMarkerData.from === '3D') { return false; } if(!circleMarkerData.visible2D){ return false; } if (circleMarkerData.groupId) { map2DViewer.groups[circleMarkerData.groupId].removeLayer(map2DViewer.circleMarkers[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.circleMarkers[guid]); } circleMarkerData.visible2D = false; }; function remove2DcircleMarker(msg, guid) { if (!map2DViewer.inited) { return false; } var circleMarkerData = map23DData.circleMarkers[guid]; if (circleMarkerData.from === '3D') { return false; } if (circleMarkerData.groupId) { map2DViewer.groups[circleMarkerData.groupId].removeLayer(map2DViewer.circleMarkers[guid]); } else { map2DViewer.map.removeLayer(map2DViewer.circleMarkers[guid]); } delete map2DViewer.circleMarkers[guid]; circleMarkerData.add2D = false; }; function update2DcircleMarker(msg, guid) { if (!map2DViewer.inited) { return false; } var circleMarkerData = map23DData.circleMarkers[guid]; if (circleMarkerData.from === '3D') { return false; } map2DViewer.circleMarkers[guid].setStyle( circleMarkerData.geojson.properties ); if (circleMarkerData.geojson.properties.popupContent) { circleMarker.bindPopup(circleMarkerData.geojson.properties.popupContent) } if(circleMarkerData.geojson.hasOwnProperty('geometry')){ map2DViewer.circleMarkers[guid].setLatLng(map23DUtil.latLngsToReverse(circleMarkerData.geojson.geometry.coordinates)); map2DViewer.circleMarkers[guid].setRadius(circleMarkerData.geojson.properties.radius); } }; }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map23D.circle.add', add3DCircle); PubSub.subscribe('map23D.circle.update', update3DCircle); PubSub.subscribe('map23D.circle.remove', remove3DCircle); PubSub.subscribe('map23D.circle.show', show3DCircle); PubSub.subscribe('map23D.circle.hide', hide3DCircle); PubSub.subscribe('map3D.circle.add', add3DCircle); PubSub.subscribe('map3D.circle.update', update3DCircle); PubSub.subscribe('map3D.circle.remove', remove3DCircle); PubSub.subscribe('map3D.circle.show', show3DCircle); PubSub.subscribe('map3D.circle.hide', hide3DCircle); function add3DCircle(msg, guid) { if (!map3DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '2D') { return false; } var properties = circleData.geojson.properties; var geometry = circleData.geojson.geometry; if (properties.altitudeMode == 0 || !properties.altitudeMode) { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1]); } else { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1], properties.altitude); } if (!properties.title) { var name = '' } else { var name = properties.title.toString() || '' } if (!properties.height || properties.height == 0) properties.height = 1 if (!properties.extrudedHeight || properties.extrudedHeight == 0) properties.extrudedHeight = 0 if (properties.weight > 0 || !properties.weight.toString()) { var outlineJudge = true; } else { var outlineJudge = false; } var ellipse = map3DViewer.map.entities.add({ id: guid, name: name, position: position, ellipse: { show: true, semiMinorAxis: properties.radius, // 长半轴 semiMajorAxis: properties.radius, // 短半轴 height: properties.height, // 距地面高度,默认为0,贴地 extrudedHeight: properties.extrudedHeight, // 高度,默认为0 fill: true, // 是否用材质填充 material: Cesium.Color.fromCssColorString(properties.fillColor).withAlpha(properties.fillOpacity), // 填充色 outline: outlineJudge, // 外边线 outlineColor: Cesium.Color.fromCssColorString(properties.color), // 外边线颜色 outlineWidth: properties.weight //外边线宽度 } }); delete circleData.action; map3DViewer.circles[guid] = ellipse; if (circleData.groupId) { map3DViewer.groups[circleData.groupId].add(ellipse); } circleData.add3D = true; circleData.visible3D = true; }; function remove3DCircle(msg, guid) { if (!map3DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '2D') { return false; } if (!map3DViewer.circles[guid]) { return false; } var circle = map3DViewer.circles[guid]; map3DViewer.map.entities.remove(circle); if (circleData.groupId) { map3DViewer.groups[circleData.groupId].remove(circle) } delete map3DViewer.circles[guid]; circleData.add3D = false; }; function update3DCircle(msg, guid) { if (!map3DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '2D') { return false; } if (!map3DViewer.circles[guid]) { return false; } var properties = circleData.geojson.properties; var geometry = circleData.geojson.geometry; if (geometry) { var altitude = properties.altitude || circleData.geojson.properties.altitude; if (properties.altitudeMode == 0 || !properties.altitudeMode) { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1]); } else { var position = Cesium.Cartesian3.fromDegrees(geometry.coordinates[0], geometry.coordinates[1], properties.altitude); } map3DViewer.circles[guid].position = position; } if (!properties.height || properties.height == 0) properties.height = 0 if (!properties.extrudedHeight || properties.extrudedHeight == 0) properties.extrudedHeight = 0 if (properties.weight > 0 || !properties.weight.toString()) { var outlineJudge = true; } else { var outlineJudge = false; } var circle = map3DViewer.circles[guid].ellipse; circle.semiMinorAxis = properties.radius; circle.semiMajorAxis = properties.radius; circle.height = properties.height; circle.extrudedHeight = properties.extrudedHeight; circle.material = Cesium.Color.fromCssColorString(properties.fillColor).withAlpha(properties.fillOpacity); circle.outline = outlineJudge circle.outlineWidth = properties.weight; circle.outlineColor = Cesium.Color.fromCssColorString(properties.color).withAlpha(properties.opacity); delete circleData.action; } function show3DCircle(msg, guid) { if (!map3DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '2D') { return false; } if (circleData.visible3D) { return false; } if (!map3DViewer.circles[guid]) { return false; } var circle = map3DViewer.circles[guid]; circle.show = true; if (circleData.groupId) { map3DViewer.groups[circleData.groupId].getById(guid).show = true; } circleData.visible3D = true; }; function hide3DCircle(msg, guid) { if (!map3DViewer.inited) { return false; } var circleData = map23DData.circles[guid]; if (circleData.from === '2D') { return false; } if (!circleData.visible3D) { return false; } if (!map3DViewer.circles[guid]) { return false; } var circle = map3DViewer.circles[guid]; circle.show = false; if (circleData.groupId) { map3DViewer.groups[circleData.groupId].getById(guid).show = false; } circleData.visible3D = false; }; }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.model.add', addModel); PubSub.subscribe('map3D.model.update', updateModel); PubSub.subscribe('map3D.model.remove', removeModel); PubSub.subscribe('map3D.model.show', showModel); PubSub.subscribe('map3D.model.hide', hideModel); function addModel(msg, guid) { if (!map3DViewer.inited) { return false; } var modelData = map23DData.models[guid]; if (modelData.from === '2D') { return false; } var modelGeometry = modelData.geojson.geometry; var modelProperty = modelData.geojson.properties; if (modelProperty.anination) { var property = new Cesium.SampledPositionProperty(); for (var i = 0; i < modelGeometry.coordinates.length; i++) { var item = { longitude: JSON.parse(modelGeometry.coordinates[i][0]), dimension: JSON.parse(modelGeometry.coordinates[i][1]), height: modelProperty.altitude[i] || 0, time: modelGeometry.timeLine[i] - modelGeometry.timeLine[0] } var start = null if (i == 0) { start = Cesium.JulianDate.fromDate(modelGeometry.timeLine[i]) } var time = Cesium.JulianDate.addSeconds(start, item.time, new Cesium.JulianDate); var position = Cesium.Cartesian3.fromDegrees(item.longitude, item.dimension, item.height); // 添加位置,和时间对应 property.addSample(time, position); } var scale = modelProperty.scale || 1; var model = map3DViewer.map.entities.add({ // 和时间轴关联 availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: map3DViewer.map.clock.startTime, stop: map3DViewer.map.clock.stopTime })]), position: property, // 根据所提供的速度计算点 orientation: new Cesium.VelocityOrientationProperty(property), // 模型数据 model: { scale: scale, uri: modelProperty.url, minimumPixelSize: 128 }, path: { resolution: 1, material: new Cesium.PolylineGlowMaterialProperty({ glowPower: 0.1, color: Cesium.Color.fromCssColorString(modelProperty.pathColor) }), width: modelProperty.pathWidth } }); if (!modelProperty.path) { model.path.show = false; } } else { var height = modelProperty.altitude[0] || 0; var scale = modelProperty.scale || 1; var position = Cesium.Cartesian3.fromDegrees(modelGeometry.coordinates[0][0], modelGeometry.coordinates[0][1], height); var model = map3DViewer.map.entities.add({ position: position, model: { scale: scale, uri: modelProperty.url, minimumPixelSize: 128 } }); } delete modelData.action; map3DViewer.models[guid] = model; if (modelData.groupId) { map3DViewer.groups[modelData.groupId].add(model); } modelData.add3D = true; modelData.visible3D = true; }; function removeModel(msg, guid) { if (!map3DViewer.inited) { return false; } var modelData = map23DData.models[guid]; if (modelData.from === '2D') { return false; } if (!map3DViewer.models[guid]) { return false; } var model = map3DViewer.models[guid]; map3DViewer.map.entities.remove(model); if (modelData.groupId) { map3DViewer.groups[modelData.groupId].remove(model) } delete map3DViewer.models[guid]; modelData.add3D = false; }; function updateModel(msg, guid) { if (!map3DViewer.inited) { return false; } var modelData = map23DData.models[guid]; if (modelData.from === '2D') { return false; } if (!map3DViewer.models[guid]) { return false; } var model = map3DViewer.models[guid]; } function showModel(msg, guid) { if (!map3DViewer.inited) { return false; } var modelData = map23DData.models[guid]; if (modelData.from === '2D') { return false; } if (!map3DViewer.models[guid]) { return false; } var model = map3DViewer.models[guid]; model.show = true; if (modelData.groupId) { map3DViewer.groups[modelData.groupId].getById(guid).show = true } modelData.visible3D = true; } function hideModel(msg, guid) { if (!map3DViewer.inited) { return false; } var modelData = map23DData.models[guid]; if (modelData.from === '2D') { return false; } if (!map3DViewer.models[guid]) { return false; } var model = map3DViewer.models[guid]; model.show = false; if (modelData.groupId) { map3DViewer.groups[modelData.groupId].getById(guid).show = false } modelData.visible3D = false; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.measureArea.add', init); PubSub.subscribe('map3D.measureArea.remove', removeMeasureArea); PubSub.subscribe('map3D.measureArea.clear', clearMeasureArea); var modValue = { handler: null, tempPoints: [], viewer: null, tempEntities: {}, areaIndex: 0, area: null, polygon: {}, afterMeasureJudgeContinue: false, tips: $('
左键添加点,右键结束
') } function init(msg, options) { if (options.action == 'add') { modValue.viewer = options.viewer; modValue.afterMeasureJudgeContinue = options.afterMeasureJudgeContinue || false addMeasureArea(); modValue.tips.appendTo(modValue.viewer._container); } else if (options.action == 'remove') { removeMeasureArea(); } }; function addMeasureArea() { if (!modValue.handler) { modValue.tempPoints = []; modValue.areaIndex++; modValue.tempEntities[modValue.areaIndex] = []; modValue.handler = new Cesium.ScreenSpaceEventHandler(modValue.viewer.scene.canvas); modValue.handler.setInputAction(function (event) { var wp = event.endPosition; if (!Cesium.defined(wp)) { return; } var ray = modValue.viewer.camera.getPickRay(wp); if (!Cesium.defined(ray)) { return; } var cartesian = modValue.viewer.scene.globe.pick(ray, modValue.viewer.scene); if (!Cesium.defined(cartesian)) { return; } $('#' + modValue.viewer._container.id + ' .measureArea_tips').css({ "left": wp.x + 20, 'top': wp.y + 10 }) }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); modValue.handler.setInputAction(function (click) { var latlng = screenToLatLng(click.position.x, click.position.y) if (latlng) { modValue.tempPoints.push({ lon: latlng.lng, lat: latlng.lat, alt: latlng.alt }); var tempLength = modValue.tempPoints.length; drawPoint(modValue.tempPoints[modValue.tempPoints.length - 1]); if (tempLength > 2) { drawPoly(modValue.tempPoints); } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); modValue.handler.setInputAction(function (click) { var cartesian = modValue.viewer.camera.pickEllipsoid(click.position, modValue.viewer.scene.globe.ellipsoid); if (cartesian) { var tempLength = modValue.tempPoints.length; if (tempLength < 3) { alert('请选择3个以上的点再执行闭合操作命令'); } else { drawPoly(modValue.tempPoints); // highLightAssetsInArea(_this.modValue.tempPoints) var ent = modValue.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(modValue.tempPoints[modValue.tempPoints.length - 1].lon, modValue.tempPoints[modValue.tempPoints.length - 1].lat), label: { text: SphericalPolygonAreaMeters(modValue.tempPoints), font: '22px Helvetica', heightReference: 2, pixelOffset: new Cesium.Cartesian2(0, -22), fillColor: Cesium.Color.WHITE, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, } }); modValue.tempEntities[modValue.areaIndex].push(ent); modValue.tempPoints = []; removeMeasureArea('', modValue.afterMeasureJudgeContinue); } } }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); } } function removeMeasureArea(msg, callback) { if (!modValue.viewer) { return; } $('#' + modValue.viewer._container.id + ' .measureArea_tips').remove(); if (modValue.handler) { modValue.tempPoints = []; modValue.handler.destroy(); modValue.handler = null; } if (callback) { init('', { action: 'add', viewer: modValue.viewer }) } } function drawPoint(point) { var entity = modValue.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat), point: { pixelSize: 10, heightReference: 2, color: Cesium.Color.RED, } }); modValue.tempEntities[modValue.areaIndex].push(entity); } function drawPoly(points) { var pArray = []; for (var i = 0; i <= points.length; i++) { if (i < points.length) { pArray.push(points[i].lon); pArray.push(points[i].lat); pArray.push(points[i].alt); } } if (modValue.polygon[modValue.areaIndex]) { modValue.polygon[modValue.areaIndex].polygon.hierarchy.setValue(new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights(pArray))); } else { modValue.polygon[modValue.areaIndex] = modValue.viewer.entities.add({ polygon: { hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights(pArray)), heightReference: 0, //height : 5, material: Cesium.Color.CHARTREUSE.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.YELLOW, outlineWidth: 2 } }); modValue.tempEntities[modValue.areaIndex].push(modValue.polygon[modValue.areaIndex]); } } function SphericalPolygonAreaMeters(points) { var latLngs = points; var pointsCount = latLngs.length, area = 0.0, d2r = Math.PI / 180, p1, p2; if (pointsCount > 2) { for (var i = 0; i < pointsCount; i++) { p1 = latLngs[i]; p2 = latLngs[(i + 1) % pointsCount]; area += ((p2.lon - p1.lon) * d2r) * (2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r)); } area = area * 6378137.0 * 6378137.0 / 2.0; } area = Math.abs(area); if (area > 1000000) { area = (area * 0.000001).toFixed(2) + ' 平方公里'; } else { area = area.toFixed(2) + '平方米'; } return area; } function screenToLatLng(x, y) { var pick1 = new Cesium.Cartesian2(x, y); var cartesian = modValue.viewer.scene.globe.pick(modValue.viewer.camera.getPickRay(pick1), modValue.viewer.scene); if (cartesian) { var cartographic = modValue.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } } else { var position = false } return position; } function clearMeasureArea(msg, options) { $.each(modValue.tempEntities, function (i, t) { for (var j = 0; j < t.length; j++) { modValue.viewer.entities.removeById(t[j]._id); } }) } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.measureDistance.add', init); PubSub.subscribe('map3D.measureDistance.remove', removeMeasureDistance); PubSub.subscribe('map3D.measureDistance.clear', clearMeasureDistance); var modValue = { handler: null, tempPoints: [], viewer: null, tempEntities: {}, distanceIndex: 0, distance: null, afterMeasureJudgeContinue: false, tips: $('
左键添加点,右键结束
') } function init(msg, options) { if (options.action == 'add') { modValue.viewer = options.viewer; modValue.afterMeasureJudgeContinue = options.afterMeasureJudgeContinue || false addMeasureDistance(); modValue.tips.appendTo(modValue.viewer._container); } else if (options.action == 'remove') { removeMeasureDistance(); } }; function addMeasureDistance() { if (!modValue.handler) { modValue.distanceIndex++; modValue.distance = null; modValue.tempEntities[modValue.distanceIndex] = []; modValue.handler = new Cesium.ScreenSpaceEventHandler(modValue.viewer.scene.canvas); modValue.handler.setInputAction(function (event) { var wp = event.endPosition; if (!Cesium.defined(wp)) { return; } var ray = modValue.viewer.camera.getPickRay(wp); if (!Cesium.defined(ray)) { return; } var cartesian = modValue.viewer.scene.globe.pick(ray, modValue.viewer.scene); if (!Cesium.defined(cartesian)) { return; } $('#' + modValue.viewer._container.id + ' .measureDistance_tips').css({ "left": wp.x + 20, 'top': wp.y + 10 }) }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); modValue.handler.setInputAction(function (click) { var latlng = screenToLatLng(click.position.x, click.position.y) if (latlng) { modValue.tempPoints.push({ lon: latlng.lng, lat: latlng.lat }); var tempLength = modValue.tempPoints.length; drawPoint(modValue.tempPoints[modValue.tempPoints.length - 1]); if (tempLength > 1) { drawLine(modValue.tempPoints[modValue.tempPoints.length - 2], modValue.tempPoints[modValue.tempPoints.length - 1], true); } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); modValue.handler.setInputAction(function (click) { removeMeasureDistance('', modValue.afterMeasureJudgeContinue); }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); } } function removeMeasureDistance(msg, callback) { if (!modValue.viewer) { return; } $('#' + modValue.viewer._container.id + ' .measureDistance_tips').remove(); if (modValue.handler) { modValue.tempPoints = []; modValue.handler.destroy(); modValue.handler = null; } if (callback) { init('', { action: 'add', viewer: modValue.viewer }) } } function drawLine(point1, point2, showDistance) { var entity = modValue.viewer.entities.add({ polyline: { positions: [Cesium.Cartesian3.fromDegrees(point1.lon, point1.lat), Cesium.Cartesian3.fromDegrees(point2.lon, point2.lat)], width: 10.0, material: new Cesium.PolylineGlowMaterialProperty({ color: Cesium.Color.CHARTREUSE.withAlpha(.5) }), clampToGround: true } }); modValue.tempEntities[modValue.distanceIndex].push(entity); if (showDistance) { var curdistance = getFlatternDistance(point1.lat, point1.lon, point2.lat, point2.lon); if (modValue.distance) { modValue.distance = modValue.distance + curdistance } else { modValue.distance = curdistance; } if (modValue.distance <= 1000) { var showDistance = modValue.distance.toFixed(1) + 'm'; } else { var showDistance = (modValue.distance / 1000).toFixed(3) + 'km'; } entity = modValue.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(point2.lon, point2.lat), label: { text: showDistance, heightReference: 2, font: '22px Helvetica', fillColor: Cesium.Color.WHITE, pixelOffset: new Cesium.Cartesian2(0, -22), verticalOrigin: Cesium.VerticalOrigin.BOTTOM, } }); modValue.tempEntities[modValue.distanceIndex].push(entity); } } function drawPoint(point) { var entity = modValue.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat), point: { pixelSize: 10, heightReference: 2, color: Cesium.Color.RED, } }); modValue.tempEntities[modValue.distanceIndex].push(entity); } function getFlatternDistance(lat1, lng1, lat2, lng2) { var EARTH_RADIUS = 6378137.0; //单位M var PI = Math.PI; function getRad(d) { return d * PI / 180.0; } var f = getRad((lat1 + lat2) / 2); var g = getRad((lat1 - lat2) / 2); var l = getRad((lng1 - lng2) / 2); var sg = Math.sin(g); var sl = Math.sin(l); var sf = Math.sin(f); var s, c, w, r, d, h1, h2; var a = EARTH_RADIUS; var fl = 1 / 298.257; sg = sg * sg; sl = sl * sl; sf = sf * sf; s = sg * (1 - sl) + (1 - sf) * sl; c = (1 - sg) * (1 - sl) + sf * sl; w = Math.atan(Math.sqrt(s / c)); r = Math.sqrt(s * c) / w; d = 2 * w * a; h1 = (3 * r - 1) / 2 / c; h2 = (3 * r + 1) / 2 / s; return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg)); } function screenToLatLng(x, y) { var pick1 = new Cesium.Cartesian2(x, y); var cartesian = modValue.viewer.scene.globe.pick(modValue.viewer.camera.getPickRay(pick1), modValue.viewer.scene); if (cartesian) { var cartographic = modValue.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } } else { var position = false } return position; } function clearMeasureDistance(msg, options) { $.each(modValue.tempEntities, function (i, t) { for (var j = 0; j < t.length; j++) { modValue.viewer.entities.removeById(t[j]._id); } }) } }(window, document)); ; (function (window, document, undefined) { map3DViewer.measureHeight = function (options) { var defaultData = { action: options.action, viewer: map3DViewer.map, } defaultData = Object.assign({}, defaultData, options) switch (defaultData.action) { case 'add': if (!this.distanceTool) { this.distanceTool = new measure3DHeight(defaultData) } this.distanceTool.start(); return this.distanceTool; break; case 'remove': if (!this.distanceTool) break; this.distanceTool.remove(); break; case 'clear': if (!this.distanceTool) break; this.distanceTool.clear(); break; case 'stop': if (!this.distanceTool) break; this.distanceTool.stop(); break; case 'restart': if (!this.distanceTool) break; this.distanceTool.remove(); this.distanceTool.start(); } } function measure3DHeight(options) { this.init.apply(this, arguments); } measure3DHeight.prototype = { init: function (options) { this.measure_entities = new Cesium.Entity({ id: 'name_tile', show: true }) this.viewer = options.viewer; this.handler = null; this.finished = true; this.removed = false; this.index = 0; this.tempEntities = {}; this.popupArr = {}; this.afterMeasureJudgeContinue = (typeof options.afterMeasureJudgeContinue == "boolean") ? options.afterMeasureJudgeContinue : false; this.buttonClass = "measureTips measureHeight" }, start: function () { var that = this; this.depthTestAgainstTerrain = null; this.depthTestAgainstTerrain = this.viewer.scene.globe.depthTestAgainstTerrain this.viewer.scene.globe.depthTestAgainstTerrain = true; if (!this.handler) { this.index++; this.tempEntities[this.index] = { zhixian: null, gengxin: null, floatingPoint_g: null, }; this.popupArr[this.index] = {} this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); var positions = []; var height = 0; var cartesian = null; this.handler.setInputAction(function (movement) { that.finished = false cartesian = that.viewer.scene.pickPosition(movement.position); if (positions.length == 0) { positions.push(cartesian.clone()); that.tempEntities[that.index].floatingPoint_g = that.viewer.entities.add({ parent: that.measure_entities, name: '高度', position: positions[0], point: { pixelSize: 5, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, heightReference: Cesium.HeightReference.none } }); that.stopCamereChange(); } else { positions.push(cartesian); height = that.getHeight(positions); that.buildPolylineAndPoint(positions, height); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } }, stopCamereChange: function () { this.viewer.scene.screenSpaceCameraController.enableTilt = false; this.viewer.scene.screenSpaceCameraController.enableRotate = false; this.viewer.scene.screenSpaceCameraController.enableZoom = false; }, startCamereChange: function () { this.viewer.scene.screenSpaceCameraController.enableTilt = true; this.viewer.scene.screenSpaceCameraController.enableRotate = true; this.viewer.scene.screenSpaceCameraController.enableZoom = true; }, getHeight: function (position) { var cartographic = Cesium.Cartographic.fromCartesian(position[0]); var cartographic1 = Cesium.Cartographic.fromCartesian(position[1]); var height_temp = cartographic1.height - cartographic.height; return height_temp.toFixed(2); }, buildPolylineAndPoint: function (positions, height) { var that = this; var endPoint = positions[1].clone(); if (height < 0) { height = -1 * height; var mid = positions[0]; positions[0] = positions[1]; positions[1] = mid; } var textDisance = height + "米"; var point1cartographic = Cesium.Cartographic.fromCartesian(positions[0]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[1]); var point_temp = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(point1cartographic.longitude), Cesium.Math.toDegrees(point1cartographic.latitude), point2cartographic.height); var temp_position = []; temp_position.push(positions[0]); temp_position.push(point_temp); //添加高程点和label信息 this.tempEntities[this.index].zhixian = this.viewer.entities.add({ parent: this.measure_entities, name: '直线距离', position: point_temp, point: { pixelSize: 5, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, heightReference: Cesium.HeightReference.none }, label: { text: textDisance, font: '18px sans-serif', fillColor: Cesium.Color.GOLD, style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineWidth: 2, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, pixelOffset: new Cesium.Cartesian2(20, -20) }, polyline: { show: true, positions: temp_position, material: Cesium.Color.AQUA, width: 2 } }); //添加圆和高程线 this.tempEntities[this.index].gengxin = this.viewer.entities.add({ parent: this.measure_entities, name: '直线距离', position: endPoint, point: { pixelSize: 5, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2, heightReference: Cesium.HeightReference.none }, polyline: { show: true, positions: [point_temp, positions[1]], material: Cesium.Color.AQUA, width: 2 } }) var divEle = that.createdDiv("删除", { params: { index: this.index }, onclick: function () { var params = JSON.parse(this.getAttribute("params")) that.del(params.index) } }) // that.popupArr[that.index] = map3DViewer.setPopup({ // viewer: that.viewer, // cartesian: positions[1], // show: true, // offset: [10, -14.5], // html: divEle // }) this.finished = true; this.detach(this.afterMeasureJudgeContinue) this.startCamereChange() }, createdDiv: function (text, eventObj) { //创建一个div var div = document.createElement("div"); //为div创建属性class = "test" var divattr = document.createAttribute("class"); divattr.value = this.buttonClass; div.setAttributeNode(divattr); var divParams = document.createAttribute("params"); divParams.value = JSON.stringify(eventObj.params) div.setAttributeNode(divParams); //为div添加样式 var style = document.createAttribute("style"); div.setAttributeNode(style); div.style.backgroundColor = "#ffffff"; div.style.cursor = "pointer"; //创建一hello,world个文本节点 var text = document.createTextNode(text); div.appendChild(text); div.onclick = eventObj.onclick; return div; }, remove: function () { this.stop(); this.clear(); }, stop: function () { this.removed = true if (!this.finished) { this.del(this.index) this.finished = true; } this.detach(); this.startCamereChange() }, detach: function (judge) { if (this.handler) { this.handler.destroy(); this.handler = null; } this.viewer.scene.globe.depthTestAgainstTerrain = this.depthTestAgainstTerrain if (judge) { this.start() } }, clear: function () { var items = this.tempEntities for (var key1 in items) { if (items.hasOwnProperty(key1)) { if (items[key1].zhixian) this.viewer.entities.remove(items[key1].zhixian); if (items[key1].gengxin) this.viewer.entities.remove(items[key1].gengxin); if (items[key1].floatingPoint_g) this.viewer.entities.remove(items[key1].floatingPoint_g); } } this.tempEntities = {} var items_popup = this.popupArr for (var key2 in items_popup) { if (items_popup.hasOwnProperty(key2)) { if (Object.getOwnPropertyNames(items_popup[key2]).length != 0) { items_popup[key2].close(); } } } this.popupArr = {} }, del: function (index) { var item = this.tempEntities[index] if (item.zhixian) this.viewer.entities.remove(item.zhixian); if (item.gengxin) this.viewer.entities.remove(item.gengxin); if (item.floatingPoint_g) this.viewer.entities.remove(item.floatingPoint_g); item.zhixian = null item.gengxin = null item.floatingPoint_g = null if (Object.getOwnPropertyNames(this.popupArr).length > 0) { var popup = this.popupArr[index] if (Object.getOwnPropertyNames(popup).length != 0) { popup.close(); delete popup } } delete item }, } }(window, document)); function drawPoint_Ceisum() { this.init.apply(this, arguments) } drawPoint_Ceisum.prototype = { viewer: null, handler: null, callback: null, init: function (params) { this.viewer = params.viewer; this.callback = params.callback; }, start: function () { var _this = this; if (!this.handler) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); this.handler.setInputAction(function (click) { var pick1 = new Cesium.Cartesian2(click.position.x, click.position.y); var cartesian = _this.viewer.scene.globe.pick(_this.viewer.camera.getPickRay(pick1), _this.viewer.scene); if (cartesian) { var cartographic = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; if (_this.callback) _this.callback({ lon: lng, lat: lat }); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, stop: function () { if (this.handler) this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); this.handler = null }, } map3DViewer.setDrawPoint = function (options) { return (function () { var defaultData = { action: 'add', viewer: null, callback: null, } defaultData = Object.assign({}, defaultData, options) switch (defaultData.action) { case 'add': this.drawPoint = new drawPoint_Ceisum(defaultData) this.drawPoint.start(); return this; break; case 'remove': this.drawPoint.stop(); delete this.drawPoint break; } })() } function drawPolyline_Ceisum() { this.init.apply(this, arguments) } drawPolyline_Ceisum.prototype = { viewer: null, handler: null, callback: null, tempPoints: [], tempEntitiesPoints: [], tempEntitiesLines: [], completeBotton: '
完成
', init: function (params) { this.viewer = params.viewer; this.callback = params.callback; this.completeBotton = params.completeBotton || this.completeBotton; }, start: function () { var _this = this; if (!this.handler) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); this.handler.setInputAction(function (click) { var pick1 = new Cesium.Cartesian2(click.position.x, click.position.y); var cartesian = _this.viewer.scene.globe.pick(_this.viewer.camera.getPickRay(pick1), _this.viewer.scene); if (cartesian) { var cartographic = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); _this.tempPoints.push({ lng: lng, lat: lat }); var tempLength = _this.tempPoints.length; _this.drawPoint(); if (tempLength > 1) { _this.drawLine(); if (!_this.popup) { _this.popup = new map3DViewer.setPopup({ viewer: _this.viewer, cartesian: Cesium.Cartesian3.fromDegrees(lng, lat), show: true, offset: [10, -14.5], html: _this.completeBotton }) } else { _this.popup.refreshRender({ cartesian: Cesium.Cartesian3.fromDegrees(lng, lat), html: _this.completeBotton }) } } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, drawPoint: function () { var a = this.tempPoints[this.tempPoints.length - 1] var entity = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(a.lng, a.lat), point: { pixelSize: 10, heightReference: 2, color: Cesium.Color.RED, } }); this.tempEntitiesPoints.push(entity); }, drawLine: function (a, b) { var a = this.tempPoints[this.tempPoints.length - 2] var b = this.tempPoints[this.tempPoints.length - 1] var entity = this.viewer.entities.add({ polyline: { clampToGround: true, positions: Cesium.Cartesian3.fromDegreesArray([a.lng, a.lat, b.lng, b.lat]), width: 10.0, material: new Cesium.PolylineGlowMaterialProperty({ color: Cesium.Color.CHARTREUSE.withAlpha(.5) }), clampToGround: true } }); this.tempEntitiesLines.push(entity); }, finish: function () { this.callback(JSON.parse(JSON.stringify(this.tempPoints))) this.clear() }, clear: function () { var _this = this $.each(this.tempEntitiesPoints, function (i, t) { _this.viewer.entities.removeById(t._id); }) $.each(this.tempEntitiesLines, function (i, t) { _this.viewer.entities.removeById(t._id); }) this.tempPoints.length = 0 this.tempEntitiesPoints.length = 0 this.tempEntitiesLines.length = 0 this.popup.close(); delete this.popup; }, stop: function () { if (this.handler) this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); this.handler = null }, } map3DViewer.setDrawPolyline = function (options) { return (function () { var defaultData = { action: 'add', viewer: null, callback: null, } defaultData = Object.assign({}, defaultData, options) switch (defaultData.action) { case 'add': this.drawPolyline = new drawPolyline_Ceisum(defaultData) this.drawPolyline.start(); return this; break; case 'finish': this.drawPolyline.finish(); break; case 'remove': this.drawPolyline.stop(); delete this.drawPolyline break; } })() } function drawPolygon_Ceisum() { this.init.apply(this, arguments) } drawPolygon_Ceisum.prototype = { viewer: null, handler: null, callback: null, tempPoints: [], tempEntitiesPoints: [], tempEntityPolyline: null, tempEntityPolygon: null, completeBotton: '
完成
', init: function (params) { this.viewer = params.viewer; this.callback = params.callback; this.completeBotton = params.completeBotton || this.completeBotton }, start: function () { var _this = this; if (!this.handler) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); this.handler.setInputAction(function (click) { var pick1 = new Cesium.Cartesian2(click.position.x, click.position.y); var cartesian = _this.viewer.scene.globe.pick(_this.viewer.camera.getPickRay(pick1), _this.viewer.scene); if (cartesian) { var cartographic = _this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); _this.tempPoints.push({ lng: lng, lat: lat }); _this.drawPoint(); if (_this.tempPoints.length == 2) { _this.drawPolyline(); } else if (_this.tempPoints.length > 2) { if (_this.tempEntityPolyline) { _this.viewer.entities.removeById(_this.tempEntityPolyline._id) _this.tempEntityPolyline = null; } _this.drawPolygon(); } if (!_this.popup) { _this.popup = new Popup({ viewer: _this.viewer, cartesian: Cesium.Cartesian3.fromDegrees(lng, lat), show: true, offset: [10, -14.5], html: _this.completeBotton }) } else { _this.popup.refreshRender({ cartesian: Cesium.Cartesian3.fromDegrees(lng, lat), html: _this.completeBotton }) } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); }, drawPoint: function () { var a = this.tempPoints[this.tempPoints.length - 1]; var entity = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(a.lng, a.lat), point: { pixelSize: 10, heightReference: 2, color: Cesium.Color.RED, } }); this.tempEntitiesPoints.push(entity); }, drawPolyline: function () { var pArray = this.tempPoints.map(function (item, index, array) { return [item.lng, item.lat] }) pArray = pArray.reduce(function (a, b) { return a.concat(b) }) var entity = this.viewer.entities.add({ polyline: { clampToGround: true, positions: Cesium.Cartesian3.fromDegreesArray(pArray), width: 10.0, material: new Cesium.PolylineGlowMaterialProperty({ color: Cesium.Color.CHARTREUSE.withAlpha(.5) }), clampToGround: true } }); this.tempEntityPolyline = entity }, drawPolygon: function () { var pArray = this.tempPoints.map(function (item, index, array) { return [item.lng, item.lat] }) pArray = pArray.reduce(function (a, b) { return a.concat(b) }) if (this.tempEntityPolygon) { this.tempEntityPolygon.polygon.hierarchy.setValue(new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(pArray))); } else { var entity = this.viewer.entities.add({ polygon: { hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(pArray)), heightReference: 0, //height : 5, material: Cesium.Color.CHARTREUSE.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.YELLOW, outlineWidth: 2 } }); this.tempEntityPolygon = entity; } }, finish: function () { this.callback(JSON.parse(JSON.stringify(this.tempPoints))) this.clear() }, clear: function () { var _this = this $.each(this.tempEntitiesPoints, function (i, t) { _this.viewer.entities.removeById(t._id); }) if (_this.tempEntityPolyline) _this.viewer.entities.removeById(_this.tempEntityPolyline._id) _this.tempEntityPolyline = null; if (_this.tempEntityPolygon) _this.viewer.entities.removeById(_this.tempEntityPolygon._id) _this.tempEntityPolygon = null; this.tempPoints = [] this.tempEntitiesPoints = [] this.tempEntityPolyline = null this.tempEntityPolygon = null this.popup.close(); delete this.popup; }, stop: function () { if (this.handler) this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); this.handler = null }, } map3DViewer.setDrawPolygon = function (options) { return (function () { var defaultData = { action: 'add', viewer: null, callback: null, } defaultData = Object.assign({}, defaultData, options) switch (defaultData.action) { case 'add': this.drawPolygon = new drawPolygon_Ceisum(defaultData) this.drawPolygon.start(); return this; break; case 'finish': this.drawPolygon.finish(); break; case 'remove': this.drawPolygon.stop(); delete this.drawPolygon break; } })() } ; (function (window, document, undefined) { PubSub.subscribe('map3D.flightSimulation.add', init); PubSub.subscribe('map3D.flightSimulation.changeView', changeView); PubSub.subscribe('map3D.flightSimulation.remove', remove); var flightSimulation = map23DControl.flightSimulation; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = flightSimulation; } else if (typeof define === 'function' && define.amd) { define(flightSimulation); } // 模拟飞行 map3DViewer.flightSimulation = function (options) { switch (options.action) { case 'add': return init(options); break; case 'changeView': return changeView(options); break; case 'resetCondition': return resetCondition(options); break; case 'remove': return remove(options); break; } } var modValue = {} function reset(options) { var obj = { minPitch: -Cesium.Math.PI_OVER_TWO, maxPitch: -0.175, scale: 1, minHeight: 200, tangle: [] } modValue = Object.assign({}, modValue, obj, options) //获取屏幕最下方中部像素坐标 modValue.wx = window.innerWidth; modValue.wy = window.innerWidth; modValue.wx = modValue.wx / 2; modValue.wy = modValue.wy / 2; modValue.hpRoll = new Cesium.HeadingPitchRoll(); modValue.speedVector = new Cesium.Cartesian3(); modValue.deltaRadians = Cesium.Math.toRadians(3.0); modValue.fixedFrameTransform = Cesium.Transforms.localFrameToFixedFrameGenerator( "north", "west" ); if (modValue.daqiaoModel) { modValue.viewer.entities.removeById(modValue.daqiaoModel._id) } modValue.daqiaoModel = null if (modValue.moniPolyline) { modValue.viewer.entities.removeById(modValue.moniPolyline._id) } modValue.moniPolyline = null; modValue.viewer.clock.onTick.removeEventListener(event1) modValue.viewer.clock.onTick.removeEventListener(event2) } function init(params) { delete params.action var options = Object.assign({}, { viewer: map3DViewer.map }, params); modValue = {} modValue.viewer = options.viewer reset(options) modValue.eyeslook = options.eyeslook || "god" modValue.height = options.height || 5000 modValue.speed = options.speed || 200 modValue.lineCoor = options.lineCoor modValue.callback = options.callback || null; modValue.showLine = typeof options.showLine == "boolean" ? options.showLine : false; modValue.position = Cesium.Cartesian3.fromDegrees(modValue.lineCoor[0][0], modValue.lineCoor[0][1], options.height); modValue.lineTurf = turf.lineString(modValue.lineCoor); var cline = []; for (var i = 0; i < modValue.lineCoor.length; i++) { cline.push(modValue.lineCoor[i][0]); cline.push(modValue.lineCoor[i][1]); cline.push(modValue.height); } modValue.lineColor = options.lineColor || '#00ffcc' modValue.outlineColor = options.outlineColor || '#FFFFFF' if (!Cesium.Color.fromCssColorString(modValue.lineColor)) throw "lineColor has wrong format" if (!Cesium.Color.fromCssColorString(modValue.outlineColor)) throw "outlineColor has wrong format" var color = Cesium.Color.fromCssColorString(modValue.lineColor) || Cesium.Color.fromCssColorString('#00ffcc') var outlineColor = Cesium.Color.fromCssColorString(modValue.outlineColor) || Cesium.Color.fromCssColorString('#FFFFFF') var positionline = Cesium.Cartesian3.fromDegreesArrayHeights(cline); modValue.moniPolyline = modValue.viewer.entities.add({ name: '模拟飞行线', polyline: { show: modValue.showLine, clampToGround: false, positions: positionline, width: 3, material: new Cesium.PolylineOutlineMaterialProperty({ color: color, outlineWidth: 0, outlineColor: outlineColor }) } }); modValue.daqiaoModel = modValue.viewer.entities.add({ position: modValue.position, orientation: Cesium.Transforms.headingPitchRollQuaternion( modValue.position, modValue.hpRoll ), model: { show: true, uri: options.modelUrl, minimumPixelSize: 150, scale: modValue.scale }, }); if (options.entity) modValue.daqiaoModel = options.entity modValue.viewer.clock.onTick.addEventListener(event1) modValue.viewer.clock.onTick.addEventListener(event2) calculationEveryLineNorthPoint(); return modValue.daqiaoModel } function changeView(options) { delete options.action if (!options.eyeslook) throw "eyeslook is undefined!" if (!modValue.daqiaoModel) throw "Flight simulation is not initialized!" modValue.eyeslook = options.eyeslook if (modValue.eyeslook == "one") { modValue.daqiaoModel.model.show = false; } else { modValue.daqiaoModel.model.show = true; } } function remove() { if (!modValue.viewer) return if (modValue.daqiaoModel) { modValue.viewer.entities.remove(modValue.daqiaoModel) } modValue.daqiaoModel = null if (modValue.moniPolyline) { modValue.viewer.entities.remove(modValue.moniPolyline) } modValue.moniPolyline = null; modValue.viewer.clock.onTick.removeEventListener(event1) modValue.viewer.clock.onTick.removeEventListener(event2) } function event1() { var viewer = modValue.viewer; if (viewer.camera._suspendTerrainAdjustment && viewer.scene.mode === Cesium.SceneMode.SCENE3D) { viewer.camera._suspendTerrainAdjustment = false; viewer.camera._adjustHeightForTerrain(); } // Keep camera in a reasonable pitch range var pitch = viewer.camera.pitch; //将像素坐标转为笛卡尔坐标 var pick1 = new Cesium.Cartesian2(modValue.wx, modValue.wy); var cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(pick1), viewer.scene); if (cartesian) { var cartographic1 = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian); var lon = Cesium.Math.toDegrees(cartographic1.longitude); var lat = Cesium.Math.toDegrees(cartographic1.latitude); var height = cartographic1.height; modValue.minHeight = height + 300; } var cameraPosition = viewer.camera.positionCartographic; if (pitch > modValue.maxPitch || pitch < modValue.minPitch || cameraPosition.height < modValue.minHeight) { viewer.scene.screenSpaceCameraController.enableTilt = false; // clamp the pitch if (pitch > modValue.maxPitch) { pitch = modValue.maxPitch; } else if (pitch < modValue.minPitch) { pitch = modValue.minPitch; } var destination = Cesium.Cartesian3.fromRadians( cameraPosition.longitude, cameraPosition.latitude, Math.max(cameraPosition.height, modValue.minHeight)); viewer.camera.setView({ destination: destination, orientation: { pitch: pitch } }); viewer.scene.screenSpaceCameraController.enableTilt = true; } } function resetCondition(options) { if (!isNaN(Number(options.speed))) { modValue.speed = options.speed } else { // throw "speed is error!" } if (!isNaN(Number(options.height))) { modValue.height = options.height var position = modValue.viewer.scene.globe.ellipsoid.cartesianToCartographic(modValue.position) position.height = modValue.height modValue.position = modValue.viewer.scene.globe.ellipsoid.cartographicToCartesian(position) } else { // throw "height is error!" } } function event2() { var viewer = modValue.viewer; modValue.speedVector = Cesium.Cartesian3.multiplyByScalar( Cesium.Cartesian3.UNIT_X, modValue.speed / 10, modValue.speedVector ); modValue.position = Cesium.Matrix4.multiplyByPoint( modValue.daqiaoModel.computeModelMatrix(), modValue.speedVector, modValue.position ); //重置飞机角度 resetPlanHeading(modValue.position.x, modValue.position.y, modValue.position.z); if (modValue.eyeslook == "one") { viewer.trackedEntity = undefined; // viewer.zoomTo(daqiaoModel); viewer.camera.setView({ destination: modValue.daqiaoModel.position.getValue(), // 设置位置 orientation: { heading: modValue.hpRoll.heading + (Cesium.Math.PI / 2), // 方向 pitch: modValue.hpRoll.pitch, // 倾斜角度 roll: modValue.hpRoll.roll } }) } else if (modValue.eyeslook == "two") { if (!viewer.trackedEntity) { viewer.zoomTo(modValue.daqiaoModel, new Cesium.HeadingPitchRange(0, 0, 5000)); } } else { viewer.trackedEntity = undefined; viewer.zoomTo(modValue.moniPolyline); } // viewer.zoomTo(modValue.daqiaoModel); } function calculationEveryLineNorthPoint() { //计算每段线路偏北角 for (var i = 0; i < modValue.lineCoor.length - 1; i++) { var point1 = turf.point(modValue.lineCoor[i]); var point2 = turf.point(modValue.lineCoor[i + 1]); var bearing = turf.bearing(point1, point2); modValue.tangle.push(bearing); } modValue.hpRoll.heading = Cesium.Math.toRadians(modValue.tangle[0] - 90); modValue.daqiaoModel.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( modValue.position, modValue.hpRoll )) } /** * [resetPlanHeading description] * @return {[type]} [description] * 重置飞机飞行角度 * 根据飞机笛卡尔坐标计算出飞机经纬度坐标 * 根据经纬度计算飞机现在处于哪条线段 * 根据线段的index得出飞机的heading * 如果飞机heading发生变化,重置飞机飞行角度 */ function resetPlanHeading(x, y, z) { var tranPosition = cartesian3ToLatLng(x, y, z); var alt = tranPosition.alt; tranPosition = getLineIndex(tranPosition.lat, tranPosition.lng); var lineindex = tranPosition.properties.index; tranPosition = tranPosition.geometry.coordinates; // position1 = Cesium.Cartesian3.fromDegrees(tranPosition[0], tranPosition[1], alt); modValue.daqiaoModel.position.setValue(modValue.position); if (lineindex < modValue.tangle.length) { var curHeading = modValue.tangle[lineindex]; modValue.hpRoll.heading = Cesium.Math.toRadians(curHeading - 90); modValue.daqiaoModel.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( modValue.position, modValue.hpRoll )) } } function getLineIndex(lat, lng) { var pt = turf.point([lng, lat]); var snapped = turf.nearestPointOnLine(modValue.lineTurf, pt, { units: 'miles' }); return snapped; } //世界坐标转经纬度坐标 function cartesian3ToLatLng(x, y, z) { var ellipsoid = modValue.viewer.scene.globe.ellipsoid; var Cartesian3 = new Cesium.Cartesian3(x, y, z); var cartographic = ellipsoid.cartesianToCartographic(Cartesian3); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } return position; } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.lookAroundAnalysis.add', init); PubSub.subscribe('map3D.lookAroundAnalysis.draw', draw); PubSub.subscribe('map3D.lookAroundAnalysis.start', start); PubSub.subscribe('map3D.lookAroundAnalysis.stop', stop); PubSub.subscribe('map3D.lookAroundAnalysis.remove', remove); PubSub.subscribe('map3D.lookAroundAnalysis.clear', clear); var modValue = {} function init(msg, options) { modValue.viewer = options.viewer modValue.scene = modValue.viewer.scene modValue.callback = options.callback modValue.tempEntities = {} modValue.calcIndex = 0 modValue.viewHeight = 0 modValue.pointArr = []; modValue.maxIndex = null; modValue.index = 0; } // 经度 纬度 距离 直接绘制 function draw(msg, options) { modValue.calcIndex++ modValue.index = 0 modValue.tempEntities[modValue.calcIndex] = []; modValue.startPoint = null modValue.viewHeight = options.viewHeight || 2 modValue.angleInterval = options.angleInterval || 2 var center = [options.lng, options.lat]; var option = { steps: 360 / modValue.angleInterval, units: 'meters', }; if (!options.lng) throw "lng is undefined!" if (!options.lat) throw "lat is undefined!" if (!options.distance) throw "distance is undefined!" var circle = turf.circle(center, options.distance, option); modValue.pointArr = circle.geometry.coordinates[0]; modValue.maxIndex = modValue.pointArr.length - 1; // modValue.depthTestAgainstTerrain = modValue.viewer.scene.globe.depthTestAgainstTerrain // modValue.viewer.scene.globe.depthTestAgainstTerrain = true; var positions = [Cesium.Cartographic.fromDegrees(options.lng, options.lat)]; var promise = new Cesium.sampleTerrain(modValue.viewer.terrainProvider, 13, positions); Cesium.when(promise, function (updatedPositionsArr) { var height = updatedPositionsArr[0].height + modValue.viewHeight; var cartesian_ = Cesium.Ellipsoid.WGS84.cartographicToCartesian({ longitude: updatedPositionsArr[0].longitude, latitude: updatedPositionsArr[0].latitude, height: height }) modValue.startPoint = { cartesian: cartesian_ } var drawCircle = turf.circle(center, options.distance, { steps: 360 / 2, units: 'meters', }); var entity = addCircle(drawCircle.geometry.coordinates[0]); modValue.tempEntities[modValue.calcIndex].push(entity) // modValue.tempEntities[modValue.calcIndex].push(entity) // var entity = drawPoint(modValue.startPoint.cartesian, "start") // modValue.tempEntities[modValue.calcIndex].push(entity) stopCameraController(false); circulateIndex(0); }); } function start(msg, options) { modValue.calcIndex++; modValue.index = 0 modValue.tempEntities[modValue.calcIndex] = []; modValue.startPoint = null // modValue.depthTestAgainstTerrain = modValue.viewer.scene.globe.depthTestAgainstTerrain // modValue.viewer.scene.globe.depthTestAgainstTerrain = true; modValue.viewHeight = options.viewHeight || 2 modValue.angleInterval = options.angleInterval || 2 recordCameraController(); if (!modValue.handler) { modValue.handler = new Cesium.ScreenSpaceEventHandler(modValue.viewer.scene.canvas); modValue.handler.setInputAction(function (evt) { // 像素点坐标,evt.position var cartesian = modValue.scene.pickPosition(evt.position); if (Cesium.defined(cartesian)) { if (!modValue.startPoint) { modValue.startPoint = {} modValue.startPoint.pixelCoordinates = { x: evt.position.x, y: evt.position.y }; var pick = new Cesium.Cartesian2(evt.position.x, evt.position.y); var cartesian = modValue.scene.globe.pick(modValue.viewer.camera.getPickRay(pick), modValue.scene); var obj = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian) modValue.startPoint.pixelCoordinates.height = obj.height + modValue.viewHeight var cartesian_ = Cesium.Ellipsoid.WGS84.cartographicToCartesian({ longitude: obj.longitude, latitude: obj.latitude, height: obj.height + modValue.viewHeight }) modValue.startPoint.cartesian = cartesian_ // var entity = drawPoint(modValue.startPoint.cartesian, "start") // modValue.tempEntities[modValue.calcIndex].push(entity) } else { var pick = new Cesium.Cartesian2(evt.position.x, evt.position.y); var cartesian = modValue.scene.globe.pick(modValue.viewer.camera.getPickRay(pick), modValue.scene); var Cartographic_end = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian) var lng_end = Cesium.Math.toDegrees(Cartographic_end.longitude) var lat_end = Cesium.Math.toDegrees(Cartographic_end.latitude) var Cartographic_start = Cesium.Ellipsoid.WGS84.cartesianToCartographic(modValue.startPoint.cartesian) var lng_start = Cesium.Math.toDegrees(Cartographic_start.longitude) var lat_start = Cesium.Math.toDegrees(Cartographic_start.latitude) var from = turf.point([lng_start, lat_start]); var to = turf.point([lng_end, lat_end]); var options = { units: 'meters' }; var distance = turf.distance(from, to, options); var center = [lng_start, lat_start]; var options = { steps: 360 / modValue.angleInterval, units: 'meters', }; var circle = turf.circle(center, distance, options); modValue.pointArr = circle.geometry.coordinates[0]; modValue.maxIndex = modValue.pointArr.length - 1; var drawCircle = turf.circle(center, distance, { steps: 360 / 2, units: 'meters', }); var entity = addCircle(drawCircle.geometry.coordinates[0]); modValue.tempEntities[modValue.calcIndex].push(entity) stopCameraController(false); circulateIndex(0); } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } } function circulateIndex(index) { getHeigthByLonLat(modValue.pointArr[index][0], modValue.pointArr[index][1]); } function getHeigthByLonLat(lon, lat) { var positions = [Cesium.Cartographic.fromDegrees(lon, lat)]; var promise = new Cesium.sampleTerrain(modValue.viewer.terrainProvider, 13, positions); Cesium.when(promise, function (updatedPositionsArr) { var cartesian = Cesium.Ellipsoid.WGS84.cartographicToCartesian(updatedPositionsArr[0]) ray(modValue.startPoint.cartesian, cartesian) if (modValue.maxIndex > modValue.index) { // var entity = drawPoint(cartesian, "end") // modValue.tempEntities[modValue.calcIndex].push(entity) modValue.index++; circulateIndex(modValue.index); } else { if (modValue.callback) { detach(); modValue.callback(); } } }); } function ray(start, end) { var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()), new Cesium.Cartesian3()); var ray = new Cesium.Ray(start, direction); var result1 = map3DViewer.map.scene.globe.pick(ray, map3DViewer.map.scene); var arr = Object.values(modValue.tempEntities).map(function (item) { return Object.values(item) }) var removeArr = arr.reduce(function (a, b) { return a.concat(b) }) var result2 = map3DViewer.map.scene.pickFromRay(ray, removeArr); var result; if (result2) { result2 = result2.position; } //计算出距离起始点最近的点 if (result1) { if (result2) { result = getResult(start, end, [result1, result2]) } else { result = getResult(start, end, [result1]); } } else if (result2) { result = getResult(start, end, [result2]); } else { // result = end; } showIntersection(start, result, end); } function getResult(start, end, arr) { var result; startC = getLatlng(start); endC = getLatlng(end); var betweenStartAndEndDis = getFlatternDistance(startC.lat, startC.lng, endC.lat, endC.lng); if (arr.length == 2) { var dresult1 = getLatlng(arr[0]); var dresult2 = getLatlng(arr[1]); var dis1 = getFlatternDistance(startC.lat, startC.lng, dresult1.lat, dresult1.lng); var dis2 = getFlatternDistance(startC.lat, startC.lng, dresult2.lat, dresult2.lng); if (dis1 > betweenStartAndEndDis && dis2 > betweenStartAndEndDis) { result = end; } else if (betweenStartAndEndDis > dis1 && dis2 > betweenStartAndEndDis) { result = arr[0]; } else if (dis1 > betweenStartAndEndDis && betweenStartAndEndDis > dis2) { result = arr[1]; } else { if (dis1 <= dis2) { result = arr[0]; } else { result = arr[1]; } } } else { var dresult1 = getLatlng(arr[0]); var dis1 = getFlatternDistance(startC.lat, startC.lng, dresult1.lat, dresult1.lng); if (dis1 >= betweenStartAndEndDis) { result = end; } else { result = arr[0]; } } return result; } function getLatlng(c) { var ellipsoid = map3DViewer.map.scene.globe.ellipsoid; var Cartesian3 = c; var cartographic = ellipsoid.cartesianToCartographic(Cartesian3); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } return position; } function addCircle(array) { var positions = [] for (var i = 0; i < array.length; i++) { positions.push(array[i][0]) positions.push(array[i][1]) } var position = Cesium.Cartesian3.fromDegreesArray(positions) var entity = map3DViewer.map.entities.add({ polyline: { positions: position, clampToGround: true, width: 2, material: Cesium.Color.fromCssColorString('#D0CE00'), } }) return entity } // 处理交互点 function showIntersection(start, result, end) { if (result) { var entity1 = drawLinew(start, result, Cesium.Color.GREEN); // 可视区域 modValue.tempEntities[modValue.calcIndex].push(entity1) var entity2 = drawLinew(result, end, Cesium.Color.RED); // 不可视区域 modValue.tempEntities[modValue.calcIndex].push(entity2) } else { var entity = drawLinew(start, end, Cesium.Color.GREEN); // 可视区域 modValue.tempEntities[modValue.calcIndex].push(entity) } } function drawLinew(leftPoint, secPoint, color) { var entity = map3DViewer.map.entities.add({ polyline: { positions: [leftPoint, secPoint], arcType: Cesium.ArcType.NONE, width: 2, material: color, // clampToGround: true } }) return entity } function getFlatternDistance(lat1, lng1, lat2, lng2) { var EARTH_RADIUS = 6378137.0; //单位M var PI = Math.PI; function getRad(d) { return d * PI / 180.0; } var f = getRad((lat1 + lat2) / 2); var g = getRad((lat1 - lat2) / 2); var l = getRad((lng1 - lng2) / 2); var sg = Math.sin(g); var sl = Math.sin(l); var sf = Math.sin(f); var s, c, w, r, d, h1, h2; var a = EARTH_RADIUS; var fl = 1 / 298.257; sg = sg * sg; sl = sl * sl; sf = sf * sf; s = sg * (1 - sl) + (1 - sf) * sl; c = (1 - sg) * (1 - sl) + sf * sl; w = Math.atan(Math.sqrt(s / c)); r = Math.sqrt(s * c) / w; d = 2 * w * a; h1 = (3 * r - 1) / 2 / c; h2 = (3 * r + 1) / 2 / s; return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg)); } function stop() { detach(); } function remove() { detach(); clear(); } function detach() { recoveryCameraController(); if (modValue.handler) { modValue.handler.destroy(); modValue.handler = null } // if (callback) { // modValue.start() // } } function clear() { modValue.startPoint = null; for (var key in modValue.tempEntities) { if (modValue.tempEntities.hasOwnProperty(key)) { for (var i = 0; i < modValue.tempEntities[key].length; i++) { if (modValue.tempEntities[key][i]) modValue.viewer.entities.removeById(modValue.tempEntities[key][i]._id) } } } modValue.tempEntities = {} modValue.calcIndex = 0 modValue.viewHeight = 0 modValue.angleInterval = 2 modValue.pointArr = []; modValue.maxIndex = null; modValue.mapCameraControllerObj = null modValue.mapCameraControllerObj = null } function drawPoint(position, type) { var point = null; if (type == "start") { point = { pixelSize: 10, heightReference: 1, color: Cesium.Color.YELLOW, } } else { point = { pixelSize: 10, heightReference: 1, color: Cesium.Color.RED, } } var entity = modValue.viewer.entities.add({ position: position, point: point }); return entity // modValue.tempEntities = modValue.tempEntities.concat([entity]) } function stopCameraController(judge) { // 如果为真,则允许用户旋转相机。如果为假,相机将锁定到当前标题。此标志仅适用于2D和3D。 modValue.scene.screenSpaceCameraController.enableRotate = judge; // 如果为true,则允许用户平移地图。如果为假,相机将保持锁定在当前位置。此标志仅适用于2D和Columbus视图模式。 modValue.scene.screenSpaceCameraController.enableTranslate = judge; // 如果为真,允许用户放大和缩小。如果为假,相机将锁定到距离椭圆体的当前距离 modValue.scene.screenSpaceCameraController.enableZoom = judge; // 如果为真,则允许用户倾斜相机。如果为假,相机将锁定到当前标题。这个标志只适用于3D和哥伦布视图。 modValue.scene.screenSpaceCameraController.enableTilt = judge; } function recordCameraController() { modValue.mapCameraControllerObj = { enableRotate: null, enableTranslate: null, enableZoom: null, enableTilt: null } modValue.mapCameraControllerObj.enableRotate = modValue.scene.screenSpaceCameraController.enableRotate modValue.mapCameraControllerObj.enableTranslate = modValue.scene.screenSpaceCameraController.enableTranslate modValue.mapCameraControllerObj.enableZoom = modValue.scene.screenSpaceCameraController.enableZoom modValue.mapCameraControllerObj.enableTilt = modValue.scene.screenSpaceCameraController.enableTilt } function recoveryCameraController() { if (modValue.scene && modValue.mapCameraControllerObj) { modValue.scene.screenSpaceCameraController.enableRotate = modValue.mapCameraControllerObj.enableRotate; modValue.scene.screenSpaceCameraController.enableTranslate = modValue.mapCameraControllerObj.enableTranslate; modValue.scene.screenSpaceCameraController.enableZoom = modValue.mapCameraControllerObj.enableZoom; modValue.scene.screenSpaceCameraController.enableTilt = modValue.mapCameraControllerObj.enableTilt; } } // function judgeBetweenPoint(start, end) { // var rad1 = start // var rad2 = end // var xy = true; // function createEquation(obj1, obj2) { // var d = function (x) { // return (x - obj1.x) / (obj2.x - obj1.x) * (obj2.y - obj1.y) + obj1.y // } // d.__proto__.obj1 = obj1 // d.__proto__.obj2 = obj2 // return d // } // var equation = null // if (Math.abs(rad1.x - rad2.x) >= Math.abs(rad1.y - rad2.y)) { // xy = true; // interpolationAccuracy = Math.ceil(Math.abs(rad1.x - rad2.x)) // equation = createEquation({ // x: rad1.x, // y: rad1.y, // }, { // x: rad2.x, // y: rad2.y, // }) // } else { // xy = false; // interpolationAccuracy = Math.ceil(Math.abs(rad1.y - rad2.y)) // equation = createEquation({ // x: rad1.y, // y: rad1.x, // }, { // x: rad2.y, // y: rad2.x, // }) // } // var gaodu = null; // var judge = { // coordinates: null, // judge: false // } // for (var k = 0; k < interpolationAccuracy; k++) { // gaodu = rad1.height - (rad1.height - rad2.height) * 1 / interpolationAccuracy * (k + 1); // var x = null, // y = null // if (xy) { // x = Math.round(rad1.x - (rad1.x - rad2.x) * 1 / interpolationAccuracy * (k + 1)) // y = Math.round(equation(x)) // } else { // y = Math.round(rad1.y - (rad1.y - rad2.y) * 1 / interpolationAccuracy * (k + 1)) // x = Math.round(equation(y)) // } // var _cartesian = modValue.viewer.scene.globe.pick(modValue.viewer.camera.getPickRay({ // x: x, // y: y // }), modValue.viewer.scene); // if (_cartesian) { // var pick = Cesium.Ellipsoid.WGS84.cartesianToCartographic(_cartesian) // var gaocheng = pick.height // if (gaocheng > gaodu) { // //经纬度高程 转 笛卡尔 // judge.coordinates = _cartesian // judge.judge = true; // break // } else { // continue // } // } else { // continue // } // } // return judge // } // function drawLine(start, end, cannotSee) { // if (!cannotSee) { // var entity = modValue.viewer.entities.add({ // polyline: { // positions: [ // start, // end // ], // arcType: Cesium.ArcType.NONE, // width: 5, // material: Cesium.Color.GREEN, // // depthFailMaterial: Cesium.Color.GREEN // } // }) // modValue.tempEntities = modValue.tempEntities.concat([entity]) // } else { // var entity1 = modValue.viewer.entities.add({ // polyline: { // positions: [ // start, // cannotSee // ], // arcType: Cesium.ArcType.NONE, // width: 5, // material: Cesium.Color.GREEN, // // depthFailMaterial: Cesium.Color.GREEN // } // }) // var entity2 = modValue.viewer.entities.add({ // polyline: { // positions: [ // cannotSee, // end, // ], // arcType: Cesium.ArcType.NONE, // width: 5, // material: Cesium.Color.RED, // // depthFailMaterial: Cesium.Color.RED // } // }) // modValue.tempEntities = modValue.tempEntities.concat([entity1, entity2]) // } // } }(window, document)); ; (function (window, document, undefined) { // PubSub.subscribe('map3D.modelControl.add', init); // PubSub.subscribe('map3D.modelControl.changeView', changeView); var modelControl = map23DControl.modelControl; if (typeof module === 'object' && typeof module.exports === 'object') { module.exports = modelControl; } else if (typeof define === 'function' && define.amd) { define(modelControl); } // 模型控制 map3DViewer.modelControl = function (options) { switch (options.action) { case 'add': return init(options); break; case 'change': return change(options); break; case 'control': return control(options); break; case 'update': return update(options); break; case 'delete': return deleteGuid(options); break; case 'remove': return remove(options); break; } } var guid = null; function init(options) { guid = options.guid || map23DControl.buildGuid('modelControl3D'); // if (!options.entity) throw "entity is undefined!" // entity = options.entity var entity = null; if (options.modelGuid) { entity = map3DViewer.models[options.modelGuid] } else { if (!options.entity) throw "entity is undefined!" entity = options.entity } if (!options.modelGuid && !options.entity) { throw "No model in parameters" } map3DViewer.modelControlObj[guid] = {} var radianInterval = null if (options.radianInterval) { radianInterval = Cesium.Math.toRadians(options.radianInterval) } else { radianInterval = Cesium.Math.toRadians(3.0) } var scaleInterval = options.scaleInterval || 2 var scaleMax = options.scaleMax || 10 var scaleInit = options.scaleInit || 1 var heading = options.heading || 0 var pitch = options.pitch || 0 var roll = options.roll || 0 map3DViewer.modelControlObj[guid] = { scale: scaleInit, keyboardControl: options.keyboardControl || false, customizeControl: options.customizeControl || true, // hpRoll: new Cesium.HeadingPitchRoll().fromDegrees(heading, pitch, roll), hpRoll: Cesium.HeadingPitchRoll.fromDegrees(heading, pitch, roll), radianInterval: radianInterval, scaleInterval: scaleInterval, scaleMax: scaleMax, scaleInit: scaleInit, entity: entity, viewer: options.viewer || map3DViewer.map, callback: options.callback || null } document.addEventListener("keydown", event); return guid } function deleteGuid(options) { delete map3DViewer.modelControlObj[options.guid] } function remove() { document.removeEventListener("keydown", event); for (var key in map3DViewer.modelControlObj) { if (object.hasOwnProperty(key)) { delete map3DViewer.modelControlObj[key] } } guid = null } function update(options) { if (options.guid || !map3DViewer.modelControlObj[options.guid]) throw "guid is undefined!" map3DViewer.modelControlObj[options.guid] = Object.assign({}, map3DViewer.modelControlObj[options.guid], options) } function change(options) { if (!options.guid) throw "guid is undefined!" if (!map3DViewer.modelControlObj[options.guid]) throw "guid is undefined!" if (!map3DViewer.modelControlObj[options.guid].entity) throw "entity is undefined!" guid = options.guid } function control(options) { if (!map3DViewer.modelControlObj[guid].customizeControl) return change(options) if (!options.behavior) throw "behavior is undefined!" if (!map3DViewer.modelControlObj[options.guid].entity) throw "entity is undefined!" if (!map3DViewer.modelControlObj[guid]) throw "guid is undefined!" mod(options.behavior); } function event(e) { if (!map3DViewer.modelControlObj[guid]) throw "guid is undefined!" if (!map3DViewer.modelControlObj[guid].keyboardControl) return var obj = map3DViewer.modelControlObj[guid] switch (e.keyCode) { case 40: if (e.ctrlKey) { mod("BeSmaller") } else { // pitch down mod("PitchDown") } break; case 38: if (e.ctrlKey) { mod("BeLarger") } else { // pitch up mod("PitchUp") } break; case 39: if (e.shiftKey) { // roll right mod("RollRight") } else { // turn right mod("TurnRight") } break; case 37: if (e.shiftKey) { // roll left until mod("RollLeft") } else { // turn left mod("TurnLeft") } break; default: } } function mod(behavior) { var obj = map3DViewer.modelControlObj[guid] if (!map3DViewer.modelControlObj[guid].viewer.entities.getById(obj.entity._id)) { delete map3DViewer.modelControlObj[guid] return } switch (behavior) { case "BeLarger": var scale = obj.scale + obj.scaleInterval; obj.scale = scale <= obj.scaleMax ? scale : obj.scaleMax; obj.entity.model.scale.setValue(obj.scale) break; case "BeSmaller": var scale = obj.scale - obj.scaleInterval; obj.scale = scale >= obj.scaleInit ? scale : obj.scaleInit; obj.entity.model.scale.setValue(obj.scale) break; case "PitchUp": // pitch up obj.hpRoll.pitch += obj.radianInterval; if (obj.hpRoll.pitch > Cesium.Math.TWO_PI) { obj.hpRoll.pitch -= Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; case "PitchDown": // pitch down obj.hpRoll.pitch -= obj.radianInterval; if (obj.hpRoll.pitch < -Cesium.Math.TWO_PI) { obj.hpRoll.pitch += Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; case "RollRight": // roll right obj.hpRoll.roll += obj.radianInterval; if (obj.hpRoll.roll > Cesium.Math.TWO_PI) { obj.hpRoll.roll -= Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; case "RollLeft": // roll left until obj.hpRoll.roll -= obj.radianInterval; if (obj.hpRoll.roll < 0.0) { obj.hpRoll.roll += Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; case "TurnRight": // turn right obj.hpRoll.heading += obj.radianInterval; if (obj.hpRoll.heading > Cesium.Math.TWO_PI) { obj.hpRoll.heading -= Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; case "TurnLeft": // turn left obj.hpRoll.heading -= obj.radianInterval; if (obj.hpRoll.heading < 0.0) { obj.hpRoll.heading += Cesium.Math.TWO_PI; } obj.entity.orientation.setValue(Cesium.Transforms.headingPitchRollQuaternion( obj.entity._position.getValue(), obj.hpRoll )) break; default: break; } if (map3DViewer.modelControlObj[guid].callback) { // map3DViewer.modelControlObj[guid] map3DViewer.modelControlObj[guid].callback({ scale: obj.scale, heading: obj.hpRoll.heading / Cesium.Math.TWO_PI * 360, roll: obj.hpRoll.roll / Cesium.Math.TWO_PI * 360, pitch: obj.hpRoll.pitch / Cesium.Math.TWO_PI * 360, }) } } }(window, document)); ; (function (window, document, undefined) { PubSub.subscribe('map3D.visualAnalysis.add', init); PubSub.subscribe('map3D.visualAnalysis.start', start); PubSub.subscribe('map3D.visualAnalysis.stop', stop); PubSub.subscribe('map3D.visualAnalysis.remove', remove); PubSub.subscribe('map3D.visualAnalysis.clear', clear); var modValue = {} function init(msg, options) { modValue.viewer = options.viewer modValue.scene = modValue.viewer.scene modValue.callback = options.callback modValue.index = 0 modValue.tempEntities = {} } function start(msg, options) { modValue.startPoint = null; modValue.endPoint = null; modValue.index++; modValue.tempEntities[modValue.index] = []; modValue.depthTestAgainstTerrain = modValue.viewer.scene.globe.depthTestAgainstTerrain modValue.viewer.scene.globe.depthTestAgainstTerrain = true; modValue.viewHeight = options.viewHeight || 2 if (!modValue.handler) { modValue.handler = new Cesium.ScreenSpaceEventHandler(modValue.viewer.scene.canvas); modValue.handler.setInputAction(function (evt) { // 像素点坐标,evt.position var cartesian = modValue.scene.pickPosition(evt.position); if (Cesium.defined(cartesian)) { if (!modValue.startPoint) { modValue.startPoint = {} modValue.startPoint.pixelCoordinates = { x: evt.position.x, y: evt.position.y }; var pick = evt.position; var cartesian = modValue.scene.pickPosition(pick); var obj = Cesium.Cartographic.fromCartesian(cartesian); modValue.startPoint.pixelCoordinates.height = obj.height + modValue.viewHeight; var cartesian_ = Cesium.Ellipsoid.WGS84.cartographicToCartesian({ longitude: obj.longitude, latitude: obj.latitude, height: obj.height + modValue.viewHeight }) modValue.startPoint.cartesian = cartesian_ var entity = drawPoint(modValue.startPoint.cartesian, "start"); modValue.tempEntities[modValue.index].push(entity); } else { modValue.endPoint = {} modValue.endPoint.pixelCoordinates = { x: evt.position.x, y: evt.position.y }; var pick = evt.position; var cartesian = modValue.scene.pickPosition(pick); modValue.endPoint.cartesian = cartesian modValue.endPoint.pixelCoordinates.height = Cesium.Cartographic.fromCartesian(cartesian).height; var entity = drawPoint(modValue.endPoint.cartesian, "end") modValue.tempEntities[modValue.index].push(entity); var result = ray(modValue.startPoint.cartesian, modValue.endPoint.cartesian) if (modValue.callback) { detach() modValue.callback(); } } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); } } function ray(start, end) { var direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()), new Cesium.Cartesian3()); var ray = new Cesium.Ray(start, direction); var result1 = map3DViewer.map.scene.globe.pick(ray, map3DViewer.map.scene); var result2 = map3DViewer.map.scene.pickFromRay(ray, modValue.tempEntities[modValue.index]); if (result2) { result2 = result2.position; } //计算出距离起始点最近的点 if (result1) { if (result2) { result = getResult(start, end, [result1, result2]) } else { result = getResult(start, end, [result1]); } } else if (result2) { result = getResult(start, end, [result2]); } else { // result = end; } showIntersection(start, result, end); return result } function getResult(start, end, arr) { var result; startC = getLatlng(start); endC = getLatlng(end); var betweenStartAndEndDis = getFlatternDistance(startC.lat, startC.lng, endC.lat, endC.lng); if (arr.length == 2) { var dresult1 = getLatlng(arr[0]); var dresult2 = getLatlng(arr[1]); var dis1 = getFlatternDistance(startC.lat, startC.lng, dresult1.lat, dresult1.lng); var dis2 = getFlatternDistance(startC.lat, startC.lng, dresult2.lat, dresult2.lng); if (dis1 > betweenStartAndEndDis && dis2 > betweenStartAndEndDis) { result = end; } else if (betweenStartAndEndDis > dis1 && dis2 > betweenStartAndEndDis) { result = arr[0]; } else if (dis1 > betweenStartAndEndDis && betweenStartAndEndDis > dis2) { result = arr[1]; } else { if (dis1 <= dis2) { result = arr[0]; } else { result = arr[1]; } } } else { var dresult1 = getLatlng(arr[0]); var dis1 = getFlatternDistance(startC.lat, startC.lng, dresult1.lat, dresult1.lng); if (dis1 >= betweenStartAndEndDis) { result = end; } else { result = arr[0]; } } return result; } function getLatlng(c) { var ellipsoid = map3DViewer.map.scene.globe.ellipsoid; var Cartesian3 = c; var cartographic = ellipsoid.cartesianToCartographic(Cartesian3); var lat = Cesium.Math.toDegrees(cartographic.latitude); var lng = Cesium.Math.toDegrees(cartographic.longitude); var alt = cartographic.height; var position = { lat: lat, lng: lng, alt: alt } return position; } // 处理交互点 function showIntersection(start, result, end) { // // 如果是场景模型的交互点,排除交互点是地球表面 // drawLinew(result, viewPoint, Cesium.Color.GREEN); // 可视区域 // drawLinew(result, destPoint, Cesium.Color.RED); // 不可视区域 if (result) { var entity1 = drawLinew(start, result, Cesium.Color.GREEN); // 可视区域 modValue.tempEntities[modValue.index].push(entity1) var entity2 = drawLinew(result, end, Cesium.Color.RED); // 不可视区域 modValue.tempEntities[modValue.index].push(entity2) } else { var entity = drawLinew(start, end, Cesium.Color.GREEN); // 可视区域 modValue.tempEntities[modValue.index].push(entity) } } function drawLinew(leftPoint, secPoint, color) { var entity = map3DViewer.map.entities.add({ polyline: { positions: [leftPoint, secPoint], arcType: Cesium.ArcType.NONE, width: 5, material: color, // clampToGround: true } }) modValue.tempEntities[modValue.index].push(entity) // modValue.tempEntities = modValue.tempEntities.concat([entity]) } function stop() { detach(); } function remove() { detach(); clear(); } function detach() { if (modValue.handler) { modValue.handler.destroy(); modValue.handler = null } // if (callback) { // modValue.start() // } } function clear() { modValue.startPoint = null; modValue.endPoint = null; if (modValue.tempEntities) for (var key in modValue.tempEntities) { if (modValue.tempEntities.hasOwnProperty(key)) { for (var i = 0; i < modValue.tempEntities[key].length; i++) { if (modValue.tempEntities[key][i]) modValue.viewer.entities.removeById(modValue.tempEntities[key][i]._id) } } } modValue.tempEntities = {}; modValue.index = 0; modValue.viewHeight = 2 if (modValue.scene) modValue.scene.globe.depthTestAgainstTerrain = modValue.depthTestAgainstTerrain; modValue.depthTestAgainstTerrain = null } function getFlatternDistance(lat1, lng1, lat2, lng2) { var EARTH_RADIUS = 6378137.0; //单位M var PI = Math.PI; function getRad(d) { return d * PI / 180.0; } var f = getRad((lat1 + lat2) / 2); var g = getRad((lat1 - lat2) / 2); var l = getRad((lng1 - lng2) / 2); var sg = Math.sin(g); var sl = Math.sin(l); var sf = Math.sin(f); var s, c, w, r, d, h1, h2; var a = EARTH_RADIUS; var fl = 1 / 298.257; sg = sg * sg; sl = sl * sl; sf = sf * sf; s = sg * (1 - sl) + (1 - sf) * sl; c = (1 - sg) * (1 - sl) + sf * sl; w = Math.atan(Math.sqrt(s / c)); r = Math.sqrt(s * c) / w; d = 2 * w * a; h1 = (3 * r - 1) / 2 / c; h2 = (3 * r + 1) / 2 / s; return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg)); } function drawPoint(position, type) { var point = null; if (type == "start") { point = { pixelSize: 10, heightReference: 0, color: Cesium.Color.YELLOW, } } else { point = { pixelSize: 10, heightReference: 0, color: Cesium.Color.RED, } } var entity = modValue.viewer.entities.add({ position: position, point: point }); return entity // modValue.tempEntities = modValue.tempEntities.concat([entity]) } }(window, document)); /* * L.Control.Zoom is used for the default zoom buttons on the map. */ L.Control.Zoom = L.Control.extend({ options: { position: 'bottomleft' }, onAdd: function (map) { var zoomName = 'leaflet-control-zoom', container = L.DomUtil.create('div', zoomName + ' leaflet-bar'); this._map = map; this._zoomInButton = this._createButton( '+', '放大', zoomName + '-in', container, this._zoomIn, this); this._zoomNum = L.DomUtil.create('div','zoom-num',container); this._zoomNum.innerHTML = this._map.getZoom(); this._zoomOutButton = this._createButton( '-', '缩小', zoomName + '-out', container, this._zoomOut, this); map.on('zoomend zoomlevelschange', this._updateDisabled, this); L.DomEvent.on(container,'contextmenu',L.DomEvent.stopPropagation); return container; }, onRemove: function (map) { map.off('zoomend zoomlevelschange', this._updateDisabled, this); }, _zoomIn: function (e) { this._map.zoomIn(e.shiftKey ? 3 : 1); }, _zoomOut: function (e) { this._map.zoomOut(e.shiftKey ? 3 : 1); }, _createButton: function (html, title, className, container, fn, context) { var link = L.DomUtil.create('a', className, container); link.innerHTML = html; link.title = title; var stop = L.DomEvent.stopPropagation; L.DomEvent .on(link, 'click', stop) .on(link, 'mousedown', stop) .on(link, 'dblclick', stop) .on(link, 'click', L.DomEvent.preventDefault) .on(link, 'click', fn, context) .on(link, 'click', this._refocusOnMap, context); return link; }, _updateDisabled: function () { var map = this._map, className = 'leaflet-disabled'; L.DomUtil.removeClass(this._zoomInButton, className); L.DomUtil.removeClass(this._zoomOutButton, className); if (map._zoom === map.getMinZoom()) { L.DomUtil.addClass(this._zoomOutButton, className); } if (map._zoom === map.getMaxZoom()) { L.DomUtil.addClass(this._zoomInButton, className); } this._zoomNum.innerHTML = map._zoom; } }); L.Map.mergeOptions({ zoomControl: false }); L.Map.addInitHook(function () { if (this.options.zoomControl) { this.zoomControl = new L.Control.Zoom(); this.addControl(this.zoomControl); } }); L.control.zoom = function (options) { return new L.Control.Zoom(options); }; /** * 添加缩放等级控件 * @param {[type]} options [description] * @return {[type]} [description] */ map2DViewer.setZoomControl = function(options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10] } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.zoomControl = new L.Control.Zoom({ position: defaultData.position, offset: defaultData.offset }).addTo(this.map); return this.zoomControl; break; case 'remove': this.map.removeControl(this.zoomControl) break; } } var Knob = L.Draggable.extend({ initialize: function (element, stepWidth, knobWidth) { L.Draggable.prototype.initialize.call(this, element, element); this._element = element; this._stepWidth = stepWidth; this._knobWidth = knobWidth; this.on('predrag', function () { this._newPos.y = 0; this._newPos.x = this._adjust(this._newPos.x); }, this); }, _adjust: function (x) { var value = Math.round(this._toValue(x)); value = Math.max(0, Math.min(this._maxValue, value)); return this._toX(value); }, // x = k*v + m _toX: function (value) { return this._k * value + this._m; }, // v = (x - m) / k _toValue: function (x) { return (x - this._m) / this._k; }, setSteps: function (steps) { var sliderWidth = steps * this._stepWidth; this._maxValue = steps - 1; // conversion parameters // the conversion is just a common linear function. this._k = this._stepWidth; this._m = (this._stepWidth ) / 2; }, setPosition: function (x) { L.DomUtil.setPosition(this._element, L.point(this._adjust(x),0)); }, setValue: function (v) { this.setPosition(this._toX(v)); }, getValue: function () { return this._toValue(L.DomUtil.getPosition(this._element).x); } }); L.Control.Zoomslider = L.Control.extend({ options: { position: 'topleft', // Height of zoom-slider.png in px stepWidth: 8, // Height of the knob div in px (including border) knobWidth: 12, styleNS: 'leaflet-control-zoomslider', offset:[10,10], showZoomInfo:true }, onAdd: function (map) { this._map = map; this._ui = this._createUI(); this._knob = new Knob(this._ui.knob, this.options.stepWidth, this.options.knobWidth); map.whenReady(this._initKnob, this) .whenReady(this._initEvents, this) .whenReady(this._updateSize, this) .whenReady(this._updateKnobValue, this) .whenReady(this._updateDisabled, this); switch(this.options.position){ case 'topleft': this._ui.bar.style.marginLeft = this.options.offset[0]+'px'; this._ui.bar.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._ui.bar.style.marginRight = this.options.offset[0]+'px'; this._ui.bar.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._ui.bar.style.marginLeft = this.options.offset[0]+'px'; this._ui.bar.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._ui.bar.style.marginRight = this.options.offset[0]+'px'; this._ui.bar.style.marginBottom = this.options.offset[1]+'px'; break; } return this._ui.bar; }, onRemove: function (map) { map.off('zoomlevelschange', this._updateSize, this) .off('zoomend zoomlevelschange', this._updateKnobValue, this) .off('zoomend zoomlevelschange', this._updateDisabled, this); }, _createUI: function () { var ui = {}, ns = this.options.styleNS; ui.bar = L.DomUtil.create('div', ns + ' leaflet-bar'); ui.zoomOut = this._createZoomBtn('out', 'bottom', ui.bar); ui.wrap = L.DomUtil.create('div', ns + '-wrap leaflet-bar-part', ui.bar); ui.zoomIn = this._createZoomBtn('in', 'top', ui.bar); ui.body = L.DomUtil.create('div', ns + '-body', ui.wrap); ui.knob = L.DomUtil.create('div', ns + '-knob'); ui.zoomNum = L.DomUtil.create('div', ns + '-zoomNum',ui.knob); if(!this.options.showZoomInfo){ ui.zoomNum.style.display = 'none'; } L.DomEvent.disableClickPropagation(ui.bar); L.DomEvent.disableClickPropagation(ui.knob); return ui; }, _createZoomBtn: function (zoomDir, end, container) { var classDef = this.options.styleNS + '-' + zoomDir + ' leaflet-bar-part' + ' leaflet-bar-part-' + end, link = L.DomUtil.create('a', classDef, container); link.href = '#'; link.title = 'Zoom ' + zoomDir; L.DomEvent.on(link, 'click', L.DomEvent.preventDefault); return link; }, _initKnob: function () { this._knob.enable(); this._ui.body.appendChild(this._ui.knob); }, _initEvents: function () { this._map .on('zoomlevelschange', this._updateSize, this) .on('zoomend zoomlevelschange', this._updateKnobValue, this) .on('zoomend zoomlevelschange', this._updateDisabled, this); L.DomEvent.on(this._ui.body, 'click', this._onSliderClick, this); L.DomEvent.on(this._ui.zoomIn, 'click', this._zoomIn, this); L.DomEvent.on(this._ui.zoomOut, 'click', this._zoomOut, this); this._knob.on('dragend', this._updateMapZoom, this); }, _onSliderClick: function (e) { var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), x = L.DomEvent.getMousePosition(first, this._ui.body).x; this._knob.setPosition(x); this._updateMapZoom(); }, _zoomIn: function (e) { this._map.zoomIn(e.shiftKey ? 3 : 1); }, _zoomOut: function (e) { this._map.zoomOut(e.shiftKey ? 3 : 1); }, _zoomLevels: function () { var zoomLevels = this._map.getMaxZoom() - this._map.getMinZoom() + 1; return zoomLevels < Infinity ? zoomLevels : 0; }, _toZoomLevel: function (value) { return value + this._map.getMinZoom(); }, _toValue: function (zoomLevel) { return zoomLevel - this._map.getMinZoom(); }, _updateSize: function () { var steps = this._zoomLevels(); this._ui.body.style.width = this.options.stepWidth * steps + 'px'; this._knob.setSteps(steps); }, _updateMapZoom: function () { this._map.setZoom(this._toZoomLevel(this._knob.getValue())); }, _updateKnobValue: function () { this._knob.setValue(this._toValue(this._map.getZoom())); this._ui.zoomNum.innerHTML = this._map.getZoom(); }, _updateDisabled: function () { var zoomLevel = this._map.getZoom(), className = this.options.styleNS + '-disabled'; L.DomUtil.removeClass(this._ui.zoomIn, className); L.DomUtil.removeClass(this._ui.zoomOut, className); if (zoomLevel === this._map.getMinZoom()) { L.DomUtil.addClass(this._ui.zoomOut, className); } if (zoomLevel === this._map.getMaxZoom()) { L.DomUtil.addClass(this._ui.zoomIn, className); } } }); L.Map.addInitHook(function () { if (this.options.zoomsliderControl) { this.zoomsliderControl = new L.Control.Zoomslider(); this.addControl(this.zoomsliderControl); } }); L.control.zoomslider = function (options) { return new L.Control.Zoomslider(options); }; /** * 添加缩放等级滑动条 * @param {[type]} options [description] */ map2DViewer.setNavigationControl = function(options) { var _this = map2DViewer; var defaultData = { action: 'add', position: 'bottomright', offset: [10, 10] } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.navigationControl = new L.Control.Zoomslider({ position: defaultData.position, offset: defaultData.offset }).addTo(this.map); return this.navigationControl; break; case 'remove': this.map.removeControl(this.navigationControl) break; } } /* * L.Control.Scale is used for displaying metric/imperial scale on the map. */ L.Control.Scale = L.Control.extend({ options: { position: 'bottomleft', maxWidth: 100, metric: false, imperial: true, updateWhenIdle: false, offset:[10,10] }, initialize: function (options) { L.setOptions(this, options); }, onAdd: function (map) { this._map = map; var className = 'leaflet-control-scale', container = L.DomUtil.create('div', className), options = this.options; switch(this.options.position){ case 'topleft': container.style.marginLeft = this.options.offset[0]+'px'; container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': container.style.marginRight = this.options.offset[0]+'px'; container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': container.style.marginLeft = this.options.offset[0]+'px'; container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': container.style.marginRight = this.options.offset[0]+'px'; container.style.marginBottom = this.options.offset[1]+'px'; break; } this._addScales(options, className, container); map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this); map.whenReady(this._update, this); L.DomEvent.on(container,'contextmenu',L.DomEvent.stopPropagation); return container; }, onRemove: function (map) { map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this); }, getUnit:function(){ return this.options.metric?'metric':'imperial' }, setUnit:function(unit){ if(unit == 'metric'){ this.options.metric = true; this.options.imperial = false; this._mScale.style.display = 'block'; this._iScale.style.display = 'none'; } if(unit == 'imperial'){ this.options.metric = false; this.options.imperial = true; this._iScale.style.display = 'block'; this._mScale.style.display = 'none'; } this._update(); }, _addScales: function (options, className, container) { this._mScale = L.DomUtil.create('div', className + '-line', container); this._iScale = L.DomUtil.create('div', className + '-line', container); if (options.metric) { this._mScale.style.display = 'block'; this._iScale.style.display = 'none'; } if (options.imperial) { this._iScale.style.display = 'block'; this._mScale.style.display = 'none'; } }, _update: function () { var bounds = this._map.getBounds(), centerLat = bounds.getCenter().lat, halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180), dist = halfWorldMeters * (bounds.getNorthEast().lng - bounds.getSouthWest().lng) / 180, size = this._map.getSize(), options = this.options, maxMeters = 0; if (size.x > 0) { maxMeters = dist * (options.maxWidth / size.x); } this._updateScales(options, maxMeters); }, _updateScales: function (options, maxMeters) { if (options.metric && maxMeters) { this._updateMetric(maxMeters); } if (options.imperial && maxMeters) { this._updateImperial(maxMeters); } }, _updateMetric: function (maxMeters) { var meters = this._getRoundNum(maxMeters); this._mScale.style.width = this._getScaleWidth(meters / maxMeters) + 'px'; this._mScale.innerHTML = meters < 1000 ? ''+meters + ' 米' : ''+(meters / 1000) + ' 公里'; }, _updateImperial: function (maxMeters) { var maxFeet = maxMeters * 3.2808399, scale = this._iScale, maxMiles, miles, feet; feet = this._getRoundNum(maxFeet); scale.style.width = this._getScaleWidth(feet / maxFeet) + 'px'; scale.innerHTML = ''+feet + ' 英尺'; }, _getScaleWidth: function (ratio) { return Math.round(this.options.maxWidth * ratio) - 10; }, _getRoundNum: function (num) { var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), d = num / pow10; d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1; return pow10 * d; } }); L.Map.addInitHook(function () { if (this.options.scaleControl) { this.scaleControl = new L.Control.Scale(); this.addControl(this.scaleControl); } }); L.control.scale = function (options) { return new L.Control.Scale(options); }; /** * 添加比例尺控件 * @param {[type]} options [description] * @return {[type]} [description] */ map2DViewer.setScaleControl = function(options) { var defaultData = { action: 'add', position: 'bottomleft', offset: [10, 10] } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.scaleControl = new L.Control.Scale({ position: defaultData.position, offset: defaultData.offset, metric: defaultData.metric, imperial: defaultData.imperial, }).addTo(this.map); return this.scaleControl; break; case 'remove': this.map.removeControl(this.scaleControl) break; } } L.Control.MeasureArea = L.Control.extend({ //是否初始化 _initialized: false, //统计 _mC: 0, //marker统计 AreaMarker: {}, //测 _measureAObjs: {}, //是否已经显示测面 isshowpolygonArea: false, //是否完成当前测绘 _finished: true, /** * 是否是新的测量事件 * @type {Boolean} * @default true * @private */ _isNewMeasure: true, options: { position: 'topright', autoZIndex: true, offset: [10, 40], background: "#000", color: "#fff", size: 14, closeButton: true, tips: $('
单击添加点,双击结束
') }, initialize: function (options) { L.setOptions(this, options); return this; }, onAdd: function (map) { this._map = map; this._addMeasureGroup(); this.start(); this._createControl(); this._map.on('measure-area-start', this.stop, this); switch (this.options.position) { case 'topleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; } return this._container; }, _addTip: function (param) { param.options.tips.appendTo(param._map.getContainer()); param._map.on('mousemove', param._onMovePoint, this); }, _createControl: function () { var _this = this; this._container = L.DomUtil.create('div', 'leaflet-bar leaflet-control-measure-area'); this._container.style.display = "none" var link = L.DomUtil.create('a', 'leaflet-control-measure-area-link', this._container); link.title = '测面积'; L.DomUtil.create('span', '', link); L.DomEvent .on(this._container, 'contextmenu', L.DomEvent.stopPropagation) .on(link, 'click', L.DomEvent.stopPropagation) .on(link, 'click', function () { if (!_this._finished) { _this._finished = true; L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; } else { _this._finished = false; L.DomUtil.addClass(_this._container, 'active'); _this._addMeasureGroup(); if (L.Browser.ie || L.Browser.firefox) { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur),auto'; } else { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur) 5 5,auto'; } } }) }, start: function () { var _this = this; if (!_this._finished) { _this._finished = true; //L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; } _this._finished = false; _this.isshowpolygonArea = false; _this._mC++ //L.DomUtil.addClass(_this._container, 'active'); _this._addTip(_this); _this._map.on('click', _this._onClickPoint, this); if (L.Browser.ie || L.Browser.firefox) { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur),auto'; } else { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur) 5 5,auto'; } }, _addMeasureGroup: function () { var _this = this; if (!_this._initialized) { _this._measureGroup = new L.featureGroup(); _this._measureGroup.addTo(_this._map); _this._initialized = true; } _this._map.doubleClickZoom.disable(); }, /** * 鼠标单击添加多边形的点 * @type {Function} * @param e * @private */ _onClickPoint: function (e) { var _this = this; e.latlng = L.Util.formatEarthLatLng(e.latlng); if (_this._isNewMeasure) { //_this._mC++; _this._measureAObjs[_this._mC] = new L.FeatureGroup(); _this._measureAObjs[_this._mC].addTo(_this._measureGroup); _this._measureAObjs[_this._mC].measurePoints = []; _this._measureAObjs[_this._mC].polygon = new L.polygon([ [0, 0], [0, 0], [0, 0] ], { fillColor: "blue", color: "#00b7ef", opacity: 0.8, weight: 3 }); _this._measureAObjs[_this._mC].polygon.addTo(_this._measureGroup); _this._measureAObjs[_this._mC].polygon.on('click', _this._onClickPoint, this); _this._isNewMeasure = false; } _this._measureAObjs[_this._mC].measurePoints.push(e.latlng); if (_this._measureAObjs[_this._mC].measurePoints.length > 1) { _this._drawPolygon(); _this._map.on('mousemove', _this._onMovePoint, this); } _this._buildMarker(e).addTo(_this._measureAObjs[_this._mC]); }, /** * 鼠标移动重绘多边形 //todo 这里应该 新建立一个临时 坐标组 * @type {Function} * @param e * @private */ _onMovePoint: function (e) { var _this = this; var wp = _this._map.latLngToContainerPoint(e.latlng) $(".measureArea_tips").css({ "left": wp.x + 20, 'top': wp.y + 10 }) if (Object.getOwnPropertyNames(_this._measureAObjs).length > 0) { if (_this._measureAObjs[_this._mC]) { if (_this._measureAObjs[_this._mC].measurePoints.length > 0) { var tempPoint = []; tempPoint = _this._measureAObjs[_this._mC].measurePoints.concat(); _this._measureAObjs[_this._mC].measurePoints.push(e.latlng); _this._drawPolygon(); _this._measureAObjs[_this._mC].measurePoints = tempPoint.concat(); } } } }, /** * 鼠标双击结束多边形点添加 * @type {Function} * @param e * @private */ _onFinishClick: function (e) { var _this = this; _this._map.off('mousemove', _this._onMovePoint, this); _this._measureAObjs[_this._mC].measurePoints.push(e.latlng); if (_this._measureAObjs[_this._mC].measurePoints.length > 1) { _this._drawPolygon(); } _this._measureAObjs[_this._mC].polygon.off('click', _this._onClickPoint, this); _this._isNewMeasure = true; if (!_this.isshowpolygonArea) { _this._countArea(e); _this.isshowpolygonArea = true; } _this._finished = true; _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; _this._restartMearing(); }, /** * [cleanAllMeasure description] * @return {[type]} [description] */ cleanAllMeasure: function () { var _this = this; for (var item in _this._measureAObjs) { _this.del(item); } }, /** * 重绘多边形 * @type {Function} * @private */ _drawPolygon: function () { var _this = this; _this._measureAObjs[_this._mC].polygon.setLatLngs(_this._measureAObjs[_this._mC].measurePoints); _this._measureAObjs[_this._mC].polygon.redraw(); }, /** * 创建一个marker 并返回该marker * @type {Function} * @param obj {Object} {latlng} * @returns {L.Marker} * @private */ _buildMarker: function (obj) { var _this = this; var marker = L.marker( obj.latlng, { icon: L.divIcon({ //className: 'my-div-icon1', //iconUrl: L.DefaultImagePath+'/icon-linePoint.png', iconSize: [5, 5] }) } ); marker.on('dblclick', function (e) { if (_this._measureAObjs[_this._mC].measurePoints.length < 2) { return false; } //与上一个点相同,测量完成 //if(e.latlng == _this._measureAObjs[_this._mC].measurePoints[_this._measureAObjs[_this._mC].measurePoints.length-1] ){ _this._onFinishClick({ latlng: _this._measureAObjs[_this._mC].measurePoints[_this._measureAObjs[_this._mC].measurePoints.length - 1] }); return false; //} }); _this.AreaMarker[_this._mC] = marker; return marker; }, /** * 测量面积 * @type {Function} * @param e * @private */ _countArea: function (e) { var _this = this; var areaLabel = L.DomUtil.create('span', 'area'); areaLabel.style.color = 'red'; areaLabel.style.fontWeight = 'bold'; areaLabel.innerHTML = '面积:' + _this._getArea(); //console.log(areaLabel.innerHTML); areaLabel.mid = _this._mC; //添加结束信息 var oLabelObjContent = L.DomUtil.create('div', 'measure-area-content'); var oLabelObj = L.DomUtil.create('p'); var delLabel = L.DomUtil.create('div', 'distance-ico-del'); //delLabel.innerHTML = '删除'; delLabel.lC = _this._mC; oLabelObj.lC = _this._mC; L.DomEvent.on(delLabel, 'click', function (e) { L.DomEvent.stopPropagation(e); _this.del(delLabel.lC) }); oLabelObj.appendChild(areaLabel); L.DomEvent.on(oLabelObj, 'dblclick', function () { L.DomEvent.stopPropagation(e); _this.del(oLabelObj.lC); }); oLabelObjContent.appendChild(oLabelObj); if (_this.options.closeButton) { oLabelObjContent.appendChild(delLabel); } L.marker(e.latlng, { icon: L.divIcon({ className: 'distance-div-icon' }) }).bindLabel(oLabelObjContent, { noHide: true, clickable: true, className: 'measure-distance-tip', offset: [0, 0] }).addTo(_this._measureAObjs[_this._mC]); _this.editerCSS(); }, /** * 修改测距样式 */ editerCSS: function () { var _this = this; $(".measure-area-content span").css({ "color": _this.options.color, }) $(".measure-area-content span").css({ "font-size": _this.options.font_size, }) $(".measure-area-content").css({ "background": _this.options.background }); }, /** * 合并样式 */ addCss: function (options) { var _this = this; _.merge(this.options, options); _this.editerCSS(); }, /** * 通过坐标点计算面积 * @type {Function} * @returns {Number} 面积 * @private */ _getArea: function () { var _this = this; var latLngs = _this._measureAObjs[_this._mC].measurePoints; var pointsCount = latLngs.length, area = 0.0, d2r = Math.PI / 180, p1, p2; if (pointsCount > 2) { for (var i = 0; i < pointsCount; i++) { p1 = latLngs[i]; p2 = latLngs[(i + 1) % pointsCount]; area += ((p2.lng - p1.lng) * d2r) * (2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r)); } area = area * 6378137.0 * 6378137.0 / 2.0; } area = Math.abs(area); if (area > 1000000) { area = (area * 0.000001).toFixed(2) + ' 平方公里'; } else { area = area.toFixed(2) + ' 米²'; } return area; }, _removeMeasureGroup: function () { var _this = this; _this._map.doubleClickZoom.enable(); $('#' + _this._map._container.id + ' .measureArea_tips').remove(); _this._map.off('click', _this._onClickPoint, this); }, /** * 重启测面 * [_restartMearing description] * @return {[type]} [description] */ _restartMearing: function () { var _this = this; _this.start(); }, /** * 删除对应iC的测距 * @type {Function} */ del: function (mC) { var _this = this; /* var event = event || window.event; L.DomEvent.stop(event);*/ _this._measureGroup.removeLayer(_this._measureAObjs[mC].polygon); _this._measureGroup.removeLayer(_this._measureAObjs[mC]); delete _this._measureAObjs[mC]; }, }); L.control.measureArea = function (options) { return new L.Control.MeasureArea(options); } /** * 测量工具 */ map2DViewer.setAreaToolStyle = function (options) { this.areaTool.addCss(options); } map2DViewer.areaToolFire = function (data) {}; map2DViewer.areaToolDelFire = function (data) {}; map2DViewer.measureArea = function (options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 40], background: "#fff", color: "#000", font_size: "14px", closeButton: true } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.areaTool = new L.Control.MeasureArea({ position: defaultData.position, offset: defaultData.offset, background: defaultData.background, color: defaultData.color, font_size: defaultData.font_size, closeButton: defaultData.closeButton }).addTo(this.map); this.map.on('measure-distance-result', map2DViewer.areaToolFire); this.map.on('measure-distance-delete', map2DViewer.areaToolDelFire); return this.areaTool; break; case 'restart': if (!this.areaTool) break; this.areaTool._restartMearing(); break; case 'clear': if (!this.areaTool) break; this.areaTool.cleanAllMeasure(); this.areaTool._removeMeasureGroup(); this.map.removeControl(this.areaTool); break; case 'remove': if (!this.areaTool) break; this.areaTool._removeMeasureGroup(); this.map.off('measure-distance-result', map2DViewer.areaToolFire); this.map.off('measure-distance-delete', map2DViewer.areaToolDelFire); break; } } L.Control.MeasureDistance = L.Control.extend({ //是否初始化 _initialized: false, //统计 _lC: 0, //测 _measureObjs: {}, //是否完成当前测绘 _finished: true, isNewElevation: true, options: { position: 'topright', autoZIndex: true, offset: [10, 10], background: "#000", color: "#fff", size: 14, closeButton: true, tips: $('
单击添加点,双击结束
') }, initialize: function (options) { L.setOptions(this, options); return this; }, onAdd: function (map) { this._map = map; this._addMeasureGroup(); this.start(); this._createControl(); this._map.on('measure-area-start', this.stop, this); switch (this.options.position) { case 'topleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; } return this._container; }, _addTip: function (param) { param.options.tips.appendTo(param._map.getContainer()); param._map.on('mousemove', param._onMoveLine, this); }, _createControl: function () { var _this = this; this._container = L.DomUtil.create('div', 'leaflet-bar leaflet-control-measure-distance'); this._container.style.display = "none" var link = L.DomUtil.create('a', 'leaflet-control-measure-distance-link', this._container); link.title = '两点测量距离'; L.DomUtil.create('span', '', link); L.DomEvent .on(this._container, 'contextmenu', L.DomEvent.stopPropagation) .on(link, 'click', L.DomEvent.stopPropagation) .on(link, 'click', function () { if (!_this._finished) { if (_this._measureObjs[_this._lC].distancePoints.length > 0) { _this._onFinishClick(); } _this._finished = true; L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); _this._map.fire('measure-distance-stop'); _this._map.getContainer().style.cursor = 'auto'; } else { _this._finished = false; L.DomUtil.addClass(_this._container, 'active'); _this._addMeasureGroup(); _this._map.fire('measure-distance-start'); if (L.Browser.ie || L.Browser.firefox) { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur),auto'; } else { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur) 5 5,auto'; } } }) }, start: function () { var _this = this; if (!_this._finished) { if (_this._measureObjs[_this._lC]) { if (_this._measureObjs[_this._lC].distancePoints) { if (_this._measureObjs[_this._lC].distancePoints.length > 0) { _this._onFinishClick(); } } } _this._finished = true; //L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); _this._map.fire('measure-distance-stop'); } _this._finished = false; _this._lC++; //L.DomUtil.addClass(_this._container, 'active'); _this._addTip(_this); _this._map.fire('measure-distance-start'); _this._map.on('click', _this._onClickPoint, this); if (L.Browser.ie || L.Browser.firefox) { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur),auto'; } else { _this._map.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-ruler.cur) 5 5,auto'; } _this._map.doubleClickZoom.disable(); }, stopMasuring: function () { var _this = this; _this._finished = true; _this._initialized = false; //L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); //_this._map.getContainer().style.cursor = 'auto'; }, stop: function () { var _this = this; if (!_this._finished) { if (_this._measureObjs[_this._lC].distancePoints.length > 0) { _this._onFinishClick(); } _this._finished = true; //L.DomUtil.removeClass(_this._container, 'active'); _this._removeMeasureGroup(); _this._map.fire('measure-distance-stop'); _this._map.getContainer().style.cursor = 'auto'; } }, measurePoints: function (startPoint, endPoint) { var _this = this; _this.start(); _this._onClickPoint({ latlng: startPoint }); _this._onClickPoint({ latlng: endPoint }); }, updatelC: function (lC, startPoint, endPoint) { var _this = this; _this._measureObjs[lC].distancePoints = [startPoint, endPoint]; _this._measureObjs[lC].linePoints = [startPoint, endPoint]; _this._measureObjs[lC].lineDistance = new L.LatLng(startPoint[0], startPoint[1]).distanceTo(new L.LatLng(endPoint[0], endPoint[1])); var newPos = _this._getCurvePoints([new L.LatLng(startPoint[0], startPoint[1]), new L.LatLng(endPoint[0], endPoint[1])]); _this._measureObjs[lC].polyLine.setLatLngs(newPos); _this._measureObjs[lC].polyLine.redraw(); _this._measureObjs[lC].resultMarker.setLatLng(new L.LatLng(endPoint[0], endPoint[1])); var lineDistance = _this._measureObjs[lC].lineDistance; var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; var pointAngle = L.Util.getAngleByLatLng(startPoint[1], startPoint[0], endPoint[1], endPoint[0]); pointAngle += '度'; //添加结束信息 var pointText = L.DomUtil.create('div', 'measure-distance-result-text'); pointText.innerHTML = lineDistanceStr + '
' + pointAngle; pointText.lC = _this._lC; L.DomEvent.on(pointText, 'dblclick', function (e) { L.DomEvent.stopPropagation(e); _this.del(pointText.lC) }); _this._measureObjs[lC].removeLayer(_this._measureObjs[lC].resultMarker); _this._measureObjs[lC].resultMarker = L.marker(endPoint, { icon: L.divIcon({ iconSize: [5, 5] }) }).bindLabel(pointText, { noHide: true, clickable: true, className: 'measure-distance-tip', offset: [0, 0] }).addTo(_this._measureObjs[lC]); _this._map.fire('measure-distance-result', { lC: lC, distance: lineDistanceStr, angle: pointAngle, distancePoints: _this._measureObjs[lC].distancePoints }); }, /** * 清除所有的量算 * @return {[type]} [description] */ cleanAllMeasure: function () { var _this = this; for (var item in _this._measureObjs) { _this.del(item); } }, _addMeasureGroup: function () { var _this = this; if (!_this._initialized) { _this._measureGroup = new L.featureGroup(); _this._measureGroup.addTo(_this._map); _this._initialized = true; } _this._map.doubleClickZoom.disable(); }, _removeMeasureGroup: function () { var _this = this; _this._map.getContainer().style.cursor = 'auto'; $('#' + _this._map._container.id + ' .measureDistance_tips').remove(); _this._map.off('mousemove', _this._onMoveLine, this); _this._map.off('click', _this._onClickPoint, this); }, _removeMeasure: function () { var _this = this; if (!_this._finished) { if (_this._measureObjs[_this._lC]) { if (_this._measureObjs[_this._lC].distancePoints) { if (_this._measureObjs[_this._lC].distancePoints.length > 0) { _this._onMoveLineRemove(); _this._onFinishClick({ latlng: _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 1] }); } } } _this._removeMeasureGroup(); _this._map.fire('measure-distance-stop'); } else { _this._removeMeasureGroup(); } }, _restartMearing: function () { var _this = this; _this.start() }, /** * 鼠标单击事件,如果是第一次,则设置为初始点 如果产生第二个点表示测量完成 * @param e * @returns {boolean} * @private */ _onClickPoint: function (e) { var _this = this; e.latlng = L.Util.formatEarthLatLng(e.latlng); if (_this.isNewElevation) { //_this._lC++; _this._measureObjs[_this._lC] = new L.FeatureGroup(); _this._measureObjs[_this._lC].tempLine = new L.Polyline([ [0, 0], [0, 0] ], { clickable: false, color: '#ff0000', weight: 2, opacity: 1 }).addTo(_this._measureObjs[_this._lC]); _this._measureObjs[_this._lC].addTo(_this._measureGroup); _this._measureObjs[_this._lC].distancePoints = []; _this._measureObjs[_this._lC].linePoints = []; _this._measureObjs[_this._lC].lineDistance = 0; _this.isNewElevation = false; } if (_this._measureObjs[_this._lC].distancePoints.length > 0) { _this.dblclickFirst = true; _this._measureObjs[_this._lC].distancePoints.push(e.latlng); var _sPoint = _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 2]; var qPoints = _this._getCurvePoints([_sPoint, e.latlng]); _this._measureObjs[_this._lC].linePoints.push(qPoints); var lineDistance = _sPoint.distanceTo(e.latlng) + _this._measureObjs[_this._lC].lineDistance; _this._measureObjs[_this._lC].lineDistance = lineDistance; var _lastPoint = _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 1]; _this._measureObjs[_this._lC].lineDistance = lineDistance; var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; var pointAngle = L.Util.getAngleByLatLng(_sPoint.lng, _sPoint.lat, _lastPoint.lng, _lastPoint.lat); //添加结束信息 var oLabelObj = L.DomUtil.create('div', 'measure-distance-content'); var delLabel = L.DomUtil.create('span', 'distance-ico-del'); var pointText = L.DomUtil.create('span', 'measure-distance-result-text'); delLabel.innerHTML = '删除'; delLabel.lC = _this._lC; L.DomEvent.on(delLabel, 'click', function (e) { L.DomEvent.stopPropagation(e); _this.del(delLabel.lC) }); pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'; pointText.lC = _this._lC; oLabelObj.appendChild(pointText); _this._measureObjs[_this._lC].resultMarker = _this._buildMarker(_lastPoint).bindLabel(oLabelObj, { noHide: true, clickable: true, className: 'measure-distance-tip', offset: [0, 0] }).addTo(_this._measureObjs[_this._lC]); } else { _this._measureObjs[_this._lC].resultMarker = _this._buildMarker(e.latlng).addTo(_this._measureObjs[_this._lC]); _this._measureObjs[_this._lC].distancePoints.push(e.latlng); _this._map.on('mousemove', _this._onMoveLine, this); } _this.editerCSS(); }, /** * 创建一个marker 并返回该marker * @type {Function} * @param obj {Object} {latlng} * @returns {L.Marker} * @private */ _buildMarker: function (obj) { var _this = this; var marker = L.marker( obj, { icon: L.divIcon({ iconSize: [5, 5] }) } ); marker.on('click', function (e) { if (_this._measureObjs[_this._lC].distancePoints.length < 2) { return false; } //与上一个点相同,测量完成 if (e.latlng == _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 1]) { _this._onFinishClick(e); return false; } }); return marker; }, /** * 给起始点和目的点的鼠标画线 * @type {Function} * @param e * @private */ _onMoveLine: function (e) { var _this = this; var wp = _this._map.latLngToContainerPoint(e.latlng) $(".measureDistance_tips").css({ "left": wp.x + 20, 'top': wp.y + 10 }) if (Object.getOwnPropertyNames(_this._measureObjs).length > 0) { if (_this._measureObjs[_this._lC]) { if (_this._measureObjs[_this._lC].distancePoints.length > 0) { var length = _this._measureObjs[_this._lC].distancePoints.length; var _startPoint = _this._measureObjs[_this._lC].distancePoints[length - 2]; var _endPoint = e.latlng; _this._drawLine(_startPoint, _endPoint); } } } }, /** * 更新画线 * @type {Function} * @param start {Object} 开始点 * @param end {Object} 结束点 * @private */ _drawLine: function (start, end) { var _this = this; _this._measureObjs[_this._lC].distancePoints.push(end); var newPos = _this._measureObjs[_this._lC].distancePoints; _this._measureObjs[_this._lC].tempLine.setLatLngs(newPos); _this._measureObjs[_this._lC].tempLine.redraw(); var length = _this._measureObjs[_this._lC].distancePoints.length; _this._measureObjs[_this._lC].distancePoints.splice(length - 1, 1); }, // 未完成绘制就取消绘制时,删除最后一段 _onMoveLineRemove: function () { var _this = this _this._measureObjs[_this._lC].tempLine.setLatLngs(_this._measureObjs[_this._lC].distancePoints); _this._measureObjs[_this._lC].tempLine.redraw(); }, _upDateLine: function (lC) { var _this = this; var linePoints = _this._measureObjs[_this._lC].linePoints; var allPoints = []; for (var i = 0, l = linePoints.length; i < l; i++) { allPoints = allPoints.concat(linePoints[i]); } if (_this._measureObjs[lC].polyLine) { _this._measureObjs[lC].polyLine.setLatLngs(allPoints); } else { _this._measureObjs[lC].polyLine = L.polyline(allPoints, { color: '#ff0000', weight: 2, opacity: 1, clickable: false }) .addTo(_this._measureObjs[lC]); } }, /** * 结束当前线条画线测距 * @param e * @private */ _onFinishClick: function (e) { var _this = this; _this._map.off('click', _this._onClickPoint, this); if (e && _this.dblclickFirst) { _this.dblclickFirst = false; _this._measureObjs[_this._lC].distancePoints.push(e.latlng); var _sPoint = _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 3]; var qPoints = _this._getCurvePoints([_sPoint, e.latlng]); _this._measureObjs[_this._lC].linePoints.push(qPoints); //var lineDistance = _sPoint.distanceTo(e.latlng) + _this._measureObjs[_this._lC].lineDistance; var lineDistance = _this._measureObjs[_this._lC].lineDistance; _this._measureObjs[_this._lC].lineDistance = lineDistance; var _lastPoint = _this._measureObjs[_this._lC].distancePoints[_this._measureObjs[_this._lC].distancePoints.length - 2]; _this._measureObjs[_this._lC].lineDistance = lineDistance; var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; var pointAngle = L.Util.getAngleByLatLng(_sPoint.lng, _sPoint.lat, _lastPoint.lng, _lastPoint.lat); //添加结束信息 var oLabelObj = L.DomUtil.create('div', 'measure-distance-content'); var delLabel = L.DomUtil.create('div', 'distance-ico-del'); var pointText = L.DomUtil.create('span', 'measure-distance-result-text'); //delLabel.innerHTML = '删除'; delLabel.lC = _this._lC; L.DomEvent.on(delLabel, 'click', function (e) { L.DomEvent.stopPropagation(e); _this.del(delLabel.lC) }); pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'; pointText.lC = _this._lC; L.DomEvent.on(pointText, 'dblclick', function (e) { L.DomEvent.stopPropagation(e); _this.del(pointText.lC) }); oLabelObj.appendChild(pointText); if (_this.options.closeButton) { oLabelObj.appendChild(delLabel); } _this._measureObjs[_this._lC].resultMarker.unbindLabel(); _this._measureObjs[_this._lC].resultMarker = L.marker(_lastPoint, { icon: L.divIcon({ iconSize: [5, 5] }) }).bindLabel(oLabelObj, { noHide: true, clickable: true, className: 'measure-distance-tip', offset: [0, 0] }).addTo(_this._measureObjs[_this._lC]); } _this._map.off('mousemove', _this._onMoveLine, this); $('#' + _this._map._container.id + ' .measureDistance_tips').remove(); _this.isNewElevation = true; _this.editerCSS(); _this.stopMasuring(); _this._restartMearing(); }, /** * 修改测距样式 */ editerCSS: function () { var _this = this; $(".measure-distance-content span").css({ "color": _this.options.color, }) $(".measure-distance-content span").css({ "font-size": _this.options.font_size, }) $(".measure-distance-content").css({ "background": _this.options.background }); }, /** * 合并样式 */ addCss: function (options) { var _this = this; _.merge(this.options, options); _this.editerCSS(); }, /** * 删除对应lC的测距 */ del: function (lC) { var _this = this; if (_this._measureObjs[lC]) { _this._measureGroup.removeLayer(_this._measureObjs[lC]); delete _this._measureObjs[lC]; _this._map.fire('measure-distance-delete', { lC: lC }); } }, /** * 获取弧线的节点坐标数组 * @type {Function} * @param points * @returns {Array} * @private */ _getCurvePoints: function (points) { var _this = this; var curvePoints = []; for (var i = 0; i < points.length - 1; i++) { if (points[i]['lat'] == points[i + 1]['lat'] && points[i]['lng'] == points[i + 1]['lng']) { curvePoints = curvePoints.concat(points[i]); } else { var p = _this._getCurve(points[i], points[i + 1], 20); if (p && p.length > 0) { curvePoints = curvePoints.concat(p); } } } return curvePoints; }, /** * 根据两点获取曲线坐标点数组 * @type {Function} * @param start {Object} 起点 * @param finish {Object} 终点 * @param segments {Number} 拐点数量 * @returns {*} * @private */ _getCurve: function (start, finish, segments) { var startlat = start.lat; var startlon = start.lng; var finishlat = finish.lat; var finishlon = finish.lng; var segments = segments; var curveAry = []; var lat1 = startlat * (Math.PI / 180); var lon1 = startlon * (Math.PI / 180); var lat2 = finishlat * (Math.PI / 180); var lon2 = finishlon * (Math.PI / 180); var d = 2 * Math.asin(Math.sqrt(Math.pow((Math.sin((lat1 - lat2) / 2)), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow((Math.sin((lon1 - lon2) / 2)), 2))); for (var n = 0; n < segments + 1; n++) { var f = (1 / segments) * n; var A = Math.sin((1 - f) * d) / Math.sin(d); var B = Math.sin(f * d) / Math.sin(d); var x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2); var y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2); var z = A * Math.sin(lat1) + B * Math.sin(lat2); var lat = Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))); var lon = Math.atan2(y, x); try { var temp = L.latLng(lat / (Math.PI / 180), lon / (Math.PI / 180)); curveAry.push(temp); } catch (e) { } } return curveAry; }, onRemove: function (map) { return this; } }); L.control.measureDistance = function (options) { return new L.Control.MeasureDistance(options); } /** * 测量工具 */ map2DViewer.distanceToolFire = function (data) {}; map2DViewer.distanceToolDelFire = function (data) {}; map2DViewer.measureDistance = function (options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10], background: "#fff", color: "#000", font_size: "14px", closeButton: true } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.distanceTool = new L.Control.MeasureDistance({ position: defaultData.position, offset: defaultData.offset, background: defaultData.background, color: defaultData.color, font_size: defaultData.font_size, closeButton: defaultData.closeButton }).addTo(this.map); this.map.on('measure-distance-result', map2DViewer.distanceToolFire); this.map.on('measure-distance-delete', map2DViewer.distanceToolDelFire); return this.distanceTool; break; case 'remove': if (!this.distanceTool) break; this.distanceTool._removeMeasure(); this.map.doubleClickZoom.enable(); this.map.off('measure-distance-result', map2DViewer.distanceToolFire); this.map.off('measure-distance-delete', map2DViewer.distanceToolDelFire); break; case 'clean': if (!this.distanceTool) break; this.distanceTool.cleanAllMeasure(); this.distanceTool._removeMeasure(); this.map.doubleClickZoom.enable(); this.map.removeControl(this.distanceTool); break; case 'restart': if (!this.distanceTool) break; this.distanceTool._restartMearing(); } } L.RadarCircleTimer = { count:0, start:0, speed:50, timer:null, initialize:false, init:function(options){ var _this = L.RadarCircleTimer; _this.count += 1; _this.map = options.map; if(_this.initialize){ return true; } _this.initialize = true; _this.timer = setInterval(function(){ _this.start += 5; _this.map.fire('radarCircleTimer') }, _this.speed); }, clear:function(){ var _this = L.RadarCircleTimer; _this.count -= 1; if(_this.count == 0){ _this.timer = clearInterval(_this.timer); _this.initialize = false; _this.start = 0; } } } L.RadarCircle = function(options){ this._featureGroup = new L.FeatureGroup(); this.options = { angle:30, //speed:50, center:[0,0], color:'#0033ff', opacity:0.5, fillColor:'#0033ff', weight:1, fillOpacity:0.1, radius:10000, //start:0 } L.setOptions(this, options); this.wCircle = new L.circle(this.options.center,this.options.radius,this.options).addTo(this._featureGroup); this.nCircle = new L.circle(this.options.center,this.options.radius,this.options).addTo(this._featureGroup); this.nCircle.setStyle({ fillOpacity:0.3, weight:0 }) var _this = this; L.RadarCircleTimer.init({map:this.options.map}) this.options.map.on('radarCircleTimer',function(){ _this.nCircle.setDirection(L.RadarCircleTimer.start,_this.options.angle) }) this._featureGroup.onRemove = function(){ L.RadarCircleTimer.clear(); L.FeatureGroup.prototype.onRemove.call(this, this._map); } this._featureGroup.bindPlabel = function(options){ _this.wCircle.bindPlabel(options); _this._featureGroup.plabel = _this.wCircle.plabel; } this._featureGroup.showPlabel = function(){ _this.wCircle.showPlabel(); } this._featureGroup.hidePlabel = function(){ _this.wCircle.hidePlabel(); } return this._featureGroup } L.radarCircle = function (options) { return new L.RadarCircle(options); }; /** * 设置雷达圆 * @param {[type]} options [description] */ map2DViewer.setRadarCircle = function(options) { var _this = map2DViewer; var defaultData = { action: 'add', options: { angle: 30, speed: 50, center: [0, 0], color: '#0033ff', opacity: 0.5, fillColor: '#0033ff', weight: 2, fillOpacity: 0.1, radius: 10000, map: _this.map } } _.merge(defaultData, options); switch (defaultData.action) { case 'add': var _guid = map23DControl.buildGuid('radarCircle'); var _radarCircle = L.radarCircle(defaultData.options).addTo(_this.map); _radarCircle.guid = _guid; _this.circles[_guid] = _radarCircle; return _radarCircle; break; case 'bringToFront': this.circles[defaultData.guid].bringToFront(); break; case 'bringToBack': this.circles[defaultData.guid].bringToBack(); break; case 'remove': this.map.removeLayer(this.circles[defaultData.guid]); break; } } L.Control.MiniMap = L.Control.extend({ options: { position: 'bottomright', zoomLevelOffset: -4, zoomLevelFixed: false, zoomAnimation: false, autoToggleDisplay: true, width: 150, height: 150, maxWidth: 300, minWidth: 150, offset:[10,10], aimingRectOptions: {color: "#ff7800", weight: 1, clickable: false}, shadowRectOptions: {color: "#00b7ef", weight: 1, clickable: false, opacity:0, fillOpacity:0} }, hideText: '隐藏', showText: '显示鹰眼地图', timeOut: null, //layer is the map layer to be shown in the minimap initialize: function (layer, options) { L.Util.setOptions(this, options); //Make sure the aiming rects are non-clickable even if the user tries to set them clickable (most likely by forgetting to specify them false) this.options.aimingRectOptions.clickable = false; this.options.shadowRectOptions.clickable = false; this._layer = layer; }, onAdd: function (map) { this._mainMap = map; //Creating the container and stopping events from spilling through to the main map. this._container = L.DomUtil.create('div', 'leaflet-control-minimap'); this._mapContainer = L.DomUtil.create('div', 'leaflet-control-minimap-wrap',this._container); this._container.style.width = '26px'; this._container.style.height = '26px'; L.DomEvent.disableClickPropagation(this._container); L.DomEvent.on(this._container, 'mousewheel', L.DomEvent.stopPropagation) .on(this._container,'contextmenu',L.DomEvent.stopPropagation); this._miniMap = new L.Map(this._mapContainer, { attributionControl: false, zoomControl: false, zoomAnimation: this.options.zoomAnimation, autoToggleDisplay: this.options.autoToggleDisplay, touchZoom: !this.options.zoomLevelFixed, scrollWheelZoom: !this.options.zoomLevelFixed, doubleClickZoom: !this.options.zoomLevelFixed, boxZoom: !this.options.zoomLevelFixed, crs: map.options.crs, inertia:false, fadeAnimation:false }); this._miniMap.addLayer(this._layer); //These bools are used to prevent infinite loops of the two maps notifying each other that they've moved. this._mainMapMoving = false; this._miniMapMoving = false; //Keep a record of this to prevent auto toggling when the user explicitly doesn't want it. this._minimized = true; this._addToggleButton(); this._miniMap.whenReady(L.Util.bind(function () { this._aimingRect = L.rectangle(this._mainMap.getBounds(), this.options.aimingRectOptions).addTo(this._miniMap); this._shadowRect = L.rectangle(this._mainMap.getBounds(), this.options.shadowRectOptions).addTo(this._miniMap); this._mainMap.on('moveend', this._onMainMapMoved, this); this._mainMap.on('move', this._onMainMapMoving, this); this._miniMap.on('movestart', this._onMiniMapMoveStarted, this); this._miniMap.on('move', this._onMiniMapMoving, this); this._miniMap.on('moveend', this._onMiniMapMoved, this); this._mainMap.on('resize',this._onMainResize,this); this._mainMap.on('hideMiniMap',this._minimize,this); this._mainMap.on('miniMap:changeLayer',this.changeLayer,this); }, this)); this._copanel = L.DomUtil.create('div','leaflet-control-minimap-copanel',this._container); this._l_1_btn = L.DomUtil.create('span','level_1_abtn active-1',this._copanel); this._l_1_btn.title = '1倍'; var _this = this; L.DomEvent.on(this._l_1_btn,'click',function(){ _this.options.zoomLevelOffset = -4; _this._miniMap.setView(_this._mainMap.getCenter(), _this._decideZoom(true)); L.DomUtil.addClass(_this._l_1_btn,'active-1'); L.DomUtil.removeClass(_this._l_2_btn,'active-2'); L.DomUtil.removeClass(_this._l_4_btn,'active-4'); }); this._l_2_btn = L.DomUtil.create('span','level_2_abtn',this._copanel); this._l_2_btn.title = '2倍'; L.DomEvent.on(this._l_2_btn,'click',function(){ _this.options.zoomLevelOffset = -6; _this._miniMap.setView(_this._mainMap.getCenter(), _this._decideZoom(true)); L.DomUtil.addClass(_this._l_2_btn,'active-2'); L.DomUtil.removeClass(_this._l_1_btn,'active-1'); L.DomUtil.removeClass(_this._l_4_btn,'active-4'); }); this._l_4_btn = L.DomUtil.create('span','level_4_abtn',this._copanel); this._l_4_btn.title = '4倍'; L.DomEvent.on(this._l_4_btn,'click',function(){ _this.options.zoomLevelOffset = -8; _this._miniMap.setView(_this._mainMap.getCenter(), _this._decideZoom(true)); L.DomUtil.addClass(_this._l_4_btn,'active-4'); L.DomUtil.removeClass(_this._l_2_btn,'active-2'); L.DomUtil.removeClass(_this._l_1_btn,'active-1'); }); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; this._toggleDisplayButton.style.left = '0px'; this._toggleDisplayButton.style.top = '0px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; this._toggleDisplayButton.style.right = '0px'; this._toggleDisplayButton.style.top = '0px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; this._toggleDisplayButton.style.bottom = '0px'; this._toggleDisplayButton.style.left = '0px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; this._toggleDisplayButton.style.bottom = '0px'; this._toggleDisplayButton.style.right = '0px'; break; } return this._container; }, addTo: function (map) { L.Control.prototype.addTo.call(this, map); //this._container.parentElement.style.marginRight = '28px'; //this._container.style.marginRight = '-28px'; return this; }, onRemove: function () { this._mainMap.off('moveend', this._onMainMapMoved, this); this._mainMap.off('move', this._onMainMapMoving, this); this._miniMap.off('moveend', this._onMiniMapMoved, this); this._mainMap.off('resize',this._onMainResize,this); this._mainMap.off('hideMiniMap',this._minimize,this); this._mainMap.off('miniMap:changeLayer',this.changeLayer,this); this._miniMap.removeLayer(this._layer); }, _onMainResize: function(){ if(this._minimized) { return false; }else { this._restore(); } }, changeLayer: function (layer) { this._miniMap.removeLayer(this._layer); this._layer = layer; this._miniMap.addLayer(this._layer); }, _addToggleButton: function () { this._toggleDisplayButton = this._createButton( '', this.showText, 'leaflet-control-minimap-toggle-display minimized', this._container, this._toggleDisplayButtonClicked, this); }, _createButton: function (html, title, className, container, fn, context) { var link = L.DomUtil.create('a', className, container); link.innerHTML = html; link.title = title; var stop = L.DomEvent.stopPropagation; L.DomEvent .on(link, 'click', stop) .on(link, 'mousedown', stop) .on(link, 'dblclick', stop) .on(link, 'click', L.DomEvent.preventDefault) .on(link, 'click', fn, context); return link; }, _toggleDisplayButtonClicked: function () { if (!this._minimized) { this._minimize(); this._toggleDisplayButton.title = this.showText; } else { this._restore(); this._toggleDisplayButton.title = this.hideText; } }, _setDisplay: function (minimize) { if (minimize != this._minimized) { if (!this._minimized) { this._minimize(); } else { this._restore(); } } }, _minimize: function () { // hide the minimap this._container.style.width = '26px'; this._container.style.height = '26px'; this._toggleDisplayButton.className += ' minimized'; //this._container.parentElement.style.marginRight = '28px'; //this._container.style.marginRight = '-28px'; this._copanel.style.display = 'none'; this._minimized = true; }, _restore: function () { var _this = this; this.options.width = parseInt(this._mainMap.getContainer().offsetWidth/this._mainMap.getContainer().offsetHeight*this.options.height); if(this.options.width > this.options.maxWidth){this.options.width = this.options.maxWidth} if(this.options.width < this.options.minWidth){this.options.width = this.options.minWidth} this._container.style.width = this.options.width + 'px'; this._container.style.height = this.options.height + 'px'; this._toggleDisplayButton.className = this._toggleDisplayButton.className .replace(/(?:^|\s)minimized(?!\S)/g, ''); clearTimeout(this.timeOut); this.timeOut = setTimeout(function(){ _this._miniMap.setView(_this._mainMap.getCenter(), _this._decideZoom(true),{animate:false,pan:{animate:false},zoom:{animate:false}}).invalidateSize(); }, 300); //this._container.parentElement.style.marginRight = this.options.width+2 + 'px'; //this._container.style.marginRight = -this.options.width-2 + 'px'; this._copanel.style.display = 'block'; this._minimized = false; }, _onMainMapMoved: function () { if (!this._miniMapMoving) { this._mainMapMoving = true; this._miniMap.setView(this._mainMap.getCenter(), this._decideZoom(true),{animate:false,pan:{animate:false},zoom:{animate:false}}); this._setDisplay(this._decideMinimized()); } else { this._miniMapMoving = false; } this._aimingRect.setBounds(this._mainMap.getBounds()); }, _onMainMapMoving: function () { this._aimingRect.setBounds(this._mainMap.getBounds()); }, _onMiniMapMoveStarted:function () { var lastAimingRect = this._aimingRect.getBounds(); var sw = this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest()); var ne = this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast()); this._lastAimingRectPosition = {sw:sw,ne:ne}; }, _onMiniMapMoving: function () { if (!this._mainMapMoving && this._lastAimingRectPosition) { this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw),this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne))); this._shadowRect.setStyle({opacity:1,fillOpacity:0.3}); } }, _onMiniMapMoved: function () { if (!this._mainMapMoving) { this._miniMapMoving = true; this._mainMap.setView(this._miniMap.getCenter(), this._decideZoom(false)); this._shadowRect.setStyle({opacity:0,fillOpacity:0}); } else { this._mainMapMoving = false; } }, _decideZoom: function (fromMaintoMini) { if (!this.options.zoomLevelFixed) { if (fromMaintoMini) return this._mainMap.getZoom() + this.options.zoomLevelOffset; else { var currentDiff = this._miniMap.getZoom() - this._mainMap.getZoom(); var proposedZoom = this._miniMap.getZoom() - this.options.zoomLevelOffset; var toRet; if (currentDiff > this.options.zoomLevelOffset && this._mainMap.getZoom() < this._miniMap.getMinZoom() - this.options.zoomLevelOffset) { //This means the miniMap is zoomed out to the minimum zoom level and can't zoom any more. if (this._miniMap.getZoom() > this._lastMiniMapZoom) { //This means the user is trying to zoom in by using the minimap, zoom the main map. toRet = this._mainMap.getZoom() + 1; //Also we cheat and zoom the minimap out again to keep it visually consistent. this._miniMap.setZoom(this._miniMap.getZoom() -1); } else { //Either the user is trying to zoom out past the mini map's min zoom or has just panned using it, we can't tell the difference. //Therefore, we ignore it! toRet = this._mainMap.getZoom(); } } else { //This is what happens in the majority of cases, and always if you configure the min levels + offset in a sane fashion. toRet = proposedZoom; } this._lastMiniMapZoom = this._miniMap.getZoom(); return toRet; } } else { if (fromMaintoMini) return this.options.zoomLevelFixed; else return this._mainMap.getZoom(); } }, _decideMinimized: function () { if (this._mainMap.getBounds().contains(this._miniMap.getBounds())) { return true; } return this._minimized; } }); L.Map.mergeOptions({ miniMapControl: false }); L.Map.addInitHook(function () { if (this.options.miniMapControl) { this.miniMapControl = (new L.Control.MiniMap()).addTo(this); } }); L.control.minimap = function (options) { return new L.Control.MiniMap(options); }; /** * 设置小地图 * @param {[type]} options [description] */ map2DViewer.setMiniMap = function(options) { var defaultData = { action: 'add', layer: L.tileLayer(map23DConfig.tileServerUrl + '/gm?l={z}&x={x}&y={y}', { minZoom: 1, maxZoom: 19, maxNativeZoom: 19 }), position: 'bottomright', offset: [10, 10], autoToggleDisplay: true, width: 150, //宽 height: 150, //高 maxWidth: 300, //最大宽 minWidth: 150 //最大高 } _.merge(defaultData, options); switch (defaultData.action) { case 'add': if (!this.miniMap) { this.miniMap = new L.Control.MiniMap(defaultData.layer, { position: defaultData.position, offset: defaultData.offset, autoToggleDisplay: defaultData.autoToggleDisplay, width: defaultData.width, height: defaultData.height, maxWidth: defaultData.maxWidth, minWidth: defaultData.minWidth }).addTo(this.map); } return this.miniMap; break; case 'remove': this.map.removeControl(this.miniMap); break; } } L.Control.DrawCircles = L.Control.extend({ //是否初始化 _initialized:false, //是否完成当前测绘 _finished:true, curcircles:null, circlesdata:{ startpoint:null, stoppoint:null, radius:null, }, options:{ position:'topright', autoZIndex:true, offset:[10,40] }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this._createControl(); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; } return this._container; }, _createControl:function(){ var _this = this; this._container = L.DomUtil.create('div','leaflet-bar leaflet-control-measure-drawcircles'); var link = L.DomUtil.create('a','leaflet-control-measure-drawcircles-link',this._container); link.title = '画圆'; var drawSpan = L.DomUtil.create('span','',link); drawSpan.innerHTML = "圆"; L.DomEvent .on(this._container,'contextmenu',L.DomEvent.stopPropagation) .on(link,'click', L.DomEvent.stopPropagation) .on(link,'click',function(){ _this.start(); }) }, start:function(){ var _this = this; L.DomUtil.addClass(_this._container,'active'); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur) 5 5,auto'; } map2DViewer.map.on('measure-drawCircle-result', map2DViewer.drawCircleResult); _this._map.dragging.disable(); _this._map.on("mousedown",_this.circleMousedown,this) .on("mouseup",_this.circleUp,this); }, //画圆结束 stop:function(){ var _this = this; map2DViewer.map.getContainer().style.cursor = 'auto'; _this._map.dragging.enable(); _this._map.off("mousedown",_this.circleMousedown,this) .off("mousemove",_this.circleMove,this) .off("mouseup",_this.circleUp,this); _this._map.fire('measure-drawCircle-result',_this.circlesdata); if(_this.curcircles){ _this._map.removeLayer(_this.curcircles); } }, circleUp:function(){ var _this = this; _this._map.dragging.enable(); _this._map.off("mousedown",_this.circleMousedown,this) .off("mousemove",_this.circleMove,this) .off("mouseup",_this.circleUp,this); _this._map.fire('measure-drawCircle-result',_this.circlesdata); _this._map.off('measure-drawCircle-result', map2DViewer.drawCircleResult); _this._map.removeLayer(_this.curcircles); map2DViewer.map.getContainer().style.cursor = 'auto'; }, circleMousedown:function(e){ var _this = this; _this.circlesdata.startpoint = [e.latlng.lat,e.latlng.lng]; _this.curcircles = L.circle( _this.circlesdata.startpoint, 0, { color: '#ff0000', weight: 3, fillColor: '#ff6600', opacity: 0.7, fillOpacity: 0.2, } ).addTo(_this._map); _this._map.on("mousemove",_this.circleMove,this); }, circleMove:function(e){ var _this = this; _this.circlesdata.stoppoint = [e.latlng.lat,e.latlng.lng]; var distance = new L.LatLng(_this.circlesdata.startpoint[1],_this.circlesdata.startpoint[0]).distanceTo(new L.LatLng(_this.circlesdata.stoppoint[1],_this.circlesdata.stoppoint[0])); _this.curcircles.setRadius(distance); _this.circlesdata.radius = distance; } }); L.control.drawcircles = function(options){ return new L.Control.DrawCircles(options); } //2D画圆 map2DViewer.drawCircleResult = function(data) {}; map2DViewer.drawCircle = function(options){ this.DrawCircles = new L.Control.DrawCircles({ position: 'topleft', autoZIndex:true, offset:[150,50] }).addTo(this.map); } map2DViewer.removeCircle = function(){ this.DrawCircles.stop(); this.map.removeControl(this.DrawCircles); } L.Control.Drawpolygon = L.Control.extend({ //是否初始化 _initialized:false, //统计 _pmC:0, //marker统计 DrawAreaMarker:{}, //测 _measureDrawObjs:{}, //是否完成当前测绘 _finished:true, /** * 是否是新的测量事件 * @type {Boolean} * @default true * @private */ _isNewMeasure:true, options:{ position:'topright', autoZIndex:true, offset:[10,40] }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this._createControl(); this._map.on('measure-drawpolygon-start',this.stop,this); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; } return this._container; }, _createControl:function(){ var _this = this; this._container = L.DomUtil.create('div','leaflet-bar leaflet-control-measure-drawpolygon'); var link = L.DomUtil.create('a','leaflet-control-measure-drawpolygon-link',this._container); link.title = '画面'; var drawSpan = L.DomUtil.create('span','',link); drawSpan.innerHTML = "面"; L.DomEvent .on(this._container,'contextmenu',L.DomEvent.stopPropagation) .on(link,'click', L.DomEvent.stopPropagation) .on(link,'click',function(){ _this.start(); }) }, _addMeasureGroup:function(){ var _this = this; if(!_this._initialized){ _this._measureGroup = new L.featureGroup(); _this._measureGroup.addTo(_this._map); _this._initialized = true; } _this._map.doubleClickZoom.disable(); _this._map.on('click',_this._onClickPoint,this); }, /** * 鼠标移动重绘多边形 //todo 这里应该 新建立一个临时 坐标组 * @type {Function} * @param e * @private */ _onMovePoint:function(e){ var _this = this; var tempPoint = []; tempPoint = _this._measureDrawObjs[_this._pmC].measurePoints.concat(); _this._measureDrawObjs[_this._pmC].measurePoints.push(e.latlng); _this._drawPolygon(); _this._measureDrawObjs[_this._pmC].measurePoints = tempPoint.concat(); }, /** * 鼠标单击添加多边形的点 * @type {Function} * @param e * @private */ _onClickPoint:function(e){ var _this = this; e.latlng = L.Util.formatEarthLatLng(e.latlng); if(_this._isNewMeasure){ _this._pmC++; _this._measureDrawObjs[_this._pmC] = new L.FeatureGroup(); _this._measureDrawObjs[_this._pmC].addTo(_this._measureGroup); _this._measureDrawObjs[_this._pmC].measurePoints = []; _this._measureDrawObjs[_this._pmC].polygon = new L.polygon([[0,0],[0,0],[0,0]],{fillColor:_this.options.properties.fillColor,color:_this.options.properties.color,opacity:_this.options.properties.opacity,weight:_this.options.properties.weight}); _this._measureDrawObjs[_this._pmC].polygon.addTo(_this._measureGroup); //_this._measureDrawObjs[_this._pmC].polygon.on('click',_this._onClickPoint,this); _this._isNewMeasure = false; } _this._measureDrawObjs[_this._pmC].measurePoints.push(e.latlng); if(_this._measureDrawObjs[_this._pmC].measurePoints.length > 1){ _this._drawPolygon(); _this._map.on('mousemove',_this._onMovePoint,this); } _this._buildMarker(e).addTo(_this._measureDrawObjs[_this._pmC]); }, /** * 鼠标双击结束多边形点添加 * @type {Function} * @param e * @private */ stop:function(e){ var _this = this; if(e){ _this._map.off('mousemove',_this._onMovePoint,this); _this._measureDrawObjs[_this._pmC].measurePoints.push(e.latlng); if(_this._measureDrawObjs[_this._pmC].measurePoints.length > 1){ _this._drawPolygon(); } _this._measureDrawObjs[_this._pmC].polygon.off('click',_this._onClickPoint,this); _this._isNewMeasure = true; _this._map.fire('measure-drawpolygon-result',{options:_this.options.properties,coordinates:_this._measureDrawObjs[_this._pmC].measurePoints}); _this._removeMeasureGroup(); _this._measureGroup.removeLayer(_this._measureDrawObjs[_this._pmC].polygon); _this._measureGroup.removeLayer(_this._measureDrawObjs[_this._pmC]); delete _this._measureDrawObjs[_this._pmC]; _this._finished = true; _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; }else{ if(_this._measureDrawObjs[_this._pmC]){ _this._map.off('mousemove',_this._onMovePoint,this); _this._removeMeasureGroup(); _this._isNewMeasure = true; _this._measureGroup.removeLayer(_this._measureDrawObjs[_this._pmC].polygon); _this._measureGroup.removeLayer(_this._measureDrawObjs[_this._pmC]); delete _this._measureDrawObjs[_this._pmC]; _this._finished = true; _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; }else{ _this._map.getContainer().style.cursor = 'auto'; } } _this._map.off('measure-drawpolygon-result', map2DViewer.drawpolygonFire); }, start:function(){ var _this = this; if(!_this._finished){ _this._finished = true; L.DomUtil.removeClass(_this._container,'active'); _this._removeMeasureGroup(); _this._map.getContainer().style.cursor = 'auto'; }else { _this._finished = false; L.DomUtil.addClass(_this._container,'active'); _this._addMeasureGroup(); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur) 5 5,auto'; } _this._map.on('measure-drawpolygon-result', map2DViewer.drawpolygonFire); } }, /** * 重绘多边形 * @type {Function} * @private */ _drawPolygon:function(){ var _this = this; _this._measureDrawObjs[_this._pmC].polygon.setLatLngs(_this._measureDrawObjs[_this._pmC].measurePoints); _this._measureDrawObjs[_this._pmC].polygon.redraw(); }, /** * 创建一个marker 并返回该marker * @type {Function} * @param obj {Object} {latlng} * @returns {L.Marker} * @private */ _buildMarker:function(obj){ var _this = this; var marker = new L.Marker( obj.latlng, {icon: L.divIcon({ //className: 'my-div-icon1', //iconUrl: L.DefaultImagePath+'/icon-linePoint.png', iconSize: [5, 5] })} ); marker.on('dblclick',function(e){ if(_this._measureDrawObjs[_this._pmC].measurePoints.length<2){ return false; } //与上一个点相同,测量完成 //if(e.latlng == _this._measureDrawObjs[_this._pmC].measurePoints[_this._measureDrawObjs[_this._pmC].measurePoints.length-1] ){ _this.stop({latlng:_this._measureDrawObjs[_this._pmC].measurePoints[_this._measureDrawObjs[_this._pmC].measurePoints.length-1]}); return false; //} }); return marker; }, _removeMeasureGroup:function(){ var _this = this; _this._map.doubleClickZoom.enable(); _this._map.off('click',_this._onClickPoint,this); }, }); L.control.drawpolygon = function(options){ return new L.Control.Drawpolygon(options); } // 地图上画面 map2DViewer.drawpolygonFire = function(data) {}; map2DViewer.setDrawPolygon = function(options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10], properties: { color: '#ff0000', weight: 3, fillColor: '#ff6600', opacity: 1, fillOpacity: 0.5 }, } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.drawpolygon = new L.Control.Drawpolygon({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); return this.drawpolygon; break; case 'add_start': this.drawpolygon = new L.Control.Drawpolygon({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); this.drawpolygon.start(); return this.drawpolygon; break; case 'stop': this.drawpolygon.stop(); case 'remove': this.map.removeControl(this.drawpolygon); break; } } L.Control.DrawPolyline = L.Control.extend({ //是否初始化 _initialized:false, //是否完成当前测绘 _finished:true, polylines:null, polylinesdata:{ latlng:[], _latlng:[] }, options:{ position:'topright', autoZIndex:true, offset:[10,40] }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this._createControl(); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; } return this._container; }, _createControl:function(){ var _this = this; this._container = L.DomUtil.create('div','leaflet-bar leaflet-control-polylines'); var link = L.DomUtil.create('a','leaflet-control-polylines-link',this._container); link.title = '画线'; var drawSpan = L.DomUtil.create('span','',link); drawSpan.innerHTML = "线"; L.DomEvent .on(this._container,'contextmenu',L.DomEvent.stopPropagation) .on(link,'click', L.DomEvent.stopPropagation) .on(link,'click',function(){ _this.start(); }) }, start:function(){ var _this = this; _this.polylinesdata.latlng = []; _this.polylinesdata._latlng = []; L.DomUtil.addClass(_this._container,'active'); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur) 5 5,auto'; } _this._map.doubleClickZoom.disable(); map2DViewer.map.on('measure-polylines-result', map2DViewer.drawpolylineFire); _this._map.on("click",_this.polylineMouseclick,this) .on("dblclick",_this.polylineDblclick,this); }, polylineDblclick:function(){ var _this = this; _this._map.doubleClickZoom.enable(); _this._map.off("click",_this.polylineMouseclick,this) .off("mousemove",_this.polylineMove,this) .off("dblclick",_this.polylineDblclick,this); _this._map.fire('measure-polylines-result',_this.polylinesdata._latlng); _this._map.off('measure-polylines-result', map2DViewer.drawPolylinesResult); _this._map.removeLayer(_this.polylines); map2DViewer.map.getContainer().style.cursor = 'auto'; }, stop:function(){ var _this = this; _this._map.doubleClickZoom.enable(); _this._map.off("click",_this.polylineMouseclick,this) .off("mousemove",_this.polylineMove,this) .off("dblclick",_this.polylineDblclick,this); _this._map.off('measure-polylines-result', map2DViewer.drawPolylinesResult); if(_this.polylines){ _this._map.removeLayer(_this.polylines); } map2DViewer.map.getContainer().style.cursor = 'auto'; }, polylineMouseclick:function(e){ var _this = this; _this.polylinesdata.latlng.push([e.latlng.lat,e.latlng.lng]); _this.polylinesdata._latlng.push([e.latlng.lng,e.latlng.lat]); if(_this.polylinesdata.latlng.length<2){ _this.polylines = L.polyline( _this.polylinesdata.latlng, { color: '#ff0000', weight: 3, opacity: 0.7, } ).addTo(_this._map); _this._map.on("mousemove",_this.polylineMove,this); }else{ _this.polylines.setLatLngs(_this.polylinesdata.latlng); } }, polylineMove:function(e){ var _this = this; var movelatlng = [e.latlng.lat,e.latlng.lng]; _this.polylinesdata.latlng.push(movelatlng); _this.polylinesdata._latlng.push([e.latlng.lng,e.latlng.lat]); _this.polylines.setLatLngs(_this.polylinesdata.latlng); var latlng_length = _this.polylinesdata.latlng.length-1; _this.polylinesdata.latlng.splice(latlng_length,1); _this.polylinesdata._latlng.splice(latlng_length,1); } }); L.control.drawpolyline = function(options){ return new L.Control.DrawPolyline(options); } //地图画线 map2DViewer.drawpolylineFire = function(data) {}; map2DViewer.setDrawPolyline = function(options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10], properties: { color: '#ff0000', weight: 3, opacity: 1, }, } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.drawpolyline = new L.Control.DrawPolyline({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); return this.drawpolyline; break; case 'add_start': this.drawpolyline = new L.Control.DrawPolyline({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); this.drawpolyline.start(); return this.drawpolyline; break; case 'remove': this.map.removeControl(this.drawpolyline); break; } } L.Control.DrawRectangle = L.Control.extend({ //是否初始化 _initialized:false, //是否完成当前测绘 _finished:true, drawrectangle:null, drawrectangledata:{ _latlng:[], bounds:[] }, options:{ position:'topright', autoZIndex:true, offset:[10,40] }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this._createControl(); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; } return this._container; }, _createControl:function(){ var _this = this; this._container = L.DomUtil.create('div','leaflet-bar leaflet-control-drawrectangle'); var link = L.DomUtil.create('a','leaflet-control-drawrectangle-link',this._container); link.title = '画矩形'; var drawSpan = L.DomUtil.create('span','',link); drawSpan.innerHTML = "矩"; L.DomEvent .on(this._container,'contextmenu',L.DomEvent.stopPropagation) .on(link,'click', L.DomEvent.stopPropagation) .on(link,'click',function(){ _this.start(); }) }, start:function(){ var _this = this; L.DomUtil.addClass(_this._container,'active'); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur) 5 5,auto'; } map2DViewer.map.on('measure-drawrectangle-result', map2DViewer.drawrectangleFire); _this._map.dragging.disable(); _this._map.on("mousedown",_this.rectangleMousedown,this) .on("mouseup",_this.rectangleUp,this); }, stop:function(){ var _this = this; _this._map.dragging.enable(); map2DViewer.map.getContainer().style.cursor = 'auto'; _this._map.off("mousedown",_this.rectangleMousedown,this) .off("mousemove",_this.rectangleMove,this) .off("mouseup",_this.rectangleUp,this); _this._map.off('measure-drawrectangle-result', map2DViewer.drawrectangleFire); if(_this.rectangle){ _this._map.removeLayer(_this.rectangle); } }, rectangleUp:function(){ var _this = this; _this._map.dragging.enable(); _this._map.off("mousedown",_this.rectangleMousedown,this) .off("mousemove",_this.rectangleMove,this) .off("mouseup",_this.rectangleUp,this); var recdata = _this.drawrectangledata.bounds; map2DViewer.map.getContainer().style.cursor = 'auto'; _this._map.removeLayer(_this.rectangle); if(recdata.length<2){ return; } _this.drawrectangledata._latlng = []; _this.drawrectangledata._latlng.push([recdata[0][1],recdata[0][0]]); _this.drawrectangledata._latlng.push([recdata[0][1],recdata[1][0]]); _this.drawrectangledata._latlng.push([recdata[1][1],recdata[1][0]]); _this.drawrectangledata._latlng.push([recdata[1][1],recdata[0][0]]); _this._map.fire('measure-drawrectangle-result',_this.drawrectangledata); _this._map.off('measure-drawrectangle-result', map2DViewer.drawrectangleFire); }, rectangleMousedown:function(e){ var _this = this; _this.drawrectangledata.bounds[0] = [e.latlng.lat,e.latlng.lng]; _this.rectangle = L.rectangle( _this.drawrectangledata.bounds, { color: '#ff0000', weight: 3, fillColor: '#ff6600', opacity: 0.7, fillOpacity: 0.2, } ).addTo(_this._map); _this._map.on("mousemove",_this.rectangleMove,this); }, rectangleMove:function(e){ var _this = this; _this.drawrectangledata.bounds[1] = [e.latlng.lat,e.latlng.lng]; _this.rectangle.setBounds(_this.drawrectangledata.bounds); } }); L.control.drawrectangle = function(options){ return new L.Control.DrawRectangle(options); } //地图画矩形 map2DViewer.drawrectangleFire = function(data) {}; map2DViewer.setDrawRectangle = function(options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10], properties: { color: '#ff0000', weight: 3, opacity: 1, }, } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.drawrectangle = new L.Control.DrawRectangle({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); return this.drawrectangle; break; case 'add_start': this.drawrectangle = new L.Control.DrawRectangle({ position: defaultData.position, offset: defaultData.offset, properties: defaultData.properties, }).addTo(this.map); this.drawrectangle.start(); return this.drawrectangle; break; case 'remove': this.drawrectangle.stop(); this.map.removeControl(this.drawrectangle); break; } } L.Control.AltitudeTool = L.Control.extend({ /** * 线条统计 * @type {Number} * @default 0 * @private */ _lC:0, /** * 量算集合 * @type {Object} * @default {} * @private */ _altitudeObjs:{}, /** * 点和线容器 * @type {Object} * @private */ _altitudeGroup: new L.FeatureGroup(), /** * 正在进行量算的 * @type {[type]} */ _curElevIC:null, /** * 是否是新的量算事件 * @type {Boolean} * @default true * @private */ _isNewaltitude:true, /** * 布局参数 * @type {Object} */ options:{ position:'topright', autoZIndex:true, offset:[10,10] }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this._altitudeGroup.addTo(this._map); this._createControl(); switch(this.options.position){ case 'topleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginTop = this.options.offset[1]+'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0]+'px'; this._container.style.marginBottom = this.options.offset[1]+'px'; break; } return this._container; }, _createControl:function(){ var _this = this; this._container = L.DomUtil.create('div','leaflet-bar leaflet-control-altitude-tool'); var link = L.DomUtil.create('a','leaflet-control-altitude-tool-link',this._container); link.title = '高程量算'; link.innerHTML = 'G' L.DomUtil.create('span','',link); L.DomEvent.on(this._container,'contextmenu',L.DomEvent.stopPropagation); L.DomEvent .on(link,'click', L.DomEvent.stopPropagation) .on(link,'click', L.DomEvent.preventDefault) .on(link,'click',function(){ if(!_this._isNewaltitude){ _this.remove(); }else { _this._isNewaltitude = false; L.DomUtil.addClass(_this._container,'active'); _this._map.doubleClickZoom.disable(); _this._map.on('click',_this._onClickPoint,_this); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-ruler.cur) 5 5,auto'; } } }) }, /** * 鼠标单击事件 * @param e * @returns {boolean} * @private */ _onClickPoint:function(e){ var _this = this; _this._lC++; _this._altitudeObjs[_this._lC] = new L.FeatureGroup(); _this._altitudeObjs[_this._lC].addTo(_this._altitudeGroup); //e.latlng _this._buildMarker({latlng: e.latlng}); }, /** * 删除对应iC的测距 */ del:function(event,iC){ var _this = this; var event = event || window.event; L.DomEvent.stop(event); _this._altitudeGroup.removeLayer(_this._altitudeObjs[iC]); delete _this._altitudeObjs[iC]; }, /** * 清除所有的测距 * @type {Function} */ clearAllelevation:function(){ var _this = this; _this._altitudeGroup.clearLayers(); _this._altitudeObjs = {}; }, /** * 进行剖面量算 * @param {[type]} event [description] * @param {[type]} iC [description] * @return {[type]} [description] */ run:function(latlng,callBackFunc){ var _this = this; var url = map23DConfig.altitudeServerUrl+'/terrain/elevation'; var ajaxData = { lat:latlng.lat, lon:latlng.lng, zoom:_this._map.getZoom(), delta_zoom:0 }; $.ajax({ type:"post", dataType:'json', data:ajaxData, url:url, success:function(data){ callBackFunc(data); } }); }, /** * 创建一个marker 并返回该marker * @param obj * @returns {L.Marker} * @private */ _buildMarker:function(obj){ var _this = this; _this.run(obj.latlng,function(data){ var altitudeLabel = L.DomUtil.create('span','altitude-span'); altitudeLabel.lid = _this._lC altitudeLabel.style.color = 'red'; altitudeLabel.innerHTML = '高程:'+data.data+ '米'; L.DomEvent.on(altitudeLabel,'dblclick',function(e){ L.DomEvent.stopPropagation(e); var lid = e.target? e.target.lid: e.srcElement.lid; _this.del(e,lid) }); new L.Marker( obj.latlng, {icon: L.icon({ iconUrl: L.DefaultImagePath+'/icon-linePoint.png', iconSize: [15, 15], iconAnchor: [7, 7], popupAnchor: [0, -7] }), clickable:false } ).bindLabel(altitudeLabel,{ noHide:true, }).addTo(_this._altitudeObjs[_this._lC]); }); _this.remove(); }, /** * 计算完成 * @type {Function} */ remove:function(){ // var _this = this; // _this._map.doubleClickZoom.enable(); // _this._map.getContainer().style.cursor = 'auto'; // _this._isNewaltitude = true; // _this._map.off('click',_this._onClickPoint,this); // L.DomUtil.removeClass(_this._container,'active'); } }); L.control.altitudeTool = function(options){ return new L.Control.AltitudeTool(options); } /** * 高程量算 */ map2DViewer.altitudeToolsFire = function(data) {}; map2DViewer.setAltitudeTools = function(options) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10] } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.altitudeTools = new L.Control.AltitudeTool({ position: defaultData.position, offset: defaultData.offset }).addTo(this.map); this.map.on('measure-distance-result', map2DViewer.altitudeToolsFire); return this.altitudeTools; break; case 'remove': this.altitudeTools.cleanAllMeasure(); this.map.removeControl(this.altitudeTools); this.map.off('measure-distance-result', map2DViewer.altitudeToolsFire); break; } }; L.MagnifyingGlass = L.Layer.extend({ options: { radius: 150, zoomOffset: 3, layers: [], fixedPosition: false, latLng: [0, 0], fixedZoom: -1 }, initialize: function(options) { L.Util.setOptions(this, options); this._fixedZoom = (this.options.fixedZoom != -1); this._mainMap = null; this._glassMap = null; }, getMap: function() { return this._glassMap; }, _createMiniMap: function(elt) { return new L.Map(elt, { //layers: this.options.layers, zoom: this._getZoom(), maxZoom: this._mainMap.getMaxZoom(), minZoom: this._mainMap.getMinZoom(), crs: this._mainMap.options.crs, fadeAnimation: false, attributionControl: false, zoomControl: false, boxZoom: false, touchZoom: false, scrollWheelZoom: false, doubleClickZoom: false, dragging: false, keyboard: false, }); }, _getZoom: function() { return (this._fixedZoom) ? this.options.fixedZoom : this._mainMap.getZoom() + this.options.zoomOffset; }, _updateZoom: function() { this._glassMap.setZoom(this._getZoom()); }, setRadius: function(radius) { this.options.radius = radius; if (this._wrapperElt) { this._wrapperElt.style.width = this.options.radius * 2 + 'px'; this._wrapperElt.style.height = this.options.radius * 2 + 'px'; } }, setLatLng: function(latLng) { this.options.latLng = latLng; this._update(latLng); }, _updateFromMouse: function(evt) { this._update(evt.latlng, evt.layerPoint); }, _updateFixed: function() { this._update(this.options.latLng); }, _update: function(latLng, layerPoint) { // update mini map view, forcing no animation this._glassMap.setView(latLng, this._getZoom(), { pan: { animate: false } }); // update the layer element position on the main map, // using the one provided or reprojecting it layerPoint = layerPoint || this._mainMap.latLngToLayerPoint(latLng); this._wrapperElt.style.left = layerPoint.x - this.options.radius + 'px'; this._wrapperElt.style.top = layerPoint.y - this.options.radius + 'px'; }, /** As defined by ILayer */ onAdd: function(map) { this._mainMap = map; // create a wrapper element and a container for the map inside it this._wrapperElt = L.DomUtil.create('div', 'leaflet-magnifying-glass'); var glassMapEltPicture = L.DomUtil.create('div', 'leaflet-magnifying-glass-webkitPicture', this._wrapperElt); var glassMapElt = L.DomUtil.create('div', 'leaflet-magnifying-glass-webkit', glassMapEltPicture); // Webkit border-radius clipping workaround (see CSS) if (L.Browser.webkit || L.Browser.ie) L.DomEvent.on(glassMapElt, 'dblclick', L.DomEvent.stopPropagation) .on(glassMapElt, 'dblclick', function() { map2DViewer.map.removeLayer(map2DViewer.magnifyingGlass); delete map2DViewer.magnifyingGlass; }); // build the map this._glassMap = this._createMiniMap(glassMapElt); if (L.Browser.ie || L.Browser.firefox) { this._glassMap.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-none.cur),auto'; } else { this._glassMap.getContainer().style.cursor = 'url(' + L.DefaultImagePath + '/cur-none.cur) 5 5,auto'; } // forward some DOM events as Leaflet events L.DomEvent.addListener(this._wrapperElt, 'click', this._fireClick, this); var opts = this.options; this.setRadius(opts.radius); this.setLatLng(opts.latLng); this._glassMap.whenReady(function() { if (opts.fixedPosition) { this._mainMap.on('zoomend', this._updateFixed, this); L.DomUtil.addClass(this._wrapperElt, ('leaflet-zoom-hide')); } else { this._mainMap.on('mousemove', this._updateFromMouse, this); if (!this._fixedZoom) { this._mainMap.on('zoomend', this._updateZoom, this); } } }, this); // add the magnifying glass as a layer to the top-most pane map.getPanes().popupPane.appendChild(this._wrapperElt); // needed after the element has been added, otherwise tile loading is messy this._glassMap.invalidateSize(); var group = L.featureGroup(); map2DViewer.groups['glassGroup'] = group; group.addTo(this._glassMap); map2DViewer.magnifyingGlass.addLayersGlass(); return this; }, //图层加载 addLayersGlass: function() { $.each(map2DViewer.map._layers, function(name, item) { if (item.hasOwnProperty('guid') && item.hasOwnProperty('_url')) { var itemLayer = L.tileLayer(item._url, { minZoom: item.options.minZoom, maxZoom: item.options.maxZoom, maxNativeZoom: item.options.maxZoom }); itemLayer.addTo(map2DViewer.magnifyingGlass._glassMap); if (item.guid === "tileLayer2DDefault") { itemLayer.bringToBack() } if (item.guid === "oasaMapLayer") { itemLayer.bringToFront() } } }) }, _fireClick: function(domMouseEvt) { this.fire('click', domMouseEvt); L.DomEvent.stopPropagation(domMouseEvt); }, MagnifyingGlassFunction: function(defaultData) { map2DViewer.magnifyingGlass._glassMap.on('moveend', function() { map2DViewer.groups.glassGroup.clearLayers(); $.each(map23DData, function(name, item) { switch (name) { case 'polylines': return map2DViewer.magnifyingGlass.addpolylinesOnGlass(item, defaultData); break; case 'polygons': return map2DViewer.magnifyingGlass.addpolygonsOnGlass(item, defaultData); break; case 'markers': return map2DViewer.magnifyingGlass.addmarkersOnGlass(item, defaultData); break; case 'circles': return map2DViewer.magnifyingGlass.addcirclesOnGlass(item, defaultData);; break; case 'circleMarkers': return map2DViewer.magnifyingGlass.addcircleMarkersOnGlass(item, defaultData);; break; } }) }) }, addcircleMarkersOnGlass: function(item, defaultData) { $.each(item, function(name, curt) { if(curt.groupId){ if(!map23DData.groups[curt.groupId].visible2D){ return false; } } if(curt.visible2D){ var GlassBounds = map2DViewer.magnifyingGlass.magnifyingGlassbouns(map2DViewer.magnifyingGlass._glassMap.getBounds()); var judgeAddGlass = map2DViewer.magnifyingGlass.pointInPolygon(curt.geojson.geometry.coordinates, GlassBounds); if (judgeAddGlass) { var circleMarker = L.circleMarker( map23DUtil.latLngsToReverse(curt.geojson.geometry.coordinates), { radius: curt.geojson.properties.radius, color: curt.geojson.properties.color, weight: curt.geojson.properties.weight + defaultData.widthOffset, fillColor: curt.geojson.properties.fillColor, opacity: curt.geojson.properties.opacity, fillOpacity: curt.geojson.properties.fillOpacity, title: curt.geojson.properties.title } ); circleMarker.addTo(map2DViewer.groups['glassGroup']); if (map2DViewer.circleMarkers[name].hasOwnProperty('plabel')) { if (map2DViewer.circleMarkers[name].plabel._isOpen) { circleMarker.bindPlabel(map2DViewer.circleMarkers[name].plabel._content, map2DViewer.circleMarkers[name].plabel.options); circleMarker.showPlabel(); } } } } }) }, addcirclesOnGlass: function(item, defaultData) { $.each(item, function(name, curt) { if(curt.groupId){ if(!map23DData.groups[curt.groupId].visible2D){ return false; } } if(curt.visible2D){ var circle = L.circle( map23DUtil.latLngsToReverse(curt.geojson.geometry.coordinates), curt.geojson.properties.radius, { color: curt.geojson.properties.color, weight: curt.geojson.properties.weight + defaultData.widthOffset, fillColor: curt.geojson.properties.fillColor, opacity: curt.geojson.properties.opacity, fillOpacity: curt.geojson.properties.fillOpacity, title: curt.geojson.properties.title } ); circle.addTo(map2DViewer.groups['glassGroup']); } }) }, addpolygonsOnGlass: function(item, defaultData) { $.each(item, function(name, curt) { if(curt.groupId){ if(!map23DData.groups[curt.groupId].visible2D){ return false; } } if(curt.visible2D){ var polygon = L.polygon( map23DUtil.latLngsToReverse(curt.geojson.geometry.coordinates[0]), { color: curt.geojson.properties.color, weight: curt.geojson.properties.weight + defaultData.widthOffset, fillColor: curt.geojson.properties.fillColor, opacity: curt.geojson.properties.opacity, fillOpacity: curt.geojson.properties.fillOpacity, title: curt.geojson.properties.title } ); polygon.addTo(map2DViewer.groups['glassGroup']); } }) }, //marker icon glassmarker_icon: function(markerData) { if (markerData.geojson.properties.fontIcon) { var icon_html = '
' + markerData.geojson.properties.fontIcon + '
'; } else { var icon_html = ''; } return icon_html; }, addmarkersOnGlass: function(item, defaultData) { $.each(item, function(name, curt) { if(curt.groupId){ if(!map23DData.groups[curt.groupId].visible2D){ return false; } } if(curt.visible2D){ var GlassBounds = map2DViewer.magnifyingGlass.magnifyingGlassbouns(map2DViewer.magnifyingGlass._glassMap.getBounds()); var judgeAddGlass = map2DViewer.magnifyingGlass.pointInPolygon(curt.geojson.geometry.coordinates, GlassBounds); if (judgeAddGlass) { var icon_html = map2DViewer.magnifyingGlass.glassmarker_icon(curt); var setDivIcon = L.divIcon({ className: 'rorate_div', html: icon_html, iconAnchor: curt.geojson.properties.iconAnchor, iconSize: curt.geojson.properties.iconSize, popupAnchor: curt.geojson.properties.popupAnchor }); var marker = L.marker( map23DUtil.latLngsToReverse(curt.geojson.geometry.coordinates), { icon: setDivIcon, title: curt.geojson.properties.title } ) marker.addTo(map2DViewer.groups['glassGroup']); if (map2DViewer.markers[name].hasOwnProperty('plabel')) { if (map2DViewer.markers[name].plabel._isOpen) { marker.bindPlabel(map2DViewer.markers[name].plabel._content, map2DViewer.markers[name].plabel.options); marker.showPlabel(); } } } } }) }, addpolylinesOnGlass: function(item, defaultData) { $.each(item, function(name, curt) { if(curt.groupId){ if(!map23DData.groups[curt.groupId].visible2D){ return false; } } if(curt.visible2D){ var polyline = L.polyline( map23DUtil.latLngsToReverse(curt.geojson.geometry.coordinates), { color: curt.geojson.properties.color, weight: curt.geojson.properties.weight + defaultData.widthOffset, opacity: curt.geojson.properties.opacity, title: curt.geojson.properties.title, dashArray: curt.geojson.properties.dashArray, lineJoin: 'miter', lineCap: 'butt' } ); polyline.addTo(map2DViewer.groups['glassGroup']); } }) }, //创建放大镜范围 magnifyingGlassbouns: function(bouns) { var ne = [bouns._northEast.lng, bouns._northEast.lat]; var se = [bouns._northEast.lng, bouns._southWest.lat]; var sw = [bouns._southWest.lng, bouns._southWest.lat]; var nw = [bouns._southWest.lng, bouns._northEast.lat]; var mabounds = [ne, se, sw, nw, ne]; return mabounds; }, //判断坐标位置是否在放大镜中 pointInPolygon: function(point, vs) { var x = point[0], y = point[1]; var inside = false; for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) { var xi = vs[i][0], yi = vs[i][1]; var xj = vs[j][0], yj = vs[j][1]; var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; }, /** As defined by ILayer */ onRemove: function(map) { map.off('viewreset', this._updateFixed, this); map.off('mousemove', this._updateFromMouse, this); map.off('zoomend', this._updateZoom, this); for (var i = 0, l = this.options.layers.length; i < l; i++) { this._glassMap.removeLayer(this.options.layers[i]); } this._glassMap.remove(); L.DomEvent.removeListener(this._wrapperElt, 'click', this._fireClick); map.getPanes().popupPane.removeChild(this._wrapperElt); this._mainMap = null; return this; } }); L.magnifyingGlass = function(options) { return new L.MagnifyingGlass(options); }; /** * 放大镜 * @param {[type]} options [description] * @return {[type]} [description] */ //调用示例 map23DControl.show2DMagnifyingGlass(true) map2DViewer.setMagnifyingGlass = function(options) { var defaultData = { action: 'add', zoomOffset: 3, widthOffset:5 } _.merge(defaultData, options); switch (defaultData.action) { case 'add': if (!this.magnifyingGlass) { this.magnifyingGlass = L.magnifyingGlass(defaultData) } if (!this.map.hasLayer(this.magnifyingGlass)) { this.map.addLayer(this.magnifyingGlass); } map2DViewer.magnifyingGlass.MagnifyingGlassFunction(defaultData); return this.magnifyingGlass; break; case 'remove': if (this.map.hasLayer(this.magnifyingGlass)) { this.map.removeLayer(this.magnifyingGlass); this.magnifyingGlass = null; delete this.magnifyingGlass; } break; } } var ScrollBar = { timelineHtml: '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ //'

'+ '
'+ '
', value: 0, maxValue: 200, currentX: 0, init:function(options){ ScrollBar.value = 0; ScrollBar.maxValue = options.maxLength; $('
  • '+ScrollBar.timelineHtml+'
  • ').appendTo($("#TimeLineContainer ul")); //$("#"+options.id+" .scrollBarTxt").html(options); ScrollBar.Initialize(options); }, Initialize: function(options) { if (ScrollBar.value > ScrollBar.maxValue) { alert("给定当前值大于了最大值"); return; } ScrollBar.GetValue(); $(""+options.id+" .scroll_Track").css("width", ScrollBar.currentX + 2 + "px"); $(""+options.id+" .scroll_Thumb").css("margin-left", ScrollBar.currentX + "px"); ScrollBar.Value(); //$(""+options.id+" .scrollBarTxt").html(ScrollBar.value + "/" + ScrollBar.maxValue); }, Value: function() { var valite = false; var currentValue; $("#TimeLineContainer .scroll_Thumb").unbind('mousedown').bind('mousedown',function() { valite = true; $('#TimeLineContainer li').unbind('mousemove').bind('mousemove',function(event) { var _this = $(this); if (valite == false) return; var changeX = event.clientX - ScrollBar.currentX; currentValue = changeX - ScrollBar.currentX-$(".Demo").offset().left; $("#"+_this[0].id+" .scroll_Thumb").css("left", currentValue -32 + "px"); $("#"+_this[0].id+" .scroll_Track").css("width", currentValue + "px"); if ((currentValue ) >= $(".Demo").width()) { $("#"+_this[0].id+" .scroll_Thumb").css("left", $(".Demo").width() -32 + "px"); $("#"+_this[0].id+" .scroll_Track").css("width", $(".Demo").width() + "px"); ScrollBar.value = map2DViewer.markers[_this[0].id]._latlngs.length; } else if (currentValue <= 0) { $("#"+_this[0].id+" .scroll_Thumb").css("margin-left", "0px"); $("#"+_this[0].id+" .scroll_Track").css("width", "0px"); } else { ScrollBar.value = Math.round(map2DViewer.markers[_this[0].id]._latlngs.length * (currentValue / $(".Demo").width())); } //$("#"+_this[0].id+" .scrollBarTxt").html(ScrollBar.value + "/" + ScrollBar.maxValue); if(ScrollBar.value >= map2DViewer.markers[_this[0].id]._latlngs.length){ ScrollBar.value = map2DViewer.markers[_this[0].id]._latlngs.length - 1; map23DData.timeLineData[_this[0].id]={'_i':ScrollBar.value}; map2DViewer.markers[_this[0].id].setLatLng(map2DViewer.markers[_this[0].id]._latlngs[ScrollBar.value]); map2DViewer.markers[_this[0].id]['_i'] = 0; if(window.marker_Animate){ map2DViewer.markers[_this[0].id].stop(); map2DViewer.markers[_this[0].id].start(); } }else{ map23DData.timeLineData[_this[0].id]={'_i':ScrollBar.value}; map2DViewer.markers[_this[0].id].setLatLng(map2DViewer.markers[_this[0].id]._latlngs[ScrollBar.value]); map2DViewer.markers[_this[0].id]['_i'] = ScrollBar.value; if(window.marker_Animate){ map2DViewer.markers[_this[0].id].stop(); map2DViewer.markers[_this[0].id].start(); } } }); }); $('#TimeLineContainer li').unbind('mouseleave').bind('mouseleave',function() { var _this = $(this); ScrollBar.value = Math.round(ScrollBar.maxValue * (currentValue / $(".Demo").width())); valite = false; if (ScrollBar.value >= ScrollBar.maxValue) ScrollBar.value = ScrollBar.maxValue; if (ScrollBar.value <= 0) ScrollBar.value = 0; //$("#"+_this[0].id+" .scrollBarTxt").html(ScrollBar.value + "/" + ScrollBar.maxValue); }); $('#TimeLineContainer li').unbind('mouseup').bind('mouseup',function() { var _this = $(this); ScrollBar.value = Math.round(ScrollBar.maxValue * (currentValue / $(".Demo").width())); valite = false; if (ScrollBar.value >= ScrollBar.maxValue) ScrollBar.value = ScrollBar.maxValue; if (ScrollBar.value <= 0) ScrollBar.value = 0; //$("#"+_this[0].id+" .scrollBarTxt").html(ScrollBar.value + "/" + ScrollBar.maxValue); }); }, GetValue: function() { ScrollBar.currentX = $(".Demo").width() * (ScrollBar.value / ScrollBar.maxValue); }, //设置路径回放位置 setRoutBcakView:function(options){ var marker_guid = map2DViewer.routeBackGroup[options.guid].marker; map2DViewer.markers[marker_guid]['_i'] = options.step; var maxlength = $("#"+marker_guid+" .Main").width(); var curlength = Math.round((options.step/(map2DViewer.markers[marker_guid]._latlngs.length-1))*maxlength); $("#"+marker_guid+" .scroll_Thumb").css("left", curlength -32+ "px"); $("#"+marker_guid+" .scroll_Track").css("width", curlength + "px"); } } /** * 路径回放 */ map2DViewer.routeBackGroup = {}; var hasRB = false; map2DViewer.routeBack = function(markerOptions, lineOptions) { var RBkey = map23DControl.buildGuid('routeBackGroup'); map2DViewer.routeBackGroup[RBkey] = { polyline: null, marker: null, isEnd:false }; map2DViewer.routeBackGroup[RBkey].polyline = map23DControl.polyline({ action: 'add', geojson: lineOptions.geojson, }); map2DViewer.routeBackGroup[RBkey].marker = map23DControl.marker({ action: 'add', animate: true, RBkey: RBkey, geojson: markerOptions.geojson }) map2DViewer.markers[map2DViewer.routeBackGroup[RBkey].marker].start(); var maxLength = lineOptions.geojson.properties.times.length; var ScrollBarOptions = { 'id': map2DViewer.routeBackGroup[RBkey].marker, 'maxLength': maxLength }; ScrollBar.init(ScrollBarOptions); if(!hasRB){ PubSub.subscribe('payBackEnd',map2DViewer.paybackGOn); PubSub.subscribe('curMarkerOptions',map2DViewer.changeCurOptions); //this.map.on('zoomend',function(e){ /*$.each(map2DViewer.routeBackGroup,function(i,t){ var animate_data = map2DViewer.routeBackGroup[i].marker; if(map23DData.markers[animate_data].visible2D){ var _this = map2DViewer.markers[animate_data]; if (L.DomUtil.TRANSITION) { if (_this._icon) { _this._icon.style[L.DomUtil.TRANSITION] = ('all ' + 1 + 'ms linear'); } if (_this._shadow) { _this._shadow.style[L.DomUtil.TRANSITION] = 'all ' + 1 + 'ms linear'; } } if(_this._i < _this._latlngs.length){ _this.setLatLng(_this._latlngs[_this._i]); _this['_i'] = _this._i; } } }) */ //}) hasRB = true; } return RBkey; }; map2DViewer.paybackGOn = function(msg,guid){}; map2DViewer.changeCurOptions = function(msg,guid){ } /** * 暂停回放 */ map2DViewer.stopRouteBack = function(RBkey) { var animate_data = map2DViewer.routeBackGroup[RBkey].marker; map2DViewer.markers[animate_data].stop(); }; /** * 继续回放 */ map2DViewer.goonRouteBack = function(RBkey) { var animate_data = map2DViewer.routeBackGroup[RBkey].marker; map2DViewer.markers[animate_data].stop(); map2DViewer.markers[animate_data].start(); }; /** * 重放路径回放 */ map2DViewer.reStartRouteBack = function(RBkey){ var animate_data = map2DViewer.routeBackGroup[RBkey].marker; map2DViewer.markers[animate_data].restart(); } /** * 移除回放 */ map2DViewer.removeRouteBack = function(RBkey) { var animate_data = map2DViewer.routeBackGroup[RBkey]; delete map2DViewer.routeBackGroup[RBkey]; map23DControl.marker({ action: 'remove', guid: animate_data.marker }); map23DControl.polyline({ action: 'remove', guid: animate_data.polyline }); }; /* (c) 2014, Vladimir Agafonkin simpleheat, a tiny JavaScript library for drawing heatmaps with Canvas https://github.com/mourner/simpleheat */ !function(){"use strict";function t(i){return this instanceof t?(this._canvas=i="string"==typeof i?document.getElementById(i):i,this._ctx=i.getContext("2d"),this._width=i.width,this._height=i.height,this._max=1,void this.clear()):new t(i)}t.prototype={defaultRadius:25,defaultGradient:{.4:"blue",.6:"cyan",.7:"lime",.8:"yellow",1:"red"},data:function(t,i){return this._data=t,this},max:function(t){return this._max=t,this},add:function(t){return this._data.push(t),this},clear:function(){return this._data=[],this},radius:function(t,i){i=i||15;var a=this._circle=document.createElement("canvas"),s=a.getContext("2d"),e=this._r=t+i;return a.width=a.height=2*e,s.shadowOffsetX=s.shadowOffsetY=200,s.shadowBlur=i,s.shadowColor="black",s.beginPath(),s.arc(e-200,e-200,t,0,2*Math.PI,!0),s.closePath(),s.fill(),this},gradient:function(t){var i=document.createElement("canvas"),a=i.getContext("2d"),s=a.createLinearGradient(0,0,0,256);i.width=1,i.height=256;for(var e in t)s.addColorStop(e,t[e]);return a.fillStyle=s,a.fillRect(0,0,1,256),this._grad=a.getImageData(0,0,1,256).data,this},draw:function(t){this._circle||this.radius(this.defaultRadius),this._grad||this.gradient(this.defaultGradient);var i=this._ctx;i.clearRect(0,0,this._width,this._height);for(var a,s=0,e=this._data.length;e>s;s++)a=this._data[s],i.globalAlpha=Math.max(a[2]/this._max,t||.05),i.drawImage(this._circle,a[0]-this._r,a[1]-this._r);var n=i.getImageData(0,0,this._width,this._height);return this._colorize(n.data,this._grad),i.putImageData(n,0,0),this},_colorize:function(t,i){for(var a,s=3,e=t.length;e>s;s+=4)a=4*t[s],a&&(t[s-3]=i[a],t[s-2]=i[a+1],t[s-1]=i[a+2])}},window.simpleheat=t}(),/* (c) 2014, Vladimir Agafonkin Leaflet.heat, a tiny and fast heatmap plugin for Leaflet. https://github.com/Leaflet/Leaflet.heat */ L.HeatLayer=(L.Layer?L.Layer:L.Class).extend({initialize:function(t,i){this._latlngs=t,L.setOptions(this,i)},setLatLngs:function(t){return this._latlngs=t,this.redraw()},addLatLng:function(t){return this._latlngs.push(t),this.redraw()},setOptions:function(t){return L.setOptions(this,t),this._heat&&this._updateOptions(),this.redraw()},redraw:function(){return!this._heat||this._frame||this._map._animating||(this._frame=L.Util.requestAnimFrame(this._redraw,this)),this},onAdd:function(t){this._map=t,this._canvas||this._initCanvas(),t._panes.overlayPane.appendChild(this._canvas),t.on("moveend",this._reset,this),t.options.zoomAnimation&&L.Browser.any3d&&t.on("zoomanim",this._animateZoom,this),this._reset()},onRemove:function(t){t.getPanes().overlayPane.removeChild(this._canvas),t.off("moveend",this._reset,this),t.options.zoomAnimation&&t.off("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},_initCanvas:function(){var t=this._canvas=L.DomUtil.create("canvas","leaflet-heatmap-layer leaflet-layer"),i=L.DomUtil.testProp(["transformOrigin","WebkitTransformOrigin","msTransformOrigin"]);t.style[i]="50% 50%";var a=this._map.getSize();t.width=a.x,t.height=a.y;var s=this._map.options.zoomAnimation&&L.Browser.any3d;L.DomUtil.addClass(t,"leaflet-zoom-"+(s?"animated":"hide")),this._heat=simpleheat(t),this._updateOptions()},_updateOptions:function(){this._heat.radius(this.options.radius||this._heat.defaultRadius,this.options.blur),this.options.gradient&&this._heat.gradient(this.options.gradient),this.options.max&&this._heat.max(this.options.max)},_reset:function(){var t=this._map.containerPointToLayerPoint([0,0]);L.DomUtil.setPosition(this._canvas,t);var i=this._map.getSize();this._heat._width!==i.x&&(this._canvas.width=this._heat._width=i.x),this._heat._height!==i.y&&(this._canvas.height=this._heat._height=i.y),this._redraw()},_redraw:function(){var t,i,a,s,e,n,h,o,r,d=[],_=this._heat._r,l=this._map.getSize(),m=new L.Bounds(L.point([-_,-_]),l.add([_,_])),c=void 0===this.options.max?1:this.options.max,u=void 0===this.options.maxZoom?this._map.getMaxZoom():this.options.maxZoom,f=1/Math.pow(2,Math.max(0,Math.min(u-this._map.getZoom(),12))),g=_/2,p=[],v=this._map._getMapPanePos(),w=v.x%g,y=v.y%g;for(t=0,i=this._latlngs.length;i>t;t++)if(a=this._map.latLngToContainerPoint(this._latlngs[t]),m.contains(a)){e=Math.floor((a.x-w)/g)+2,n=Math.floor((a.y-y)/g)+2;var x=void 0!==this._latlngs[t].alt?this._latlngs[t].alt:void 0!==this._latlngs[t][2]?+this._latlngs[t][2]:1;r=x*f,p[n]=p[n]||[],s=p[n][e],s?(s[0]=(s[0]*s[2]+a.x*r)/(s[2]+r),s[1]=(s[1]*s[2]+a.y*r)/(s[2]+r),s[2]+=r):p[n][e]=[a.x,a.y,r]}for(t=0,i=p.length;i>t;t++)if(p[t])for(h=0,o=p[t].length;o>h;h++)s=p[t][h],s&&d.push([Math.round(s[0]),Math.round(s[1]),Math.min(s[2],c)]);this._heat.data(d).draw(this.options.minOpacity),this._frame=null},_animateZoom:function(t){var i=this._map.getZoomScale(t.zoom),a=this._map._getCenterOffset(t.center)._multiplyBy(-i).subtract(this._map._getMapPanePos());L.DomUtil.setTransform?L.DomUtil.setTransform(this._canvas,a,i):this._canvas.style[L.DomUtil.TRANSFORM]=L.DomUtil.getTranslateString(a)+" scale("+i+")"}}),L.heatLayer=function(t,i){return new L.HeatLayer(t,i)}; L.Control.MouseBlur = L.Control.extend({ //是否初始化 _initialized:false, options:{ weight:1, color:'#000000', }, linesData:{ lineX:null, lineY:null }, initialize:function(options){ L.setOptions(this, options); return this; }, onAdd:function(map){ this._map = map; this.craetMouse(); this._map.on('mousemove',this.mouseMove,this); this._container = L.DomUtil.create('div','leaflet-bar leaflet-cross'); this._container.style.display = 'none'; return this._container; }, craetMouse:function(){ var _this = this; _this.printBounds = _this._map.getBounds(); _this.center = _this._map.getCenter(); _this.linesData.lineX = [[_this.center.lat,_this.printBounds._northEast.lng],[_this.center.lat,_this.printBounds._southWest.lng]]; _this.linesData.lineY = [[_this.printBounds._northEast.lat,_this.center.lng],[_this.printBounds._southWest.lat,_this.center.lng]]; _this.crosslineX = L.polyline( _this.linesData.lineX, _this.options ).addTo(_this._map); _this.crosslineY = L.polyline( _this.linesData.lineY, _this.options ).addTo(_this._map); if(L.Browser.ie || L.Browser.firefox){ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-none.cur),auto'; }else{ _this._map.getContainer().style.cursor = 'url('+L.DefaultImagePath+'/cur-none.cur) 5 5,auto'; } }, mouseMove:function(e){ var _this = this; _this.center = e.latlng; _this.linesData.lineX = [[_this.center.lat,180],[_this.center.lat,-180]]; _this.linesData.lineY = [[90,_this.center.lng],[-90,_this.center.lng]]; _this.crosslineX.setLatLngs(_this.linesData.lineX); _this.crosslineY.setLatLngs(_this.linesData.lineY); }, onRemove: function (map) { var _this = this; map.off('mousemove', this.mouseMove, this); this._map.removeLayer(this.crosslineX); this._map.removeLayer(this.crosslineY); _this._map.getContainer().style.cursor = ''; } }); L.control.mouseblur = function(options){ return new L.Control.MouseBlur(options); } /** * 添加鼠标十字线 * @param {[type]} options [description] */ map2DViewer.setMouseBlur = function(options) { var _this = map2DViewer; var defaultData = { color:'#000000', weight:1 } _.merge(defaultData, options); switch (defaultData.action) { case 'add': this.mouseBlur = new L.Control.MouseBlur(defaultData).addTo(this.map); return this.mouseBlur; break; case 'remove': this.map.removeControl(this.mouseBlur) break; } }