Flex 是 Adobe 公司开发的支持 RIA(Rich Internet Applications) 开发和部署的技术产品,借助于其强大的功能,Flex 能够开发基于 flash 的 web 界面,如果您熟悉 flash 开发的脚本语言 AS3(ActionScript3.0),开发 Flex 程序会相当容易。
Google Map API 是 Google 公司发布的用于将 Google 地图嵌入到开发者网页的 API,有 JavaScript 版本和 flash 版本。相比于传统的 WebGIS 系统开发,Google Map 的开发更加简单快捷,不仅具有更加强大的表现力 ( 比如有普通地图和卫星图等更加丰富的信息 ),而且学习成本和维护成本也大大降低。我们只要查看 Google 网页上提供的 API 教程就可以轻松使用了。
Web Service 是基于 XML 和 HTTPS 的一种服务,它向外界暴露出一个能够通过 Web 进行调用的 API。本文通过 PHP 调用了开源的 NuSOAP 来建立 Web Service,如果您对 PHP 有一定的了解,可以帮助理解 Web Service 的创建和调用过程。
环境搭建
Flex 基本环境的搭建
本章简单介绍本项目所需要的软件,具体的详细安装过程可参见本文的 参考资料。
首先需要下载并安装 Java SDK/Flex Builder/Eclipse/Tomcat
-
Flex Builder: Adobe 公司发布的 Flex 开发工具
-
Eclipse: IBM 公司最初发布的基于 Java 的 IDE 开发环境,可用于和 Flex build 集成开发
-
Java SDK: Java 环境的基本 SDK
-
Tomcat : 小型的轻量级应用服务器,用于将 Flex 开发的 flash 集成到网页中
安装并配置完以上环境之后就可以进行 Flex 的网页开发了。
Google Map Mashup 坏境开发
在 Flex 中要实现对 Google Map 的调用,需要下载 Google Maps API for Flash SDK,到 Google 网站上下载 zip 文件,并解压缩,同时将其中的 swf 文件加入到项目的 path 中。这样项目中就能调用 Google Map 提供的各类 API,实现 Google Map 的 mashup。
PHP Web Service 环境搭建
分别下载 PHP 和 Apache, 配置并搭建好 PHP+Apache 的开发环境。下载 NuSOAP 包,解压缩后放于服务器目录下,用于创建 Web Service 时进行调用。
至此,Flex/Google Map/PHP 的坏境已经全部搭建完成,可以开始系统的搭建。
系统建立和框架结构设计
作为一个拥有大量数据的实时演示系统,在系统设计时,需要考虑到数据显示的友好性、实时性、兼容性等各个方面的问题。在本文的系统中,我们希望系统能够达到以下几个要求:
-
采用网站形式进行访问,支持多用户同时进行远程访问;
-
数据显示友好性,访问到的数据会以地图为背景,将分属于各地的数据展现在地图之上,同时需要一定的图表增加数据的可读性;
-
支持多数据集成显示,数据的获取可能来自于不同的服务器,不同的数据库,需要系统支持多个数据源同时访问;
-
支持数据的异步性、框架模块化,消除各个数据源之间的耦合性,任一数据源的损坏不会影响其他数据的正常工作 ;
-
支持数据的动态性,使显示的数据能够动态更新,保持数据信息的实时性。
按照这些要求,设计好的系统框架结构如下图所示,多个用户可同时通过网络远程访问 Flex 写成的网站服务器,通过访问该网站,用户能够见到 Google 提供的地图信息,同时在该地图上获取各类有用的数据信息。而网站中的地图信息来源于 Google 网站,不同的数据信息来源于不同的远程 Web Service 上。
图 1. 系统整体框架图
采用 Flex 制作的 flash 可直接放置于网站之上,实现了多用户的同时访问,Google Map 与 Flex 的 mashup 增强了数据显示的友好性,以地图、表格、统计图的形式更加多样化得显示数据信息。Web Service 的采用使数据源、数据量更加丰富,Flex 中采用的异步机制既能消除数据之间的耦合性,增强系统的鲁棒性,同时也能保证数据获取的动态性,保证各个数据信息的实时性。完全达到了系统设计需求。
Flex+GoogleMap 的数据显示层界面开发
在 Eclipse 中新建一个项目,并将 Google Map 的 swf 文件加入 path 中 ( 查看环境搭建的章节 )。在项目中新建 mxml 文件,在主面板的下部嵌入 Google Map:
清单 1. Flex 中嵌入 Google Map
<maps:Map xmlns:maps="com.google.maps.*" id="map" mapevent_mapready="onMapReady(event)" key= "ABQIAAAAQEmZ1ekSRwiItdoHP8xyghTW6g7ka7Q2cQuEkLP86O0lTbUN2hSwW6hhb8VkG5uslDbQSOEhO3TJ_A" right="5" left="5" top="145" bottom="5"/> |
其中"key"的值为 Google Maps API key,需要到 Google 网站上进行申请。填入自己网站的地址之后,系统会帮你生成一个适合用于该网址的密钥。
嵌入面板之后,用 AS3(ActionScript3.0) 语言对 Google Map 上操作进行程序设计,加入地图上的标记信息、数据信息,同时做好鼠标响应函数。具体程序如下:
清单 2. Flex 中实现 Google Map 加载的 AS3 语言代码
<mx:Script> <![CDATA[ ...... import com.google.maps.*;/*import Google Map 的各类 class*/ import com.google.maps.controls.* import com.google.maps.overlays.* import com.google.maps.styles.* import com.google.maps.MapMoveEvent; import com.google.maps.MapMouseEvent; private function onMapReady(event:MapEvent):void { /* 开启 map,并进行初始化工作 */ map.setCenter(new LatLng(32.81163844500426,104.7087573122981), 5); /* 设置地图初始中心位置 */ map.addControl( new PositionControl( new PositionControlOptions() ) ) ;/* 加入地图各类控件 */ map.addControl( new OverviewMapControl( new OverviewMapControlOptions() ) ); map.addControl( new ZoomControl( new ZoomControlOptions() ) ); map.addControl( new MapTypeControl( new MapTypeControlOptions() ) ); map.enableScrollWheelZoom(); map.enableContinuousZoom(); var point:LatLng; point = new LatLng(cityarray[0].bw,cityarray[0].dj); /* 地图上建立图的标记,并监听鼠标 click 事件 */ marker_city[0] = new Marker(point); marker_city[0].addEventListener(MapMouseEvent.CLICK, /* 监听鼠标点击事件,动态显示不同图表 */ function(event:MapMouseEvent):void{ citylistbox.selectedIndex=0; Chongqing.visible=true; Shanghai.visible=false; Guangzhou.visible=false; Yanshi.visible=false; if (isdetail){ Chongqing_detail.visible=true; Shanghai_detail.visible=false; Guangzhou_detail.visible=false; Yanshi_detail.visible=false; } if (istemp){ Chongqing_temp.visible=true; Shanghai_temp.visible=false; Guangzhou_temp.visible=false; Yanshi_temp.visible=false; } chartwin.visible=true; line0.visible=true; }); map.addOverlay(marker_city[0]); point = new LatLng(cityarray[0].bw,cityarray[0].dj);/* 标记下的当前动态数据显示 */ textvalue0 = new MyTextValue(); var markert_t:Marker=new Marker(point, new MarkerOptions({icon:textvalue0})); map.addOverlay(markert_t); ]]> </mx:Script> |
嵌入 Google Map,并加入地图标记后的效果图如下:
图 2. Google Map 效果图图
(查看清晰图)
对于数据显示界面,我们需要各种表单来直观有效得表现数据,实现数据信息的可视性,本文在此介绍了几种数据的表现方式:动态表格搭建,动态统计图的绘画和动态温度分布图的展示。
动态表格搭建
表格的搭建和使用 Flex 内部的各个控件,包括 Panel、Label、TextInput。代码示例如下:
清单 3. Flex 中建立表格代码示例
<mx:Panel id="Shanghai" title="上海数据" label="Shanghai" x="276" width="525" height="131" visible="true" layout="absolute" backgroundAlpha="1.0" backgroundColor="#C8D5DD"> <mx:Label text="当前数据 :" width="85" fontWeight="bold" x="10.5" y="5" color="#3B2E72"/> <mx:TextInput id="cur_wat0" text="0" width="64" fontWeight="bold" x="90.5" y="3"/> <mx:Label text="次" width="46" fontWeight="bold" color="#0E5A35" x="162.5" y="5"/> <mx:TextInput id="cur_mny0" text="0" width="64" fontWeight="bold" x="216.5" y="3"/> <mx:Label text="万元 / 天" width="56" fontWeight="bold" color="#0E5A35" x="289.5" y="5"/> <mx:TextInput id="cur_co20" text="0" width="64" fontWeight="bold" x="349" y="3"/> <mx:Label text="吨 / 天 " width="76" fontWeight="bold" color="#0E5A35" x="419" y="5"/> ...... ...... </mx:Panel> |
Flex 表格的效果图如下:
图 3. 表格效果图
动态统计图的绘画
Flex chart 有统计图的功能可直接调用实现统计图的描绘,但是目前只是一个试用功能。编译好的统计图表上会产生“Flex Data Visualization Trial”的浮水印,它是由 AS3 动态加上去的。浮水印的出现会影响用户的使用,因此我们可以在 AS3 中自己写一个空类来重载浮水印部分的类,使浮水印功能失效。
在项目的 src 文件夹下,加入类 mx.charts.chartClasses:
清单 4. 重载 chartClasses 的代码
package mx.charts.chartClasses { public class ChartsLicenseHandler { public function ChartsLicenseHandler() { } } } |
同时,在 mxml 文件中的 AS3 语言中强制引用该类。
清单 5. 强制引用 chartClasses 的 AS3 语言代码
<mx:Script> <![CDATA[ ...... [Frame(extraClass="mx.charts.chartClasses.ChartsLicenseHandler")] ...... ]]> </mx:Script> |
去除浮水印的工作完成之后,我们可以新建一个 TitleWindow,并在上面放入 chart,下面是用 LineChart 来描绘统计图的一个实例:
清单 6. Flex 中画统计图代码
<mx:TitleWindow id="chartwin" visible="false" close="chartwin.visible=false; line0.visible=false;line1.visible=false;line2.visible=false" title="当前数据图" height="30%" width="32%" showCloseButton="true" left="10" top="150" layout="vertical" fontSize="12" backgroundColor="#B2BEF6" alpha="2" borderColor="#B6C1C7"> <mx:LineChart id="chart" height="100%" width="100%" paddingRight="5" paddingLeft="5" showDataTips="true" fontSize="12"> <mx:horizontalAxis > <mx:DateTimeAxis title="时间" dataUnits="seconds" interval="5" minimum="{minDate}" maximum="{maxDate}" labelFunction="mylabel" /> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis title="数据 ( 单位:次 )" baseAtZero="true" /> </mx:verticalAxis> <mx:series> <mx:LineSeries id="line0" visible="false" yField="valueTest" xField="date" form="curve" displayName="重庆" dataProvider="{chartDatas0}"/> <mx:LineSeries id="line1" visible="false" yField="valueTest" xField="date" form="curve" displayName="上海" dataProvider="{chartDatas1}"/> <mx:LineSeries id="line2" visible="false" yField="valueTest" xField="date" form="curve" displayName="广州" dataProvider="{chartDatas2}"/> <mx:LineSeries id="line3" visible="false" yField="valueTest" xField="date" form="curve" displayName="演示中心" dataProvider="{chartDatas3}"/> </mx:series> </mx:LineChart > <mx:Legend dataProvider="{chart}" height="24"/> </mx:TitleWindow> |
Chart 的最终统计图效果如下,面板以半透明的方式显示在地图之上,当有新的数据到达时,chart 中的各条统计线可进行动态更新:
图 4. 统计图效果
动态温度分布图
在一个地区或一个房间的温度分布图通常的显示方法是将平面分割成 n 多的小块,每一小块都以一种颜色来表示。若采用此方法就需要将小块设计得很小,即 n 值需要很大,因此,n 块的小块上都需要有一个温度估计值,且都要将温度值以颜色的形式展现出来。然而,此算法需要很大的计算量对 n 个值的温度进行估算,同时需要对 n 个小块进行不同着色,难以达到实时显示的功能。
本文用一种简单的算法,利用 Flex 中颜色显示的透明度可调节性,对平面中几个关键的冷热点进行了温度动态获取和平面动态绘画。平面中存在着一定的发热点和制冷点,本文就以这些设备为圆心,一定的长宽画椭圆,越远离圆心则颜色的透明度越高,若某些平面点同时受到几个发热点 / 制冷点的影响,则他们不同透明度的颜色可进行叠加覆盖,产生出复合的效果来表示当地温度的大小。Flex 中椭圆的画法可采用 AS3 语言来实现,如下所示:
清单 7. 画透明颜色的 AS3 语言代码
<mx:Script> <![CDATA[ ...... import mx.utils.GraphicsUtil; private var box:Graphics; var matrix:Matrix = new Matrix(); /* 设定好画圈的范围和位置 */ matrix.createGradientBox(Ser_len, Ser_width, Math.PI/4 , -Ser_len/2+ser1_1.width/5, -Ser_width/2+ser1_1.height/2+27*i); /* 设定好圆的颜色透明度,温度越高,红色透明度越小 */ box.beginGradientFill("radial",Ser_color,[Ser_color_alph[i+10],0],[ 0, 255 ],matrix); GraphicsUtil.drawRoundRectComplex(box,-Ser_len/2, -Ser_width/2+ser1_1.height/2+27*i, Ser_len,Ser_width,0,0,0,0); box.endFill(); ...... ]]> </mx:Script> |
动态温度分布的最终效果图可看如下图,画图面板也是以半透明形式置于地图之上,图中的发热点以红色椭圆来表示,制冷点以青色椭圆来表示,其余背景色由淡黄色和绿色叠加来表示。
此温度图不仅能表示总体面积上的温度趋势,更能体现出温度的热点分布情况,对于热点监测、分析的显示效果尤为突出。
图 5. 温度分布图效果
Web Service 的搭建与连接
PHP Web Service 的搭建
NuSOAP 是 PHP 环境下的开源软件,是完全由 PHP 编写而成的 Web Service 编程工具,可方便得用于创建和调用 Web Service。本文采用 NuSOAP 中的 nusoap_server 类来建立 Web Service,其具体的过程如下:
-
下载代码 ( 参照环境搭建章节 ),并解压到本地目录;
-
调用 NuSOAP,写 Web Service 服务器端代码。以下是提供一个函数的 Web Service 的代码:
清单 8. PHP 建立 Web Service 代码
<?php require_once("lib/nusoap.php"); function Get_data_ServX()// 创建函数:读取 ServX 的数据 { $doc = file("./AEM/lastday.txt"); $res[0][0]=$doc; $doc = file("./AEM/lastmon.txt"); $res[0][1]=$doc; return $res; } // 建立服务 $server = new nusoap_server();// 创建 nusoap_server 类的对象 $server->configureWSDL("myTestNuSOAPServer");// 进行配置 $server->register( "Get_data_ServX",// 注册函数 array(),// 函数输入为空 array("return"=>"SOAP-ENC:Array"),// 函数的输出为一数组 "http://" ); $server->service($GLOBALS['HTTP_RAW_POST_DATA']);// 开启服务 ?> |
建立起 Web Service 之后,我们就要在 Flex 中写入 client 端的程序,来调用 Web Service 中的函数,获取数据信息。Flex 中 AS3 语言代码如下:
清单 9. Flex 调用 Web Service 的 AS3 语言代码
<mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.Fault; import mx.rpc.events.ResultEvent; import mx.rpc.soap.LoadEvent; import mx.rpc.soap.WebService; /* 创建 Web Service 类的对象 */ public var srvc:WebService = new WebService(); srvc.loadWSDL("http://xxx.xxx.xxx/webservice/Ser_AEM.php?wsdl"); /* 加入错误监听,xxx.xxx.xxx 为 Web Service 网站地址 */ srvc.addEventListener(FaultEvent.FAULT, onWebServiceFault); srvc.addEventListener(LoadEvent.LOAD,onWSDL); /* 加入 Get_data_ServX 函数监听,调用回调函数 Res_data_ServX*/ srvc.Get_data_ServX.addEventListener(ResultEvent.RESULT, Res_data_ServX); /* 声明回调函数 */ public function Res_data_ServX(event:ResultEvent):void{ /* 获取 Web Service 函数的返回值 */ data_ServX = (event.result) as ArrayCollection; if (data_ServX == null){ return; } /* 获取的 array 型数据转换为数字类型 */ var tmp1:Number; var tmp2:Number; tmp1=data_ServX[0][0].toString(); tmp2=data_ServX[0][1].toString(); ...... /* 将获取到的数据在页面中进行更新 */ update_data(); } ]]> </mx:Script> |
解决跨域调用 Web Service 方法
至此,Flex 完成的网页数据可以成功访问 PHP 创建的 Web Service 了,能通过 Web Service 提供的服务对数据信息进行访问。但是当我们将网页放到网上时,发现了 Flex 制作的 flash 有跨域访问权限的问题,在 flash 对 Web Service 进行连接并访问时,会出现错误。我们需要在 Web Service 服务的机器上进行声明,对该 flash 网页进行授权。
在服务器根目录上创建文件“crossdomain.xml”,其具体内容为 (xxx.xxx.xxx 为 Flex 开发的客户网站地址 ):
清单 10. 解决跨域访问的 xml 文件
<?xml version="1.0" ?> <!DOCTYPE cross-domain-policy > <cross-domain-policy> <allow-access-from domain="xxx.xxx.xxx" secure="true" /> <allow-http-request-headers-from domain="xxx.xxx.xxx" headers="SOAPAction" secure="true" /> </cross-domain-policy> |
数据的动态更新
至此,我们已经建立好了数据显示系统的整体框架,能够静态显示数据表格、统计图和温度分布图。然而,监控系统需要有一个动态的的更新过程,保证显示的数据状态时当前最新的。因此,我们需要定时连接 Web Service 来获取数据,同时对该数据相对应的显示部分做相应的刷新。
清单 11. 定时器动态更新代码
<mx:Script> <![CDATA[ ...... private var timer:Timer; /* 设置定时器 */ timer = new Timer(2000); timer.addEventListener(TimerEvent.TIMER, getDatas)/* 监听定时器是否时间到 */ timer.start(); /* 声明时间到了之后调用的函数 */ public function getDatas(et:Event):void{ /*Web Service 定时获得 */ srvc.Get_data_ServX(); } ...... ]]> </mx:Script> |
最终系统演示
系统最终的演示图可如下所示,Flex 面板的上方是各类控件来控制数据的显示,包括数据显示的方式和数据显示的来源。同时,面板的上方还有数据的详细表格,使用户看起来更加便捷。Google Map 内嵌于 Flex 面板下方,能够显示地图和卫星模式,同时在地图上会有不同的图标和数据,从整体上更加直观得表现了数据的可视性。地图的上层可动态显示数据的动态统计图,分别有当前时刻数据动态图,日数据动态图,月数据动态图。地图的上层同时还显示了当前地区的热点动态图,展示热点温度分布。
图 6. 最终系统演示一
(查看清晰图)
图 7. 最终系统演示二
(查看清晰图)
图 8. 最终系统演示三
(查看清晰图)
图 9. 最终系统演示四
(查看清晰图)
参考资料
学习
-
“Flex 开发入门”:介绍 Flex 开发的基础知识,包括如何搭建开发环境,如何调试,以及如何建立和部署简单的 Flex 项目。
-
“用 Flex 开发 Google Map 应用程序”:在 flex 开发的基础上,介绍了如何用 Google Maps API for Flash 来开发基于 Flash 的地图应用程序。
-
“使用 Macromedia Flex 开发 Web 服务客户端”:介绍了 Flex 与 Web Service 的调用过程,概述了 WSDL 结构与 Flex 声明之间的映射关系
-
“NuSOAP - SOAP Toolkit for PHP”:介绍了 NuSOAP 包的应用,通过 NuSOAP 包来创建和调用 Web Service。
-
“developerWorks 中国”:有大量的开发资料文章和入门级、中级及高级教程。
-
developerWorks Web development 专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。
-
developerWorks Ajax 资源中心:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。
-
developerWorks Web 2.0 资源中心,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 Web 2.0 新手入门 栏目,迅速了解 Web 2.0 的相关概念。
-
查看 HTML5 专题,了解更多和 HTML5 相关的知识和动向。