博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WebGIS--ArcGIS for Flex系列开发六:模仿百度的测距
阅读量:6684 次
发布时间:2019-06-25

本文共 31045 字,大约阅读时间需要 103 分钟。

hot3.png

放弃百度,选择更高效的检索方式,提供工作效率

效果图

235916_7HJt_615762.png

235947_nYyX_615762.png

 

非常感谢以下两位作者的分享,也许已经找不到原作者。

方案一:

方案二:

两种方法分别采用完全不同的方式实现,各有各的优势和缺陷。

方案一的实现方法较为正常,能够正常使用

现附上方案一的整理源码:

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)+"平方米";		}	}}

调用方式如下:

Measure measureTool = new Measure(map)if(!measureTool.IsActive)  measureTool.IsActive = true;             measureTool.MeasureDistance();

方案一的缺陷是长度计算方式只支持地理坐标,不支持平面坐标。在释放操作过程中没有进行完全释放内容。

方案二源码如下

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;		}	}}

 

转载于:https://my.oschina.net/u/615762/blog/1608826

你可能感兴趣的文章
【poi xlsx报错】使用POI创建xlsx无法打开
查看>>
UNIX环境高级编程笔记之文件I/O
查看>>
DIV+CSS规范命名
查看>>
我的2013 Q.E.D
查看>>
2017 Multi-University Training Contest - Team 9 1002&&HDU 6162 Ch’s gift【树链部分+线段树】...
查看>>
4.5. Rspamd
查看>>
ArcMap中的名称冲突问题
查看>>
(转) 一张图解AlphaGo原理及弱点
查看>>
美联邦调查局 FBI 网站被黑,数千特工信息泄露
查看>>
掉电引起的ORA-1172错误解决过程(二)
查看>>
在网站建设过程中主要在哪几个方面为后期的网站优打好根基?
查看>>
【MOS】RAC 环境中最常见的 5 个数据库和/或实例性能问题 (文档 ID 1602076.1)
查看>>
新年图书整理和相关的产品
查看>>
Struts2的核心文件
查看>>
Spring Boot集成Jasypt安全框架
查看>>
GIS基础软件及操作(十)
查看>>
HDOJ 2041 超级楼梯
查看>>
1108File Space Bitmap Block损坏能修复吗2
查看>>
遭遇DBD::mysql::dr::imp_data_size unexpectedly
查看>>
人人都会设计模式:03-策略模式--Strategy
查看>>