標籤:style blog http color io os 使用 ar for
前文已經完成了從資料庫查詢旅遊景點的工作,下面就是要把這些查詢的結果顯示到地圖上,同時要實現查詢列表和地圖的聯動。也就是點擊列表中的某一項,地圖能定位至該位置並彈出infowindow。
這個開發工作本身沒有太大的難度,但是我認為的增加了一點障礙,因為我不太喜歡arcgis api內建的infowindow,我需要自己做一個,這一節內容就從這個DIY的infowindow開始。首先來設計一下這個表單,為了表示不抄襲,這個infowindow改名PopupWindow。
PopupWindow.mxml
<?xml version="1.0" encoding="utf-8"?><s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="280" height="120" xmlns:esri="http://www.esri.com/2008/ags"> <fx:Script> <![CDATA[ import com.esri.ags.Graphic; import flash.net.navigateToURL; [Bindable] public var graphic:Graphic; protected function image_Close_clickHandler(event:MouseEvent):void { this.parent.removeChild(this); } ]]> </fx:Script> <!--氣泡形外框--> <s:Path data="M 1 1 L 278 1 L 278 90 L 175 90 L 130 118 L 150 90 L 1 90 Z" winding="nonZero"> <s:stroke> <s:SolidColorStroke caps="none" color="#696969" joints="miter" miterLimit="4" weight="1"/> </s:stroke> <s:fill> <s:SolidColor color="#FFFFFF"/> </s:fill> </s:Path> <!--主要內容--> <s:BorderContainer left="1" right="1" top="1" height="30" backgroundColor="#EAEAEA" dropShadowVisible="false"> <s:Image id="image_Close" right="5" click="image_Close_clickHandler(event)" source="image/close.png" verticalCenter="0"/> <s:Label id="label_Title" left="10" color="#1D2DC6" fontFamily="宋體" fontSize="16" fontWeight="bold" text="{graphic.attributes.NAME}" verticalCenter="0"/> </s:BorderContainer> <s:Label id="label_Address" left="10" top="45" color="#6B6B6B" text="{graphic.attributes.REGION}"/> <!--查看詳情時跳轉至資料內建的連結--> <s:Label right="10" top="45" color="#0000FF" text="查看詳情" textDecoration="underline" buttonMode="true" click="navigateToURL(new URLRequest(graphic.attributes.URL.toString()),‘_blank‘)"/></s:Group>
這個組件只有兩個特別的技巧,一是用path來繪製氣泡形外框,二是在關閉按鈕點擊時的處理,也都不是很難理解的東西。下面就是核心問題了,如何把這個東西放地圖上?用map控制項繼承的addChild()方法,移除就用removeChild()方法。還要利用map控制項內建的地理座標與螢幕座標轉換方法來計算這個表單在應用程式中的放置的螢幕座標。這還不算完,我們還要考慮map在平移、縮放的時候,這個表單應該是平滑的隨著map而動,這就需要同時監聽map的EXTENT_CHANGE、PAN_UPDATE、ZOOM_UPDATE三個事件,這三個事件代表了map在extent發生變化的任何情況,保證表單可以完全跟隨map而動。主要思想就這些,後面的工作就都在前文已經做的LeftResultPage.mxml中完成,下面就是修改過後的這個Page的全部代碼。
LeftResultPage.mxml
<?xml version="1.0" encoding="utf-8"?><s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="270" gap="0"> <!--註冊事件用於點擊返回按鈕回到首頁--> <fx:Metadata> [Event(name="BacktoFront", type="tool.CustomEvent")] </fx:Metadata> <fx:Script> <![CDATA[ import com.esri.ags.Graphic; import com.esri.ags.Map; import com.esri.ags.events.ExtentEvent; import com.esri.ags.events.PanEvent; import com.esri.ags.events.ZoomEvent; import com.esri.ags.geometry.MapPoint; import com.esri.ags.layers.GraphicsLayer; import com.esri.ags.symbols.PictureMarkerSymbol; import com.esri.ags.symbols.SimpleMarkerSymbol; import com.esri.ags.utils.GeometryUtil; import com.esri.ags.utils.GraphicUtil; import mx.collections.ArrayCollection; import spark.events.IndexChangeEvent; import tool.CustomEvent; //綁定map用於顯示要素、控制popupwindow //賦值map時就把三個監聽註冊 [Bindable] private var _map:Map; public function set map(value:Map):void { _map = value; _map.addEventListener(ExtentEvent.EXTENT_CHANGE,mapExtentChanger); _map.addEventListener(PanEvent.PAN_UPDATE,panHandler); _map.addEventListener(ZoomEvent.ZOOM_UPDATE,zoomHandler); } public function get map():Map { return _map; } //將result改為set函數,組件中的綁定要換為resultArray //使用時先賦值map,再賦值result,這時result會為map添加要素 [Bindable] private var resultArray:ArrayCollection; public function set result(value:ArrayCollection):void { resultArray = value; if(map) { var gLayer:GraphicsLayer = AddGraphicLayer("query"); for each(var graphic:Graphic in resultArray) { gLayer.add(graphic); } map.zoomTo(GraphicUtil.getGraphicsExtent(resultArray.toArray())); } } public function get result():ArrayCollection { return resultArray; } //返回按鈕中增加了移除要素和popwindow private function back_clickHandler(event:MouseEvent):void { RemoveGraphicLayer("query"); RemovePopup(); dispatchEvent(new CustomEvent(CustomEvent.BacktoFront)); } private function RemoveGraphicLayer(layerid:String):void { if(map.getLayer(layerid)!=null) { map.removeLayer(map.getLayer(layerid)); } } private function RemovePopup():void { if(map.getChildByName("popup")) { map.removeChild(map.getChildByName("popup")); } } //這個是常用添加GraphicsLayer函數 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; } private function list_Result_changeHandler(event:IndexChangeEvent):void { var graphic:Graphic = list_Result.selectedItem as Graphic; var mappoint:MapPoint = graphic.geometry as MapPoint; //定位至選定要素,同時控制一下層級 map.zoomTo(mappoint); if(map.level < 12) map.level = 12; var popupWindow:PopupWindow; //若map已有popupwindow,就把popupwindow移動到當前位置 if(map.getChildByName("popup")) { popupWindow = map.getChildByName("popup") as PopupWindow; popupWindow.graphic = graphic; //popup的x、y是左上方定位的,要計算一下把錨點移至氣泡底部,同時要和符號匹配 popupWindow.x = map.toScreenX(mappoint.x) - 130; popupWindow.y = map.toScreenY(mappoint.y) - 148; } //若map沒有popupwindow,建立一個並放置到對應的位置 else { popupWindow = new PopupWindow(); popupWindow.graphic = graphic; popupWindow.name = "popup"; popupWindow.x = map.toScreenX(mappoint.x) - 130; popupWindow.y = map.toScreenY(mappoint.y) - 148; map.addChild(popupWindow); } } private function panHandler(event:PanEvent):void { PopupMove(); } private function zoomHandler(event:ZoomEvent):void { PopupMove(); } private function mapExtentChanger(event:ExtentEvent):void { PopupMove(); } //move其實就是重新計算錨點的螢幕座標,移動一下popupwindow private function PopupMove():void { if(map.getChildByName("popup")) { var popupWindow:PopupWindow = map.getChildByName("popup") as PopupWindow; var mappoint:MapPoint = popupWindow.graphic.geometry as MapPoint; popupWindow.x = map.toScreenX(mappoint.x) - 130; popupWindow.y = map.toScreenY(mappoint.y) - 148; } } ]]> </fx:Script> <fx:Declarations> <!-- 將非可視元素(例如服務、值對象)放在此處 --> </fx:Declarations> <s:Group width="100%" height="30"> <s:Label left="0" text="{‘共查到‘+resultArray.length+‘個結果‘}" verticalCenter="0"/> <mx:LinkButton right="0" label="返回" click="back_clickHandler(event)" verticalCenter="0"/> </s:Group> <s:List id="list_Result" width="100%" height="100%" itemRenderer="renderer.listRenderer" dataProvider="{resultArray}" change="list_Result_changeHandler(event)"></s:List></s:VGroup>
如此全部設計功能實現,照例來一張效果:
到此,項目設計的主要功能就完成了。當然目前項目的這個樣子就交付不是很合適,後面要對項目做一系列介面調整與美化,這就要開啟我們的美工部分了。
Arcgis apis for flex項目執行個體—開發篇(6):自己的infowindow