WebGIS--ArcGIS for Flex系列開發六:模仿百度的測距

放棄百度,選擇更高效的檢索方式,提供工做效率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;
		}
	}
}
相關文章
相關標籤/搜索