放棄百度,選擇更高效的檢索方式,提供工做效率javascript
效果圖html
很是感謝如下兩位做者的分享,也許已經找不到原做者。java
方案一:http://www.cnblogs.com/siempre1091/p/3997847.html數組
方案二:http://shuaike.iteye.com/blog/1187603ide
兩種方法分別採用徹底不一樣的方式實現,各有各的優點和缺陷。函數
方案一的實現方法較爲正常,可以正常使用工具
現附上方案一的整理源碼:this
package com.esri.viewer.tool.measure { import com.esri.ags.Graphic; import com.esri.ags.Map; import com.esri.ags.Units; import com.esri.ags.events.DrawEvent; import com.esri.ags.events.MapMouseEvent; import com.esri.ags.geometry.MapPoint; import com.esri.ags.geometry.Polygon; import com.esri.ags.geometry.Polyline; import com.esri.ags.layers.GraphicsLayer; import com.esri.ags.symbols.CompositeSymbol; import com.esri.ags.symbols.PictureMarkerSymbol; import com.esri.ags.symbols.SimpleLineSymbol; import com.esri.ags.symbols.SimpleMarkerSymbol; import com.esri.ags.symbols.TextSymbol; import com.esri.ags.tools.DrawTool; import com.esri.ags.utils.GeometryUtil; import com.esri.viewer.AppEvent; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.utils.Timer; import mx.collections.ArrayCollection; public class Measure { private var lineSymbol:SimpleLineSymbol; private var markerSymbol:SimpleMarkerSymbol; private var normalLabel:TextSymbol; private var endLabel:TextSymbol; private var deleteLabel:CompositeSymbol; private var drawLayer:GraphicsLayer; private var drawTool:DrawTool; private var isActive:Boolean; private var map:Map; //測距須要的幾個全局變量 //節點數組,這是實際用於計算距離的值 private var polyArray:Array; //用這個來標識是否應放下終點註記 private var isDraw:Boolean; //當前節點,每次mapClick刷新 private var currentPoint:MapPoint; //每條測距線的標識碼 private var sierialId:int = 0; private var areaGraphic:Graphic; private var isMeausreLine:Boolean = true; public function set IsActive(value:Boolean):void { isActive = value; if(isActive) { InitDraw(); } else { StopDraw(); } } public function get IsActive():Boolean { return isActive; } public function Measure(_map:Map) { map = _map; } private function InitDraw():void { //對於這樣的類,我很喜歡使用一個函數來完成GraphicsLayer的初始化和添加 drawLayer = AddGraphicLayer("measure"); //紅色細實線做爲測距線 lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,0xff0000,1,2); //小紅圈做爲節點 markerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE,8,0xffffff,1,0,0,0,lineSymbol); //起點和中繼點的註記符號,把用於顯示的文字綁定於TEXT上 normalLabel = new TextSymbol(); normalLabel.background = true; normalLabel.backgroundColor = 0xffffff; normalLabel.border = true; normalLabel.borderColor = 0x666666; normalLabel.color = 0x666666; normalLabel.placement = TextSymbol.PLACEMENT_START; normalLabel.xoffset = 10; normalLabel.textAttribute = "TEXT"; //終點的註記符號,一樣綁定在Text上 endLabel = new TextSymbol(); endLabel.background = true; endLabel.backgroundColor = 0xffffff; endLabel.border = true; endLabel.borderColor = 0xff0000; endLabel.color = 0x000000; endLabel.yoffset = 20; endLabel.textAttribute = "TEXT"; //刪除按鈕的符號,用一個組合符號把按鈕圖標放在一個正方形的框裏 deleteLabel = new CompositeSymbol(); var picSymbol:PictureMarkerSymbol = new PictureMarkerSymbol("assets/images/delete.png",16,16,15,-15); var borderSymbol:SimpleMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE,18,0xffffff,1,15,-15,0, new SimpleLineSymbol("solid",0xff0000,1,1)); deleteLabel.symbols=[borderSymbol,picSymbol]; //drawTool初始化只需注意一下咱們額外須要一個DRAW_START事件 drawTool = new DrawTool(map); drawTool.showDrawTips = false; drawTool.graphicsLayer = drawLayer; drawTool.lineSymbol = lineSymbol; drawTool.addEventListener(DrawEvent.DRAW_END,drawEnd); drawTool.addEventListener(DrawEvent.DRAW_START,drawStart); } //中止繪製時把繪圖圖層移除 private function StopDraw():void { if(map.getLayer("measure")) map.removeLayer(map.getLayer("measure")); drawTool.deactivate(); map.removeEventListener(MapMouseEvent.MAP_CLICK,mapClicked); polyArray = []; } //這是我很是喜歡的添加圖層函數,初始化、添加、賦值所有打包 //若是map裏有這個ID的圖層,就直接放回這個圖層 //若是map裏尚未,就new一個,放進去再返回這個圖層 private function AddGraphicLayer(layerid:String):GraphicsLayer { var glayer:GraphicsLayer; if(map.getLayer(layerid)!=null) { glayer = map.getLayer(layerid) as GraphicsLayer; } else { glayer = new GraphicsLayer(); glayer.id = layerid; map.addLayer(glayer); } return glayer; } //鼠標點擊measure按鈕,就執行這個函數開始測距 public function MeasureDistance():void { isMeausreLine = true; drawTool.activate(DrawTool.POLYLINE); drawTool.showDrawTips = true; drawTool.toolTipStartAndLetGo="點擊開始測距"; drawTool.toolTipPolyEnd="雙擊結束測距"; polyArray = new Array(); isDraw = true; map.panEnabled = false; map.addEventListener(MapMouseEvent.MAP_CLICK,mapClicked); } //鼠標點擊measure按鈕,就執行這個函數開始測距 public function MeasureDistanceArea():void { isMeausreLine = false; drawTool.activate(DrawTool.POLYGON); drawTool.showDrawTips = true; drawTool.toolTipStartAndLetGo="點擊開始量面"; drawTool.toolTipPolyEnd="雙擊結束量面"; polyArray = new Array(); isDraw = true; map.panEnabled = false; map.addEventListener(MapMouseEvent.MAP_CLICK,mapClicked); } //開始繪圖時自增一下當前的測距線標識碼 private function drawStart(event:DrawEvent):void { sierialId+=1; } //結束繪圖時的操做,AppEvent是一個事件,目的在於通知頁面測距完成了 private function drawEnd(event:DrawEvent):void { event.graphic.attributes = {id:sierialId}; drawTool.deactivate(); map.removeEventListener(MapMouseEvent.MAP_CLICK,mapClicked); map.panEnabled = true; isDraw = false; AppEvent.dispatch(AppEvent.MEASURE_FINISH); } //繪圖過程當中點擊地圖時記錄節點,注意每次記錄節點的過程用timer來控制 private function mapClicked(event:MapMouseEvent):void { currentPoint = event.mapPoint; //0.2秒的延遲,放置節點紅圈干擾drawTool var timer:Timer = new Timer(200); timer.addEventListener(TimerEvent.TIMER,timerEnd); timer.start(); } //timer裏實際進行的就是距離計算和放置註記等複雜的工做 private function timerEnd(e:TimerEvent):void { (e.currentTarget as Timer).stop(); //拿到節點,必定要new啊,必定要new一個,不然會很悲劇 var mp:MapPoint = new MapPoint(currentPoint.x,currentPoint.y,currentPoint.spatialReference); //往用於計算的邏輯數組裏塞入這個節點 polyArray.push(mp); //若是還在繪圖當中的話,那就是放妖放下中繼點或起點 if(isDraw) { //這樣是起點,記得用TEXT來傳遞標註文字,用id來傳遞標識碼 if(polyArray.length == 1) { drawLayer.add(new Graphic(mp,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:"起點",id:sierialId})); } //這樣就是中繼點,這是要計算距離的,注意計算時,我把polyArray實時轉換成了Polygon else { var lenghthStr:String = LenghthCaculator(new Polyline([polyArray],map.spatialReference)); drawLayer.add(new Graphic(mp,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:lenghthStr,id:sierialId})); } } //結束繪圖的話,就放終點 else { var deleteGr:Graphic; if(!isMeausreLine) { // 倒數第二點 var totallenghth:String = LenghthCaculator(new Polyline([polyArray],map.spatialReference)); drawLayer.add(new Graphic(mp,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:totallenghth,id:sierialId})); // 最後點,首位鏈接 polyArray.push(polyArray[0]); totallenghth = LenghthCaculator(new Polyline([polyArray],map.spatialReference)); drawLayer.add(new Graphic(polyArray[0],new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總長:"+totallenghth,id:sierialId})); // 計算面積 var tmpPolygon:Polygon = new Polygon([polyArray],map.spatialReference); var totalAreaStr:String = AreaCaculator(tmpPolygon); var markpoint:MapPoint = tmpPolygon.extent.center; drawLayer.add(new Graphic(markpoint,new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總面積:"+totalAreaStr,id:sierialId})); deleteGr = new Graphic(markpoint,deleteLabel,{id:sierialId}); }else{ var totallenghthStr:String = LenghthCaculator(new Polyline([polyArray],map.spatialReference)); drawLayer.add(new Graphic(mp,new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總長:"+totallenghthStr,id:sierialId})); deleteGr = new Graphic(mp,deleteLabel,{id:sierialId}); } //這是要放刪除按鈕,就是一個graphic啦,可是須要綁定一下Click事件。 deleteGr.toolTip = "刪除"; deleteGr.buttonMode = true; deleteGr.addEventListener(MouseEvent.CLICK,deleteHandler); drawLayer.add(deleteGr); } } //刪除的時候根據標識碼來刪除對應測距線中的元素 private function deleteHandler(event:MouseEvent):void { var id:int = (event.currentTarget as Graphic).attributes.id; var deletArray:Array = new Array(); for each(var line:Graphic in drawLayer.graphicProvider) { if(line.attributes.id == id) { deletArray.push(line); } } for each(var graphic:Graphic in deletArray) { drawLayer.remove(graphic); } //若是刪除的是最後一條測距線,就把這個測距圖層移除,而且讓測距功能關閉,減小資源佔用 if((drawLayer.graphicProvider as ArrayCollection).length == 0) this.IsActive = false; } //距離計算,注意使用的函數,另外距離比較短的時候單位能夠變爲米 private function LenghthCaculator(polyline:Polyline):String { var lenghth:Number = GeometryUtil.geodesicLengths([polyline],Units.METERS)[0]; if(lenghth>1000) return (lenghth/1000).toFixed(2)+"千米"; else return lenghth.toFixed(2)+"米"; } private function AreaCaculator(polygon:Polygon):String { var lenghth:Number = GeometryUtil.geodesicAreas([polygon],Units.SQUARE_METERS)[0]; if(lenghth>=1000000) return (lenghth/1000000).toFixed(2)+"平方公里"; else return lenghth.toFixed(2)+"平方米"; } } }
調用方式以下:url
Measure measureTool = new Measure(map) if(!measureTool.IsActive) measureTool.IsActive = true; measureTool.MeasureDistance();
方案一的缺陷是長度計算方式只支持地理座標,不支持平面座標。在釋放操做過程當中沒有進行徹底釋放內容。spa
方案二源碼以下
package com.esri.viewer.tool { import com.esri.ags.Map; import com.esri.ags.events.MapMouseEvent; import com.esri.ags.tasks.GeometryServiceSingleton; import com.esri.viewer.AppEvent; import com.esri.viewer.ViewerContainer; import com.esri.viewer.tool.measure.MeasureLengths; import flash.events.MouseEvent; import flash.utils.clearInterval; import flash.utils.setInterval; public class ToolWidget { public static var interval:Number=0; public static var measureGrArr:Array=[]; //地圖上繪製的測量線的圖層 private var measureLength:MeasureLengths; private var map:Map; // 當前執行的工具 private var tool:String; public function ToolWidget(map:Map) { this.map=map; } public function activeTool(tool:String, status:String):void { this.tool = tool; switch (this.tool) { case ViewerContainer.MEASURE_LENGTH: { lengthHandler(); break; } } } private function lengthHandler():void { //setMapAction(DrawTool.POLYLINE, LocaleResource.strings("iframe_label_length"), null, _compute.drawEndHandler);_compute.mapclick _compute.measureFinish measureLength=new MeasureLengths(GeometryServiceSingleton.instance.url, map); map.addEventListener(MapMouseEvent.MAP_CLICK, clickLength); map.addEventListener(MouseEvent.DOUBLE_CLICK, doubleclickLength); map.doubleClickEnabled=true; map.openHandCursorVisible=false; } //消除單擊和雙擊使勁啊的衝突 private function clickLength(event:MouseEvent):void { clearInterval(interval); interval=setInterval(measureLength.mapclick, 200, event); } //消除單擊和雙擊使勁啊的衝突 private function doubleclickLength(event:MouseEvent):void { clearInterval(interval); measureLength.measureFinish(event); measureLengthFinish(null); } //取測量點完畢 private function measureLengthFinish(event:AppEvent):void { //取消測量點擊的雙擊單擊事件 map.removeEventListener(MapMouseEvent.MAP_CLICK, clickLength); map.removeEventListener(MouseEvent.DOUBLE_CLICK, doubleclickLength); } } }
package com.esri.viewer.tool.measure { import flash.events.Event; import mx.containers.Canvas; import mx.events.FlexEvent; import spark.components.Label; public class Infosym extends Canvas { public function Infosym() { super(); this.addEventListener(FlexEvent.CREATION_COMPLETE, init); } private function init(event:Event):void { var label:Label=new Label(); this.addChild(label); label.height=16; label.setStyle("borderColor", "red"); label.setStyle("color", "red"); label.setStyle("textAlign", "center"); label.text=super.data.toString() + "千米"; } } }
package com.esri.viewer.tool.measure { import flash.events.Event; import mx.containers.Canvas; import mx.events.FlexEvent; import spark.components.Label; public class InfosymStart extends Canvas { public function InfosymStart() { super(); this.addEventListener(FlexEvent.CREATION_COMPLETE, init); } private function init(event:Event):void { var label:Label=new Label(); this.addChild(label); label.height=16; label.setStyle("borderColor", "red"); label.setStyle("color", "red"); label.setStyle("textAlign", "center"); label.text="起點"; label.width=45; } } }
package com.esri.viewer.tool.measure { import flash.events.Event; public class MeasureEvent extends Event { public static var MEASURE_FINISH:String="measurefinish"; private var _data:Object; public function get data():Object{ return _data; } public function MeasureEvent(type:String,data:Object=null,bubbles:Boolean=false, cancelable:Boolean=false) { this._data=data; super(type, bubbles, cancelable); } } }
package com.esri.viewer.tool.measure { import com.esri.ags.Graphic; import com.esri.ags.Map; import com.esri.ags.components.supportClasses.InfoPlacement; import com.esri.ags.events.GeometryServiceEvent; import com.esri.ags.events.MapMouseEvent; import com.esri.ags.geometry.MapPoint; import com.esri.ags.geometry.Polyline; import com.esri.ags.layers.GraphicsLayer; import com.esri.ags.symbols.InfoSymbol; import com.esri.ags.symbols.PictureMarkerSymbol; import com.esri.ags.symbols.SimpleLineSymbol; import com.esri.ags.symbols.SimpleMarkerSymbol; import com.esri.ags.tasks.GeometryService; import com.esri.ags.tasks.supportClasses.DistanceParameters; import com.esri.viewer.AppEvent; import com.esri.viewer.tool.ToolWidget; import com.esri.viewer.tool.measure.Infosym; import com.esri.viewer.tool.measure.InfosymStart; import flash.events.MouseEvent; import flash.utils.clearInterval; import flash.utils.setInterval; import mx.core.ClassFactory; import mx.formatters.NumberFormatter; /** * 測量工具類,每測量一次初始化該類 * */ public class MeasureLengths { private const _service:GeometryService=new GeometryService(); private var map:Map; private var measureGraphicLayer:GraphicsLayer=new GraphicsLayer(); //準測量圖層 private var measurePoiintGraphicLayer:GraphicsLayer=new GraphicsLayer(); //真實測量圖層 private var lineGraphic:Graphic=new Graphic(); //準測量圖形 private var realLineGraphic:Graphic=new Graphic(); //真實測量圖形 private var pointArr:Array=[]; //保存全部的測量點 private var distanceArr:Array=[]; //保存全部的測量距離 private var flag:Boolean=false; //判斷是不是最後一個點 private var tmpGraphic:Graphic = null; private var clickPoint:MapPoint; public function MeasureLengths(url:String, map:Map=null) { _service.url=url; this.map=map; measureGraphicLayer.add(lineGraphic); measurePoiintGraphicLayer.add(realLineGraphic); map.addLayer(measureGraphicLayer); map.addLayer(measurePoiintGraphicLayer); _service.addEventListener(GeometryServiceEvent.DISTANCE_COMPLETE, distancecomplete); map.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveFun); } public function disposeMeasureLengths():void { measureGraphicLayer.remove(lineGraphic); measurePoiintGraphicLayer.remove(realLineGraphic); map.removeLayer(measureGraphicLayer); map.removeLayer(measurePoiintGraphicLayer); _service.removeEventListener(GeometryServiceEvent.DISTANCE_COMPLETE, distancecomplete); map.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveFun); } public function mapclick(event:MapMouseEvent):void { clickPoint=event.mapPoint; pointArr.push(clickPoint); var pointSysmbol:SimpleMarkerSymbol=new SimpleMarkerSymbol("circle", 12, 0xFF0000, 0.65); var clickPointGraphic:Graphic=new Graphic(clickPoint, pointSysmbol); measurePoiintGraphicLayer.add(clickPointGraphic); if (pointArr.length > 1) { realGraphicLine(pointArr); } else { measurePoiintGraphicLayer.add(createStartLable(pointArr[0] as MapPoint)); } clearInterval(ToolWidget.interval); } private function mouseMoveFun(moveEvent:MouseEvent):void { var movePoint:MapPoint=map.toMapFromStage(moveEvent.stageX, moveEvent.stageY); if(tmpGraphic) { measurePoiintGraphicLayer.remove(tmpGraphic); } if(pointArr.length > 0) { if(tmpGraphic) { tmpGraphic = null; } //根據movePoint準測量點 畫準測量線 graphicLine(movePoint, clickPoint); } else { tmpGraphic?tmpGraphic.geometry = movePoint:tmpGraphic = createStartLable(movePoint); measurePoiintGraphicLayer.add(tmpGraphic); } } private function createStartLable(movePoint:MapPoint):Graphic { var infosymbol:InfoSymbol=new InfoSymbol(); infosymbol.infoRenderer=new ClassFactory(InfosymStart); infosymbol.containerStyleName="infosymbolvenues"; infosymbol.infoPlacement=InfoPlacement.RIGHT; return new Graphic(movePoint, infosymbol); } //畫測量點完畢,開始測量 public function measureFinish(event:MouseEvent):void { if (pointArr.length > 0) { var finishPoint:MapPoint=map.toMapFromStage(event.stageX, event.stageY); pointArr.push(finishPoint); var pointSysmbol:SimpleMarkerSymbol=new SimpleMarkerSymbol("circle", 12, 0xFF0000, 0.65); var clickPointGraphic:Graphic=new Graphic(finishPoint, pointSysmbol); measurePoiintGraphicLayer.add(clickPointGraphic); var picSysmbol:PictureMarkerSymbol=new PictureMarkerSymbol("assets/images/delete.png", 16, 16,-20); var finishGraphic:Graphic=new Graphic(finishPoint,picSysmbol); measurePoiintGraphicLayer.add(finishGraphic); finishGraphic.addEventListener(MouseEvent.CLICK, clearCurrentLayer); if (pointArr.length > 1) { realGraphicLine(pointArr); } //移除畫準測量線的事件 map.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveFun); //清空準測量圖層 measureGraphicLayer.remove(lineGraphic); //派發一個測量完的事件;移除map點擊事件 AppEvent.dispatch(AppEvent.MEASURE_FINISH, ""); //開始測量 flag=true; measureFun(pointArr); } } //畫真實測量線 private function realGraphicLine(pointArr:Array):void { var realLineSysmbol:SimpleLineSymbol=new SimpleLineSymbol("solid", 0xFF0000, 0.65, 3); var realLine:Polyline=new Polyline([pointArr], map.spatialReference); realLineGraphic.geometry=realLine; realLineGraphic.symbol=realLineSysmbol; //測量兩點距離 measureFun(pointArr); } //畫準測量線 private function graphicLine(movePoint:MapPoint, pointArrLast:MapPoint):void { var lineSysmbol:SimpleLineSymbol=new SimpleLineSymbol("solid", 0xFA8072, 0.6, 3); var paths:Array=[pointArrLast,movePoint]; var line:Polyline=new Polyline([paths], map.spatialReference); lineGraphic.geometry=line; lineGraphic.symbol=lineSysmbol; } //刪除地圖上的測量圖層 private function clearCurrentLayer(event:MouseEvent):void { map.removeLayer(event.currentTarget.parent); } //距離測量 private function measureFun(pointArr:Array):void { if (pointArr.length > 1) { var distanceParmers:DistanceParameters=new DistanceParameters(); distanceParmers.distanceUnit=GeometryService.UNIT_STATUTE_MILE; //英里 distanceParmers.geometry1=pointArr[pointArr.length - 2]; distanceParmers.geometry2=pointArr[pointArr.length - 1]; distanceParmers.geodesic=true; _service.distance(distanceParmers); } } //兩點測量完畢 private function distancecomplete(event:GeometryServiceEvent):void { var distanceObj:Object=event.result; var numberFormatter:NumberFormatter=new NumberFormatter(); numberFormatter.precision=3; var kilometre:Number=(distanceObj as Number) * 1.6; var distanceNUm:Number=Math.round(kilometre * 1000) / 1000; if (distanceArr.length > 0) { distanceNUm=distanceNUm + distanceArr[distanceArr.length - 1]; } distanceArr.push(distanceNUm); var graphic:Graphic; if (!flag) { graphic=new Graphic(pointArr[pointArr.length - 1] as MapPoint, createInfoSymbol(), numberFormatter.format(distanceNUm)); //graphic.autoMoveToTop=true; } else { graphic=new Graphic(pointArr[pointArr.length - 1] as MapPoint, createInfoSymbol(), "總長:" + numberFormatter.format(distanceNUm)); //graphic.autoMoveToTop=true; } measurePoiintGraphicLayer.add(graphic); } private function createInfoSymbol():InfoSymbol { var infosymbol:InfoSymbol=new InfoSymbol(); infosymbol.infoRenderer=new ClassFactory(Infosym); infosymbol.containerStyleName="infosymbolvenues"; infosymbol.infoPlacement=InfoPlacement.RIGHT; return infosymbol; } } }
方案二缺陷就更多了,幾乎都是沒法使用的,尤爲是鼠標雙擊事件衝突、鼠標點擊和移動事件衝突,坑了好久,因此仍是放棄。
最後綜合兩種方案得出完整的解決方案,首先利用方案一的DrawTool控制交互,用方案二的GeometryServiceEvent計算長度面積。後續能夠本身進一步豐富,
以下是新的完整的代碼。支持長度和麪積的測量
package com.esri.viewer.tool.measure { import com.esri.ags.Graphic; import com.esri.ags.Map; import com.esri.ags.Units; import com.esri.ags.events.DrawEvent; import com.esri.ags.events.GeometryServiceEvent; import com.esri.ags.events.MapMouseEvent; import com.esri.ags.geometry.MapPoint; import com.esri.ags.geometry.Polygon; import com.esri.ags.geometry.Polyline; import com.esri.ags.layers.GraphicsLayer; import com.esri.ags.symbols.CompositeSymbol; import com.esri.ags.symbols.PictureMarkerSymbol; import com.esri.ags.symbols.SimpleLineSymbol; import com.esri.ags.symbols.SimpleMarkerSymbol; import com.esri.ags.symbols.TextSymbol; import com.esri.ags.tasks.GeometryService; import com.esri.ags.tasks.supportClasses.AreasAndLengthsParameters; import com.esri.ags.tasks.supportClasses.DistanceParameters; import com.esri.ags.tools.DrawTool; import com.esri.ags.utils.GeometryUtil; import com.esri.viewer.AppEvent; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.utils.Timer; import mx.collections.ArrayCollection; import mx.formatters.NumberFormatter; public class Measure { private var lineSymbol:SimpleLineSymbol; private var markerSymbol:SimpleMarkerSymbol; private var normalLabel:TextSymbol; private var endLabel:TextSymbol; private var deleteLabel:CompositeSymbol; private var drawLayer:GraphicsLayer; private var drawTool:DrawTool; private var isActive:Boolean; private var map:Map; //測距須要的幾個全局變量 //節點數組,這是實際用於計算距離的值 private var polyArray:Array; //用這個來標識是否應放下終點註記 private var isDraw:Boolean; //當前節點,每次mapClick刷新 private var currentPoint:MapPoint; //每條測距線的標識碼 private var sierialId:int = 0; private var areaGraphic:Graphic; private var isMeasureLine:Boolean = true; private const _service:GeometryService=new GeometryService(); //保存全部的測量距離 private var distanceArr:Array=[]; private var areaCenterPoint:MapPoint; public function set IsActive(value:Boolean):void { isActive = value; if(isActive) { InitDraw(); } else { StopDraw(); } } public function get IsActive():Boolean { return isActive; } public function Measure(url:String, _map:Map) { map = _map; _service.url=url; } private function InitDraw():void { //對於這樣的類,我很喜歡使用一個函數來完成GraphicsLayer的初始化和添加 drawLayer = AddGraphicLayer("measure"); //紅色細實線做爲測距線 lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,0xff0000,1,2); //小紅圈做爲節點 markerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE,8,0xffffff,1,0,0,0,lineSymbol); //起點和中繼點的註記符號,把用於顯示的文字綁定於TEXT上 normalLabel = new TextSymbol(); normalLabel.background = true; normalLabel.backgroundColor = 0xffffff; normalLabel.border = true; normalLabel.borderColor = 0x666666; normalLabel.color = 0x666666; normalLabel.placement = TextSymbol.PLACEMENT_START; normalLabel.xoffset = 10; normalLabel.textAttribute = "TEXT"; //終點的註記符號,一樣綁定在Text上 endLabel = new TextSymbol(); endLabel.background = true; endLabel.backgroundColor = 0xffffff; endLabel.border = true; endLabel.borderColor = 0xff0000; endLabel.color = 0x000000; endLabel.yoffset = 20; endLabel.textAttribute = "TEXT"; //刪除按鈕的符號,用一個組合符號把按鈕圖標放在一個正方形的框裏 deleteLabel = new CompositeSymbol(); var picSymbol:PictureMarkerSymbol = new PictureMarkerSymbol("assets/images/delete.png",16,16,15,-15); var borderSymbol:SimpleMarkerSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE,18,0xffffff,1,15,-15,0, new SimpleLineSymbol("solid",0xff0000,1,1)); deleteLabel.symbols=[borderSymbol,picSymbol]; //drawTool初始化只需注意一下咱們額外須要一個DRAW_START事件 drawTool = new DrawTool(map); drawTool.showDrawTips = false; drawTool.graphicsLayer = drawLayer; drawTool.lineSymbol = lineSymbol; drawTool.addEventListener(DrawEvent.DRAW_END,drawEnd); drawTool.addEventListener(DrawEvent.DRAW_START,drawStart); } //中止繪製時把繪圖圖層移除 private function StopDraw():void { if(map.getLayer("measure")) map.removeLayer(map.getLayer("measure")); drawTool.deactivate(); map.removeEventListener(MapMouseEvent.MAP_CLICK,mapClicked); polyArray = []; isMeasureLine?_service.removeEventListener(GeometryServiceEvent.AREAS_AND_LENGTHS_COMPLETE, distanceComplete): _service.addEventListener(GeometryServiceEvent.AREAS_AND_LENGTHS_COMPLETE, areaComplete); } //這是我很是喜歡的添加圖層函數,初始化、添加、賦值所有打包 //若是map裏有這個ID的圖層,就直接放回這個圖層 //若是map裏尚未,就new一個,放進去再返回這個圖層 private function AddGraphicLayer(layerid:String):GraphicsLayer { var glayer:GraphicsLayer; if(map.getLayer(layerid)!=null) { glayer = map.getLayer(layerid) as GraphicsLayer; } else { glayer = new GraphicsLayer(); glayer.id = layerid; map.addLayer(glayer); } return glayer; } //鼠標點擊measure按鈕,就執行這個函數開始測距 public function MeasureDistance():void { isMeasureLine = true; drawTool.activate(DrawTool.POLYLINE); drawTool.showDrawTips = true; drawTool.toolTipStartAndLetGo="點擊開始測距"; drawTool.toolTipPolyEnd="雙擊結束測距"; polyArray = new Array(); isDraw = true; map.panEnabled = false; map.addEventListener(MapMouseEvent.MAP_CLICK,mapClicked); _service.addEventListener(GeometryServiceEvent.DISTANCE_COMPLETE, distanceComplete); } //鼠標點擊measure按鈕,就執行這個函數開始測距 public function MeasureDistanceArea():void { isMeasureLine = false; drawTool.activate(DrawTool.POLYGON); drawTool.showDrawTips = true; drawTool.toolTipStartAndLetGo="點擊開始量面"; drawTool.toolTipPolyEnd="雙擊結束量面"; polyArray = new Array(); isDraw = true; map.panEnabled = false; map.addEventListener(MapMouseEvent.MAP_CLICK,mapClicked); _service.addEventListener(GeometryServiceEvent.AREAS_AND_LENGTHS_COMPLETE, areaComplete); } //距離測量 private function measureLengthFun(pointArr:Array):void { if (pointArr.length > 1) { var distanceParmers:DistanceParameters=new DistanceParameters(); distanceParmers.distanceUnit=GeometryService.UNIT_METER; //英里 distanceParmers.geometry1=pointArr[pointArr.length - 2]; distanceParmers.geometry2=pointArr[pointArr.length - 1]; distanceParmers.geodesic=true; _service.distance(distanceParmers); } } //面積測量 private function measureAreaFun(polygons:Array):void { var areaParmers:AreasAndLengthsParameters=new AreasAndLengthsParameters(); areaParmers.lengthUnit=GeometryService.UNIT_METER; areaParmers.areaUnit=GeometryService.UNIT_SQUARE_METERS; areaParmers.polygons =polygons; _service.areasAndLengths(areaParmers); } //開始繪圖時自增一下當前的測距線標識碼 private function drawStart(event:DrawEvent):void { sierialId+=1; } //結束繪圖時的操做,AppEvent是一個事件,目的在於通知頁面測距完成了 private function drawEnd(event:DrawEvent):void { event.graphic.attributes = {id:sierialId}; drawTool.deactivate(); map.removeEventListener(MapMouseEvent.MAP_CLICK,mapClicked); map.panEnabled = true; isDraw = false; AppEvent.dispatch(AppEvent.MEASURE_FINISH); } //繪圖過程當中點擊地圖時記錄節點,注意每次記錄節點的過程用timer來控制 private function mapClicked(event:MapMouseEvent):void { currentPoint = event.mapPoint; //0.2秒的延遲,放置節點紅圈干擾drawTool var timer:Timer = new Timer(200); timer.addEventListener(TimerEvent.TIMER,timerEnd); timer.start(); } //timer裏實際進行的就是距離計算和放置註記等複雜的工做 private function timerEnd(e:TimerEvent):void { (e.currentTarget as Timer).stop(); //拿到節點,必定要new啊,必定要new一個,不然會很悲劇 var mp:MapPoint = new MapPoint(currentPoint.x,currentPoint.y,currentPoint.spatialReference); //往用於計算的邏輯數組裏塞入這個節點 polyArray.push(mp); //若是還在繪圖當中的話,那就是放妖放下中繼點或起點 if(isDraw) { //這樣是起點,記得用TEXT來傳遞標註文字,用id來傳遞標識碼 if(polyArray.length == 1) { drawLayer.add(new Graphic(mp,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:"起點",id:sierialId})); } else { measureLengthFun(polyArray); } } else { //結束繪圖的話,就放終點 var deleteGr:Graphic; if(!isMeasureLine) { // 倒數第二點 measureLengthFun(polyArray); // 最後點,首位鏈接 var tmpPolygon:Polygon = new Polygon([polyArray],map.spatialReference); areaCenterPoint = tmpPolygon.extent.center; measureAreaFun([new Polygon([polyArray],map.spatialReference)]); deleteGr = new Graphic(areaCenterPoint,deleteLabel,{id:sierialId}); }else{ measureLengthFun(polyArray); deleteGr = new Graphic(mp,deleteLabel,{id:sierialId}); } //這是要放刪除按鈕,就是一個graphic啦,可是須要綁定一下Click事件。 deleteGr.toolTip = "刪除"; deleteGr.buttonMode = true; deleteGr.addEventListener(MouseEvent.CLICK,deleteHandler); drawLayer.add(deleteGr); } } private function distanceComplete(event:GeometryServiceEvent):void { var distanceObj:Object=event.result; var kilometre:Number=(distanceObj as Number) * 1.6; var distanceNum:Number=Math.round(kilometre * 1000) / 1000; if (distanceArr.length > 0) { distanceNum=distanceNum + distanceArr[distanceArr.length - 1]; } distanceArr.push(distanceNum); var lengthStr:String =distanceNum>1000?(distanceNum/1000).toFixed(2)+"公里":distanceNum.toFixed(2)+"米"; if(isDraw) { //這樣是起點,記得用TEXT來傳遞標註文字,用id來傳遞標識碼 if(polyArray.length == 1) { drawLayer.add(new Graphic(currentPoint,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:"起點",id:sierialId})); } else { drawLayer.add(new Graphic(currentPoint,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:lengthStr,id:sierialId})); } } //結束繪圖的話,就放終點 else { if(isMeasureLine) { drawLayer.add(new Graphic(currentPoint,new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總長:"+lengthStr,id:sierialId})); } else { drawLayer.add(new Graphic(currentPoint,new CompositeSymbol([markerSymbol,normalLabel]),{TEXT:lengthStr,id:sierialId})); } } } private function areaComplete(event:GeometryServiceEvent):void { var area:Number = event.result.areas[0]; //event.arealengths.areas[0]; var length:Number = event.result.lengths[0]; // or (event.result as Array)[0]; //event.arealengths.lengths[0]; var lengthStr:String =length>1000?(length/1000).toFixed(2)+"公里":length.toFixed(2)+"米"; drawLayer.add(new Graphic(polyArray[0],new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總周長:"+lengthStr,id:sierialId})); var areaStr:String = area>=1000000?(area/1000000).toFixed(2)+"平方公里":area.toFixed(2)+"平方米"; drawLayer.add(new Graphic(areaCenterPoint,new CompositeSymbol([markerSymbol,endLabel]),{TEXT:"總面積:"+areaStr,id:sierialId})); } //刪除的時候根據標識碼來刪除對應測距線中的元素 private function deleteHandler(event:MouseEvent):void { var id:int = (event.currentTarget as Graphic).attributes.id; var deletArray:Array = new Array(); for each(var line:Graphic in drawLayer.graphicProvider) { if(line.attributes.id == id) { deletArray.push(line); } } for each(var graphic:Graphic in deletArray) { drawLayer.remove(graphic); } //若是刪除的是最後一條測距線,就把這個測距圖層移除,而且讓測距功能關閉,減小資源佔用 if((drawLayer.graphicProvider as ArrayCollection).length == 0) this.IsActive = false; } } }