Arcgis apis for flex项目实例—开发篇(6):自己的infowindow

前文已经完成了从数据库查询旅游景点的工作,下面就是要把这些查询的结果显示到地图上,同时要实现查询列表和地图的联动。也就是点击列表中的某一项,地图能定位至该位置并弹出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>

如此全部设计功能实现,照例来一张效果:

到此,项目设计的主要功能就完成了。当然目前项目的这个样子就交付不是很合适,后面要对项目做一系列界面调整与美化,这就要开启我们的美工部分了。

时间: 2024-10-29 19:11:36

Arcgis apis for flex项目实例—开发篇(6):自己的infowindow的相关文章

Arcgis apis for flex项目实例—开发篇(1):地图浏览

前文已经明确数据用天地图,这样的选择一来是免费,二来各种来源的数据都大同小异,天地图用的2000坐标系是常见的经纬度,方便专题数据叠加. 闲话少说,看一下arcgis api for flex是如何吃定天地图的吧.首先要明确的是我们需要用到四个天地图瓦片服务,分别是经纬度地图底图.经纬度地图中文注记.经纬度影像底图.经纬度影像中文注记,详情可以参阅http://www.tianditu.com/guide/index.html.各种服务形式上都差不多,我们来写一个天地图图层类. 首先新建一个类,

Arcgis apis for flex项目实例—开发篇(2):鹰眼图

在底图调用完成后,我们要为地图添加一些工具,首先就是出场率很高的鹰眼图.我这里的鹰眼图是从ESRI的Flex Viewer中剥离出来的,申明一下,怕ESRI说我侵权.经常有人质疑我为什么不直接用Viewer而要费心思自己去写一些组件.我个人的经验是Viewer东西太多了,很臃肿,对于我们这样有整洁强迫症的人来说工程里存在大量用不着的代码非常难受,其实也不光是心理作用了,确实Viewer不经过大量优化会加载比较慢.但是,Viewer中有很多思想和很多组件是非常好用的,比如这个鹰眼,所以我们依然要借

Arcgis apis for flex项目实例—开发篇(5):查询

前文已完成了基本的地图工具,现在要开始一个GIS项目的核心内容——查询.按这个项目的设计,查询要分为政区查询和关键字查询两类,其实都大同小异,这里就只按关键字查询来写了. 查询在一个系统中一般有几个要素,一是要有条件输入,这里就是一个文本框和一个搜索按钮:二是要有结果列表,项目设计的左侧区域就承担了这个任务,计划用一个list来实现:三是要有地图展示,地图展示主要是把查询结果在地图上用符号标注出来,并且能提供一个infowindow来展示详细信息.本节内容不包括第三点,与地图的一些联动在下节单独

Arcgis apis for flex项目实例—开发篇(3):地图级别控制器

地图级别控制器俗称“鱼骨头”,这几乎是Web地图的标配了.ESRI的flex api自带了级别控制器叫做zoomSlider,我觉得是非常的难看,难看的和“鱼骨头”都不太沾边,给任何客户提供这样的一个组件都是非常不严肃的事情,我的选择是要么索性不提供这个工具,要么,就自己做一个.这是我做的组件的效果: 这个组件可以整合很多的地图工具,本节只讨论中间的那个滑块部分,就是从“+”到“-”之间的部分,其他的工具留给下一节. 先来看布局,一个Group把所有的部件框起来,放下两个按钮.两个Rect.两个

Arcgis apis for flex项目实例—开发篇(4):测距工具

这一节就是要完成一个很常见的动态测距工具,一边绘制测距线,一边给出每个节点的结果.顺便把基本的四个方向的移动.放大.缩小.自由平移等map工具都补全. 四个方向的箭头很简单,我直接贴代码了. <commonitem:NavButton id="btn_up" top="10" horizontalCenter="0" icon="image/up_arrow.png" click="map.panUp()&qu

Arcgis apis for flex项目实例—美工篇(1):样式与布局

前文已完成基本的功能,该是进入美工阶段了.我也只是一个小前端程序员,没有能力把页面做的美如画,美工的原则只有两点:一是采用大众化的页面风格,配色和谐,符合大多数用户的操作习惯:二是尽可能采用自定义控件样式,不要出现flex自带的控件样式.这一节先简要介绍一下总体的样式和布局.改变一下习惯,先美工处理过后的效果图: 从最终的结果看主要由几点改变:首先是有了主题色——绿.蓝.橙为主的组合:其次是加入了一些页面元素,页面整体变得丰满:然后是很多控件样式发生了变化,如滚动条.地图切换按钮.搜索框.工具按

Arcgis apis for flex项目实例—谋局篇(2):界面设计

界面设计是谋局当中第二个任务,也是很重要的,这个和概念设计排名不分先后.合理的界面布局会给用户带来非常舒心的体验,在项目之处就能把界面风格和布局确定下来,更是可以让后面的开发事半功倍. First:基本布局.我们不是艺术家,不是激进派,四平八稳符合我们的风格,也符合快速开发的要求,布局就采用上天下地,左表右图的经典百度地图式布局,下面开始. 基本元素:三个border.一个是主窗口,也就是map,一个border是网站的头部,也就是展示个名字放点图片当好看的:一个border是左侧栏,用于查询输

南沙政府应急系统之GIS一张图(arcgis api for flex)讲解(一)GIS一张图的系统开发环境以及flexviewer框架

系统的GIS功能实现是基于arcgis api for flex,首先附上系统的主界面图,接下来的是对主界面的模块功能详细讲解: 一.GIS环境软件安装 (1)arcgis desktop的安装,要是不想对地图数据进行样式配置或者数据加工的话,这步可以跳过不用安装,详细的安装步骤见这里: (2)arcgis server的安装,这个是必须的,用来发布webgis的地图服务,比如地图基础服务,路径分析的网络服务,地理编码服务等等,详细的安装步骤见这里: (3)arcsde直连创建地理企业数据库,为

《ArcGIS Runtime SDK for Android开发笔记》——(9)、空间数据的容器-地图MapView

1.前言 在上一篇内容里介绍了 关于ArcGIS Android开发的未来(“Quartz”版Beta)相关内容,期间也提到了关于API接口的重构,开发思路的调整,根据2015UC资料也可以知道新版预计将在明年的时候推出.届时在开发思路上将会往新版迁移. 总的来说,虽然“Quartz”版的开发思路有所变化,但总体变化不大,这里我将继续以现有正式发布版本为主梳理ArcGIS Runtime SDK for Android 开发内容. 参考API版本号:version 10.2.7.后续内容若不做特