config.xml文件的配置如下:
<widget label="路径导航" icon="assets/images/lujingdaohang.png" config="widgets/eDriections/eDirectionsWidget.xml" url="widgets/eDriections/eTabDirectionsWidget.swf" />
源代码目录如下:
界面效果:
大概的思路如下:1.文本框输入开始点以及结束点,获取两个点坐标;2.直接在地图上点击两个点,获取两个点坐标;其实两个的最终目的是一样的,都是为了获取两个点坐标。其中用到了地理编码服务,用于根据地名来获取坐标以及根据坐标来获取地名信息。
用到了arcgis api的最短路径分析接口,routeParams以及routeTask,routeParams用来设置一些关于路径分析的参数,routeTask是用来执行路径分析方法的,具体的要看看api的介绍才行。备注:该功能模块的核心前提是要发布网络分析服务,这个在我的博客其他文章有写的
总的来说,获取两个点坐标,保存在一个stops数组里面,然后设置routeParams的属性,routeParams对象有个属性是stops,除了stops之外,还有attributeParameterValues、directionsLengthUnits、returnDirectionsreturnDirections、returnRoutes、returnStops等等;最好是执行routeTask.solve(routeParams);
eDirectionsWidget.xml:配置一些路径分析的信息
<?xml version="1.0" ?> <configuration> <url>http://localhost:6080/ArcGIS/rest/services/gzRoad/NAServer/路径</url> <useproxy>false</useproxy> <!-- <locatorurl>http://172.16.6.67/ArcGIS/rest/services/guangzhou_loc/GeocodeServer</locatorurl> --> <locatorurl>http://localhost:6080/ArcGIS/rest/services/ns_loc_Composite/GeocodeServer</locatorurl> <routeoptions /> <fromTx>广州市南沙区信访局</fromTx> <toTx>小虎一桥</toTx> </configuration> <!-- See Directions widget tag reference at http://links.esri.com/directionswidget -->
eTabDirectionsWidget.mxml:
<?xml version="1.0" encoding="utf-8"?> <!-- /////////////////////////////////////////////////////////////////////////// // Copyright (c) 2013 Esri. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /////////////////////////////////////////////////////////////////////////// --> <viewer:BaseWidget xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:viewer="com.esri.viewer.*" xmlns:esri="http://www.esri.com/2008/ags" xmlns:RichTabNavigator="com.RichTabNavigator.*" initialize="basewidget_initializeHandler(event)" widgetConfigLoaded="basewidget_widgetConfigLoaded()"> <viewer:states> <s:State name="textInput"/> <s:State name="resultsList"/> </viewer:states> <viewer:transitions> <s:Transition autoReverse="true" toState="*"> <s:Fade id="fade"/> </s:Transition> </viewer:transitions> <fx:Script> <![CDATA[ import com.esri.ags.FeatureSet; import com.esri.ags.Graphic; import com.esri.ags.SpatialReference; import com.esri.ags.events.DrawEvent; import com.esri.ags.events.LocatorEvent; import com.esri.ags.events.RouteEvent; import com.esri.ags.geometry.Extent; import com.esri.ags.geometry.Geometry; import com.esri.ags.geometry.MapPoint; import com.esri.ags.geometry.Polyline; import com.esri.ags.portal.PopUpRenderer; import com.esri.ags.portal.supportClasses.PopUpInfo; import com.esri.ags.symbols.TextSymbol; import com.esri.ags.tasks.supportClasses.AddressCandidate; import com.esri.ags.tasks.supportClasses.AddressToLocationsParameters; import com.esri.ags.tasks.supportClasses.DirectionsFeatureSet; import com.esri.ags.tasks.supportClasses.NAOutputLine; import com.esri.ags.tasks.supportClasses.RouteResult; import mx.collections.ArrayCollection; import mx.containers.Panel; import mx.containers.TitleWindow; import mx.controls.Alert; import mx.controls.Text; import mx.controls.TextArea; import mx.core.IVisualElement; import mx.core.UIComponent; import mx.events.CloseEvent; import mx.events.EffectEvent; import mx.events.FlexEvent; import mx.events.ListEvent; import mx.events.ModuleEvent; import mx.events.ResizeEvent; import mx.formatters.*; import mx.managers.PopUpManager; import mx.rpc.AsyncResponder; import mx.rpc.Fault; import mx.rpc.events.FaultEvent; import spark.components.NavigatorContent; import spark.events.IndexChangeEvent; import spark.primitives.Path; private const ICON_URL:String = "assets/images/"; private var textsearchLabel:String="路径分析"; private var resultsLabel:String="分析结果"; [Bindable] private var fromText:String; [Bindable] private var toText:String; protected function basewidget_initializeHandler(event:FlexEvent):void { if (isPartOfPanel) // if widget is part of "left", "right" or "bottom" panel { this.percentWidth = this.percentHeight = 100; wTemplate.percentWidth = wTemplate.percentHeight = 100; } else { wTemplate.height = map.height - map.height / 100 - Number(this.top) - Number(this.bottom); wTemplate.width = 440; } } private function basewidget_widgetConfigLoaded():void { // hide map infowindow if any map.infoWindow.hide(); if (configXML) { sUrl = configXML.url[0]; var useProxyForDirections:Boolean = configXML.useproxy[0] && configXML.useproxy == "true"; locatorURL = configXML.locatorurl[0]; fromText=configXML.fromTx[0]; toText=configXML.toTx[0]; } wTemplate.addTitlebarButton(ICON_URL + "i_searchtext.png", textsearchLabel, showStateTextSearch); wTemplate.addTitlebarButton(ICON_URL + "i_table.png", resultsLabel, showStateResults); fade.targets = [ textInput, resultsList ]; wTemplate.visible = true; } private function showStateTextSearch():void { this.currentState = "textInput"; wTemplate.selectedTitlebarButtonIndex = 0; } private function showStateResults():void { this.currentState = "resultsList"; wTemplate.selectedTitlebarButtonIndex = 1; } ////////////////////////////////////////////////////// //路径分析功能部分代码 [Bindable] private var sUrl:String;//="http://172.16.6.67/ArcGIS/rest/services/gzRoad/NAServer/路径"; [Bindable] private var locatorURL:String; private var stopType:String; private var fromGraphic:Graphic; private var toGraphic:Graphic; [Bindable] private var startTime:Date=new Date(); [Bindable] private var endTime:Date; [Bindable] private var travelTypeList:ArrayCollection = new ArrayCollection( [ { label: "步行", data: 0 }, { label: "驾车", data: 1 }, {label: "自行车", data: 2 }]); [Bindable] private var attributeParameters:Array = new Array({ "attributeName" : "Time", "parameterName" : "TravelType", "value" :1}); [Bindable] private var impedanceAttributes:ArrayCollection = new ArrayCollection( [ { label: "最短距离", data: "Distance" }, { label: "最少时间", data: "Time" }]); [Bindable] private var restrictionAttributes:Array=new Array("walking"); private const NL:String = "\n"; [Bindable]private var stopsFS:FeatureSet = new FeatureSet(); private var directionResult:directionResultGroup; private var segmentGraphic:Graphic; private var tabImpactIndex:int = 0; private function getDirections():void { //hanhh /* directionResult =new directionResultGroup(); tabImpact.addChild(directionResult); tabImpactIndex = tabImpact.numChildren-1; tabImpact.selectedIndex = tabImpactIndex; */ //add by lizeping ,2014/02/13 startTime=startDateField.selectedDate; startTime.hours=hoursStepper.value; startTime.minutes=minutesStepper.value; stopsFS.features = []; segmentGraphic = null; //hanhh // directionResult.map = map; // map.defaultGraphicsLayer.clear(); var fromParameters:AddressToLocationsParameters = new AddressToLocationsParameters(); fromParameters.distance=0.005; fromParameters.address = { SingleLine: fromTx.text, CountryCode: 'US' }; fromParameters.outFields = [ "Loc_name" ]; locator.addressToLocations(fromParameters, new AsyncResponder( myResultFunction, myFaultFunction, "From")); var toParameters:AddressToLocationsParameters = new AddressToLocationsParameters(); toParameters.address = { SingleLine: toTx.text, CountryCode: 'US' }; toParameters.distance=0.005; toParameters.outFields = [ "Loc_name" ]; locator.addressToLocations(toParameters, new AsyncResponder( myResultFunction, myFaultFunction, "To")); function myResultFunction(result:Array, token:String = null):void { solveRoute(result, token); } function myFaultFunction(error:Fault, token:Object = null):void { Alert.show(error.faultString, "Locator Error"); } } private function solveRoute(addressCandidates:Array, type:String):void { if (addressCandidates.length == 0) { Alert.show(type + " address not found.", "Missing Result"); return; } var stop:AddressCandidate = addressCandidates[0]; if (type == "From") { map.defaultGraphicsLayer.remove(fromGraphic); fromGraphic = new Graphic(stop.location, fromSymbol, { address: stop.address, score: stop.score }); map.defaultGraphicsLayer.add(fromGraphic); stopsFS.features[0] = fromGraphic; } else if (type == "To") { map.defaultGraphicsLayer.remove(toGraphic); toGraphic = new Graphic(stop.location, toSymbol, { address: stop.address, score: stop.score }); map.defaultGraphicsLayer.add(toGraphic); stopsFS.features[1] = toGraphic; } if (stopsFS.features[0] && stopsFS.features[1]) { routeParams.attributeParameterValues=attributeParameters; routeTask.solve(routeParams); } } private function solveCompleteHandler(event:RouteEvent):void { directionResult =new directionResultGroup(); tabImpact.addChild(directionResult); tabImpactIndex = tabImpact.numChildren-1; tabImpact.selectedIndex = tabImpactIndex; directionResult.map = map; showStateResults(); var routeResult:RouteResult = event.routeSolveResult.routeResults[0]; directionResult.directionsFS = routeResult.directions; //add at 2014-01-08 //var route:Graphic=routeResult.route; directionResult.route=routeResult.route; directionResult.graphicLayer.add(fromGraphic);//图标传给动态生成的tab页 directionResult.graphicLayer.add(toGraphic);//图标传给动态生成的tab页 map.defaultGraphicsLayer.clear(); directionResult.showResult(); } private function faultHandler(event:FaultEvent):void { Alert.show(event.fault.faultString + "\n\n" + event.fault.faultDetail, "Routing Error " + event.fault.faultCode); } private function formatDistance(dist:Number, units:String):String { var result:String = ""; var d:Number = Math.round(dist * 100) / 100; if (d != 0) { result = d + " " + units; } return result; } private function formatTime(time:Number):String { var result:String; var hr:Number = Math.floor(time / 60); var min:Number = Math.round(time % 60); if (hr < 1 && min < 1) { result = ""; } else if (hr < 1 && min < 2) { result = min + " 分钟"; } else if (hr < 1) { result = min + " 分钟"; } else { result = hr + " 小时 " + min + " 分钟"; } return result; } protected function cmbTravelType_changeHandler(event:ListEvent):void { // TODO Auto-generated method stub attributeParameters = new Array({ "attributeName" : "Time", "parameterName" : "TravelType", "value" : cmbTravelType.selectedItem.data}); if(cmbTravelType.selectedItem.data==0){ trace("use walking"); restrictionAttributes=new Array("walking"); }else{ restrictionAttributes=new Array("driving"); } routeParams.attributeParameterValues=attributeParameters; } protected function cmbImpedance_changeHandler(event:ListEvent):void { routeParams.impedanceAttribute=cmbImpedance.selectedItem.data; } protected function btnFrom_clickHandler(event:MouseEvent):void { // TODO Auto-generated method stub stopType="From"; myDrawTool.markerSymbol=fromSymbol; myDrawTool.activate(DrawTool.MAPPOINT); } protected function btnTo_clickHandler(event:MouseEvent):void { // TODO Auto-generated method stub stopType="To"; myDrawTool.markerSymbol=toSymbol; myDrawTool.activate(DrawTool.MAPPOINT); } protected function drawTool_drawEndHandler(event:DrawEvent):void { // reset after finished drawing a feature myDrawTool.deactivate(); //查询地址信息 if(stopType=="From"){ map.defaultGraphicsLayer.remove(fromGraphic); fromGraphic=event.graphic; }else{ map.defaultGraphicsLayer.remove(toGraphic); toGraphic=event.graphic; } var point:MapPoint=event.graphic.geometry as MapPoint; locator.locationToAddress(point, 1000); } private function onLocationToAddressComplete(event:LocatorEvent):void { var candidate:AddressCandidate = event.addressCandidate; if (candidate && candidate.address && candidate.address.Address) { var address:Object = candidate.address; if(stopType=="From"){ fromTx.text=address.Address; } else{ toTx.text=address.Address; } } else { Alert.show("This location does not have a known street address."); } } private function onFault(event:FaultEvent):void { if (event.fault.name == 'Error' && event.fault.faultCode == '500' && event.fault.faultString == 'An unexpected error occurred processing the request.') { Alert.show("Did you click too far from a road?\n\n" + event.fault.faultDetail, "No result"); } else { Alert.show(event.fault.faultString + "\n\n" + event.fault.faultDetail, "Reverse Geocoding Error " + event.fault.faultCode); } } private function widgetClosedHandler(event:Event):void { map.defaultGraphicsLayer.clear(); } ]]> </fx:Script> <fx:Declarations> <!-- Symbol for all point shapes --> <esri:DrawTool id="myDrawTool" drawEnd="drawTool_drawEndHandler(event)" graphicsLayer="{map.defaultGraphicsLayer}" map="{map}"/> <!--http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer--> <esri:Locator id="locator" fault="onFault(event)" locationToAddressComplete="onLocationToAddressComplete(event)" outSpatialReference="{map.spatialReference}" showBusyCursor="true" url="{encodeURI(locatorURL)}"/> <esri:RouteTask id="routeTask" concurrency="last" fault="faultHandler(event)" requestTimeout="30" showBusyCursor="true" solveComplete="solveCompleteHandler(event)" url="{encodeURI(sUrl)}"/> <esri:RouteParameters id="routeParams" attributeParameterValues="{attributeParameters}" directionsLengthUnits="esriMeters" outputGeometryPrecisionUnits="esriDecimalDegrees" outSpatialReference="{map.spatialReference}" restrictionAttributes="{restrictionAttributes}" returnDirections="true" returnRoutes="true" returnStops="true" startTime="{startTime}" stops="{stopsFS}"/> <!--<esri:SimpleMarkerSymbol id="fromSymbol" color="0x00FF00"/>--> <!--<esri:SimpleMarkerSymbol id="toSymbol" color="0xFF0000"/>--> <esri:PictureMarkerSymbol id="fromSymbol" source="assets/skins/directions/green-A.png"/> <esri:PictureMarkerSymbol id="toSymbol" source="assets/skins/directions/blue-B.png"/> <esri:SimpleLineSymbol id="routeSymbol" width="4" alpha="0.5" color="0x0000FF"/> <esri:SimpleLineSymbol id="segmentSymbol" width="8" alpha="0.5" color="0xFF0000"/> <esri:SimpleLineSymbol id="tempSymbol" width="8" alpha="0" color="0xFF0000"/> <s:DateTimeFormatter id="dtFormatter" dateTimePattern="MM/dd/yy, HH:mm"/> </fx:Declarations> <viewer:WidgetTemplate id="wTemplate" closed="widgetClosedHandler(event)" width="340" height="520"> <s:Group id="textInput" visible="false" width="100%" height="100%" visible.textInput="true"> <s:Form width="100%"> <!-- 更改垂直间距 --> <s:layout> <s:FormLayout gap="-14"/> </s:layout> <s:FormItem label="起点:"> <s:HGroup width="100%"> <s:TextInput id="fromTx" text="{fromText}" width="90%"/> <s:Image id="addFrom" buttonMode="true" click="btnFrom_clickHandler(event)" height="30" source="@Embed('assets/skins/directions/add-stop.png')" toolTip="{resourceManager.getString('ESRIMessages', 'directionsAddDestinationByMapClickTooltip')}" useHandCursor="true"/> </s:HGroup> </s:FormItem> <s:FormItem label="终点:"> <s:HGroup width="100%"> <s:TextInput id="toTx" text="{toText}" width="90%"/> <s:Image id="addTo" buttonMode="true" click="btnTo_clickHandler(event)" height="30" source="@Embed('assets/skins/directions/add-stop.png')" toolTip="{resourceManager.getString('ESRIMessages', 'directionsAddDestinationByMapClickTooltip')}" useHandCursor="true"/> </s:HGroup> </s:FormItem> <s:FormItem label="出行方式:"> <mx:ComboBox id="cmbTravelType" change="cmbTravelType_changeHandler(event)" dataProvider="{travelTypeList}" selectedIndex="1"/> </s:FormItem> <s:FormItem label="路径选择:"> <mx:ComboBox id="cmbImpedance" change="cmbImpedance_changeHandler(event)" dataProvider="{impedanceAttributes}" selectedIndex="0"/> </s:FormItem> <s:FormItem label="出发时间:"> <s:HGroup><mx:DateField id="startDateField" formatString="YYYY-MM-DD" height="30" selectedDate="{new Date()}"> </mx:DateField> <s:NumericStepper id="hoursStepper" width="40" maximum="24" minimum="1"> </s:NumericStepper><s:Label text="时"/> <s:NumericStepper id="minutesStepper" width="40" maximum="59" minimum="0"></s:NumericStepper><s:Label text="分"/> </s:HGroup></s:FormItem> <s:FormItem> <s:Button label="查询" click="getDirections()" height="30"/> </s:FormItem> </s:Form> </s:Group> <s:Group id="resultsList" visible="false" width="100%" height="100%" visible.resultsList="true"> <RichTabNavigator:RichTabNavigator id="tabImpact" width="100%" height="100%" backgroundAlpha="0" cornerRadius="5" dropShadowVisible="false" horizontalAlign="left" paddingTop="-1" tabHeight="30" tabWidth="110" borderVisible="true"> </RichTabNavigator:RichTabNavigator> </s:Group> </viewer:WidgetTemplate> </viewer:BaseWidget>
备注:
GIS技术交流QQ群:432512093
WebGIS二次开发培训入门群: 238339408