在ArcGIS API for Flex中实现鹰眼图中方框的拖动
这是我第一次写blog,主要目的是想告诉大家如何在ArcGIS API for Flex中拖动Graphic对象,如果是Graphic对象是鹰眼图中方框的话,可以在鹰眼图中拖动方框以改变主图的范围,如果是点图形,则可以用于做最短路径分析,通过移动起点或终点,最短路径可以重新计算,所以这个功能可以说是实现一些更高级功能的基础,所以还是比较实用的。
话不多说,说一说思路,以Extent为例(注意,这里的Extent是graphic.geometry类型而不是graphic.geometry.extent类型),对这个Extent拖动时会经历四个事件,鼠标按下,鼠标移动,鼠标放开,哎,这不是三个事件吗?别忘了,鼠标按下和放开就是一个Click事件(对这个Click事件的监听在鹰眼图中有很大用处,后面再说)。那么如何对Extent添加这四个事件监听器呢,肯定不是同时添加,看下面的代码
1 public var extentBox:Graphic = new Graphic(); 2 public var dragStartExtent:Extent; 3 public var dragStartPoint:MapPoint; 4 protected function layerCreationComplete(event:FlexEvent):void 5 { 6 7 layer.add(extentBox); 8 extentBox.symbol = extentBoxSym; 9 extentBox.buttonMode=true; 10 11 extentBox.addEventListene(MouseEvent.MOUSE_DOWN,graphicStartDrag); 12 extentBox.addEventListene(MouseEvent.CLICK,onBoxClick); 13 14 if(mainMap.loaded) 15 { 16 extentBox.geometry=mainMap.extent; 17 } 18 } 19 20 protected function graphicStartDrag(event:MouseEvent):void 21 { 22 extentBox.addEventListener(MouseEvent.MOUSE_MOVE,graphicUpdate); 23 extentBox.addEventListener(MouseEvent.MOUSE_UP,graphicDragEnd); 24 25 dragStartPoint = overviewMap.toMapFromStage(event.stageX,event.stageY); 26 dragStartExtent=extentBox.geometry.extent; 27 } 28 29 protected function graphicUpdate(event:MouseEvent):void 30 { 31 var mapPoint:MapPoint=MapPoint(overviewMap.toMapFromStage(event.stageX,event.stageY)); 32 var xOff:Number=mapPoint.x-dragStartPoint.x; 33 var yOff:Number=mapPoint.y-dragStartPoint.y; 34 35 var newExtent:Extent=dragStartExtent.offset(xOff,yOff); 36 extentBox.geometry=newExtent; 37 } 38 39 protected function graphicDragEnd(event:MouseEvent):void 40 { 41 extentBox.removeEventListener(MouseEvent.MOUSE_MOVE,graphicUpdate); 42 extentBox.removeEventListener(MouseEvent.MOUSE_UP,graphicDragEnd); 43 mainMap.extent=extentBox.geometry.extent; 44 }
(注:mainMap是主地图,overviewMap是鹰眼图)
在上面的代码中layerCreationComplete是监听GraphicsLayer创建完成时触发的函数,在GraphicsLayer创建完成后将extentBox(也就是鹰眼图中的方框)添加到该图层中,如果主地图加载完成的话,则方框即为主地图范围,然后对extentBox添加的两个事件监听器,MOUSE_DOWN和CLICK。
graphicStartDrag是监听MOUSE_DOWN触发的函数,当鼠标按下时又对extentBox添加的两个事件监听器,MOUSE_MOVE和MOUSE_UP,至此对extentBox拖动时的四个事件进行了监听。然后记录鼠标按下时起始点,用了toMapFromStage方法将屏幕上的点转化为了地图上的点,以及记录鼠标按下时extentBox的初始范围(如果是点的话,只记录起始点就可以了)。
graphicUpdate是监听MOUSE_MOVE触发的函数,也就是实现extentBox拖动的函数,这里面最关键的就是这两行
var newExtent:Extent=dragStartExtent.offset(xOff,yOff); extentBox.geometry=newExtent;
利用offset的方法在拖动时不断的生成newExtent,然后用newExtent来实时更新extentBox的geometry属性,这两行就是Graphic拖动的精髓了,它的思想是不销毁Graphic对象,而是不断的更新Graphic的gemotry属性来实现Graphic对象的移动。我刚开始做的时候,总是想着在移动的时候不断的生成和不断的销毁Graphic对象,结果总是移动了一下整个extentBox就没了,我后来想了下,extentBox销毁后对MOUSE_MOVE的监听就算结束了,所以只有不销毁extentBox,才能一直保持对MOUSE_MOVE事件的监听,然后通过不断的改变geomotry属性来达到移动的效果。
graphicDragEnd是监听MOUSE_UP触发的函数,主要是为了移除对MOUSE_MOVE和MOUSE_UP这两个事件的监听,如果不移除的话,在对extentBox进行第一次拖动以后,鼠标在滑过extentBox时,extentBox又会跟着鼠标一起动,而且会发生一些意想不到的错误,不是有句话吗,出来混,总是要还的,呵呵。
然后来说一下对CLICK事件监听的作用,看下面的代码
1 private function onBoxClick( event:MouseEvent ):void 2 { 3 event.stopPropagation(); 4 } 5 6 protected function overviewMapClick(event:MouseEvent):void 7 { 8 var newExtent:Extent=extentBox.geometry.extent.centerAt(overviewMap.toMapFromStage(event.stageX,event.stageY)); 9 extentBox.geometry=newExtent; 10 mainMap.extent=newExtent; 11 }
先看overviewMapClick这个函数,它是对监听鹰眼图CLICK事件触发的函数,它的作用就是,当用户在鹰眼图上点击时,extentBox移动到以该点为中心的位置,然后使主地图进行联动。但是,当用户在extentBox内部单击时,却不会发生任何事。前面我已经说过了,extentBox在拖动过程中会触发CLICK事件,在上面的代码中extentBox监听CLICK事件触发的函数只有一行代码
event.stopPropagation();
从字面来看,stopPropagation,停止传播,它的作用就是不让CLICK事件传播到鹰眼图中,我们来看看它有什么用。对 extentBox单击时,extentBox和鹰眼图会同时分派CLICK事件,对extentBox拖动完成后,相当于同时单击了extentBox和鹰眼图,因为鹰眼图中已经添加了对CLICK事件的监听,那么总是会使方框移动到以该点为中心的位置,如果你移动方框的起始点不是extentBox的中心点,extentBox总是会移动到以你拖动完成时鼠标放开的点为中心的位置,这句话很拗口,总之你的extentBox的在拖动完成后会突然位移。但是,对extentBox添加对CLICK事件的监听后,使用stopPropagation方法,就可以使鹰眼图不会监听到CLICK事件,所以就可以保证对extentBox拖动后,extentBox不会发生位移。
这个实际上是Flex的事件机制,捕获,目标,冒泡,关于Flex的事件机制,我这里就不讲了,网上有好多资料,可以自行查阅
最后顺便说一句,鹰眼图最好用ArcGISDynamicMapServiceLayer,好不好你用了就知道