我们之前分别品尝过Yahoo! Maps可口的甜饼、辛辣的烧饼,经过长时间的等待后,最近Yahoo终于发布了其旗下产品的Flash AS3开发类库,该类库包含AnswersWeatherSearchUpcoming.orgMaps等多项产品的开源AS3类库,开始了对As3的全面支持,Yahoo ActionScript 3 API大餐降临人间,今天我们就来和大家说说在Flex 2中怎样使用Yahoo!Maps AS3类库来创建我们自己的Yahoo!Maps Flex2应用…

我们之前分别品尝过Yahoo! Maps可口的甜饼、辛辣的烧饼,经过长时间的等待后,最近Yahoo终于发布了其旗下产品的Flash AS3开发类库,该类库包含AnswersWeatherSearchUpcoming.orgMaps等多项产品的开源AS3类库,开始了对As3的全面支持,Yahoo ActionScript 3 API大餐降临人间,今天我们就来和大家说说在Flex 2中怎样使用Yahoo!Maps AS3类库来创建我们自己的Yahoo!Maps Flex2应用。

从本次发布的Yahoo! Maps AS3类库的框架结构来看,Yahoo并没有将其Maps产品开发真正转向AS3转向Flex 2,这并不是一个真正意义的Yahoo! Maps As3类库,而只是一组通过ExternalInterface调用的Yahoo! Maps As2类库的AS3封装。实际所有的地图操作都是通过As2 API进行的。所以官方对该类库的称呼是:Yahoo! Maps AS3 Communication Kit,因为它只是一个As3到As2的通信包而已,不过却很精巧

该AS3通信包的核心组件是com.yahoo.webapis.maps.YahooMapService,该类继承mx.controls.SWFLoader,它的作用就是载入As2类库,并在载入AS2 SWF文件时,通过URL将AS3的ID等信息传递给AS2。而As3与As2之间的跨虚拟机通信也很简单,所有的通信都是通过HTML页面中的负责载入SWF的Object对象来交互的,首先在As2端通过ExternalInterface.addCallback方法将与Yahoo!Maps相关的API方法添加到HTML中Object对象上以提供给AS3调用(例如:ExternalInterface.addCallback( ’setPanTool’ + id, this, setPanTool )),而AS3/Flex2端则通过ExternalInterface.call方法调用前面As2端添加到HTML Object对象上的方法(如:ExternalInterface.call(super.swfDomId + “.setPanTool” + super.UUID,data:bool))来对Yahoo!Maps进行操作。相应的,As3/Flex2端将用来监听Yahoo!Maps事件的方法通过ExternalInterface.addCallback添加到HTML页面中的Object对象中,而在As2监听到了Yahoo!Maps相应的事件时,通过ExternalInterface.call来调用As3中的事件监听方法。整个交互的过程简单和精巧,对ExternalInterface的应用简直到了炉火纯青的地步,如果您觉得我表述的不清楚,可以看下面的以上原理部分概念图,因为Flex中监听Yahoo!maps事件与调用的过程类似只不过是正好相反的过程,所以没有将其画出。您如果花点时间好好看看Yahoo!Maps As3类库您一定会有很大收获的。


(点击查看大图)

说了半天原理,现在我们开始动手构建我们的Yahoo!Maps应用,首先下载Yahoo!As3类库,将下载的zip文件解压,然后将source/as3目录添加到您的Flex工程的代码路径就可以了,另外在examples/maps/pipes目录下的as2map.swf是实际与Yahoo!Maps服务进行交互的As2类库,请将其复制到您的Flex工程的bin目录中。详细的安装方法设置方法请看官方说明

要在Flex2中构建Yahoo!Maps应用,首先我们需要声明Yahoo!Maps使用的命名空间,例如:

[xml]
<mx:Application
     xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:yahoo="com.yahoo.webapis.maps.*"
     layout="absolute">

然后再定义以下几个变量:

  1. SWFDOMID:String,与HTML页面中的<OBJECT/>标签的ID号一致,供调用Object上的外部方法使用,一般FlexBuilder生成的HTML页面中Object标签的id为Flex主程序的文件名。所以我们这里一般定义SWFDOMID为使用Yahoo!Maps服务的Flex2 Mxml文件名。
  2. UNIQUEID:int,用于在AVM通信过程中唯一标识应用,避免但应用多个实例的情况下出现冲突。官方的做法使用使用mx.utils.getTimer()来生成UNIQUEID。
  3. YAHOOAPIKEY:String,向Yahoo申请的开发基于Yahoo!服务的API Key。如果您没有,可以到这里申请。
  4. MAPSWF:String,As2 Lib SWF文件完整路径名,如as2map.swf。

下面是定义好以上变量的代码:

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"  xmlns:yahoo="com.yahoo.webapis.maps.*"
    layout="absolute">
<mx:Script>
   <![CDATA[
      import flash.utils.getTimer;  

      private const SWFDOMID:String = "YahooAS3Maps";
      private const UNIQUEID:int = getTimer();
      private const YAHOOAPIKEY:String = "InsertYourAPIKeyHere";
      private const MAPSWF:String = "as2map.swf";
   ]]>
</mx:Script>
</mx:Application>

接着,我们实际将Yahoo!Maps添加到我们的应用中,代码很简单仅仅只需要增加一个yahoo:YahooMapService标签就可以了:

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:yahoo="com.yahoo.webapis.maps.*"
    layout="absolute">
<mx:Script>
   <![CDATA[
      import flash.utils.getTimer;  

      private const SWFDOMID:String = "YahooAS3Maps_Prac1";
      private const UNIQUEID:int = getTimer();
      private const YAHOOAPIKEY:String = "InsertYourAPIKeyHere";
      private const MAPSWF:String = "as2map.swf";
   ]]>
</mx:Script>
<yahoo:YahooMapService id="myAS2Map" UUID="{UNIQUEID}"
    swfDomId="{SWFDOMID}" apiId="{YAHOOAPIKEY}" mapURL = "{MAPSWF}"
    horizontalCenter="0" verticalCenter="0" />
</mx:Application>

运行示例

以上代码我们已经将Yahoo!Maps载入到了我们的Flex2应用中,因为载入地图数据需要时间,如果网络或其他的问题,这个载入过程可能失败,所以在添加后续的功能前,我们需要知道什么时候地图载入了、载入失败是否失败。这个很容易,只需要监听YahooMapService的onMapLoad和onMapError事件就可以了,代码如下:

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  xmlns:yahoo="com.yahoo.webapis.maps.*"
  layout="absolute"  creationComplete="init();" >
  <mx:Script>
      <![CDATA[
         import flash.utils.getTimer;
         import mx.controls.Alert;

         private const SWFDOMID:String = "YahooAS3Maps_Prac2";
         private const UNIQUEID:int = getTimer();
         private const YAHOOAPIKEY:String = "Bw7URnLV34GfW9XPiq2zQOoVbmh0h7S5s2W6F3qya9uDVR2HDqpodcYvpcWc";
         private const MAPSWF:String = "as2map.swf";

         private function init():void {
           myAS2Map.addEventListener('onMapLoad', onMapLoaded);
           myAS2Map.addEventListener('onMapError', onMapError);
        }
        private function onMapLoaded(ev:Object):void {
        }

        private function onMapError(errorCode:String, httpStatus:String):void {
           Alert.show(errorCode + '\n' + httpStatus, 'Load Error');
        }
      ]]>
  </mx:Script>
  <yahoo:YahooMapService id="myAS2Map" UUID="{UNIQUEID}"
    swfDomId="{SWFDOMID}" apiId="{YAHOOAPIKEY}" mapURL = "{MAPSWF}"
    horizontalCenter="0" verticalCenter="0" />
</mx:Application>

运行示例

您可以能已经注意到了,前面示例中的地图只是显示出来,不能进行任何的如拖动等的交互操作,还不能像实际的Yahoo!Maps一样可以鼠标点击或拖动,下面我们将逐步完善我们的代码以实现一个完之的Yahoo!Maps应用。

首先添加鼠标点击和拖动操作支持,在Yahoo!Maps载入后,我们在onMapLoaded先初始化一个com.yahoo.webapis.maps.methodgroups.PanTool类,然后使用PanTool.setPanTool(true)使得Pantools可用:

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  xmlns:yahoo="com.yahoo.webapis.maps.*"
  layout="absolute"  creationComplete="init();" >
  <mx:Script>
      <![CDATA[
         import flash.utils.getTimer;
         import mx.controls.Alert;
         /***this is the new line***/
         import com.yahoo.webapis.maps.methodgroups.*;

         private const SWFDOMID:String = "YahooAS3Maps_Prac3";
         private const UNIQUEID:int = getTimer();
         private const YAHOOAPIKEY:String = "Bw7URnLV34GfW9XPiq2zQOoVbmh0h7S5s2W6F3qya9uDVR2HDqpodcYvpcWc";
         private const MAPSWF:String = "as2map.swf";

         private function init():void {
           myAS2Map.addEventListener('onMapLoad', onMapLoaded);
           myAS2Map.addEventListener('onMapError', onMapError);
        }
        private function onMapLoaded(ev:Object):void {
          /***this is the new line***/
          var panTools:PanTool = new PanTool(myAS2Map);
          panTools.setPanTool(true);
        }

        private function onMapError(errorCode:String, httpStatus:String):void {
           Alert.show(errorCode + '\n' + httpStatus, 'Load Error');
        }
      ]]>
  </mx:Script>
  <yahoo:YahooMapService id="myAS2Map" UUID="{UNIQUEID}"
    swfDomId="{SWFDOMID}" apiId="{YAHOOAPIKEY}" mapURL = "{MAPSWF}"
    horizontalCenter="0" verticalCenter="0" />
</mx:Application>

运行示例

接着与前面类似我们使用Widgets添加导航控件(NavigatorControl)和卫星地图控件(SatelliteControl):

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  xmlns:yahoo="com.yahoo.webapis.maps.*"
  layout="absolute"  creationComplete="init();" >
  <mx:Script>
      <![CDATA[
         import flash.utils.getTimer;
         import mx.controls.Alert;

         import com.yahoo.webapis.maps.methodgroups.*;

         private const SWFDOMID:String = "YahooAS3Maps_Prac4";
         private const UNIQUEID:int = getTimer();
         private const YAHOOAPIKEY:String = "Bw7URnLV34GfW9XPiq2zQOoVbmh0h7S5s2W6F3qya9uDVR2HDqpodcYvpcWc";
         private const MAPSWF:String = "as2map.swf";

         private function init():void {
           myAS2Map.addEventListener('onMapLoad', onMapLoaded);
           myAS2Map.addEventListener('onMapError', onMapError);
        }
        private function onMapLoaded(ev:Object):void {
          var panTools:PanTool = new PanTool(myAS2Map);
          panTools.setPanTool(true);

          /***this is the new line***/
          var widgets:Widgets = new Widgets(myAS2Map);
          widgets.showNavigatorWidget(true);
          widgets.showSatelliteControlWidget(true);
        }

        private function onMapError(errorCode:String, httpStatus:String):void {
           Alert.show(errorCode + '\n' + httpStatus, 'Load Error');
        }
      ]]>
  </mx:Script>
  <yahoo:YahooMapService id="myAS2Map" UUID="{UNIQUEID}"
    swfDomId="{SWFDOMID}" apiId="{YAHOOAPIKEY}" mapURL = "{MAPSWF}"
    horizontalCenter="0" verticalCenter="0" />
</mx:Application>

运行示例

以上我们已经在Flex2应用中显示了一个有完整功能的Yahoo!Maps,我们还想监控一下地图操作信息,比如说在地图缩放过程中给用户一个正在缩放的提示,目前的API中,我们可以监听Maps操作过程中的如下事件:

  • onMapMove
  • onPanStart
  • onPanStop
  • onToolAdded
  • onToolChanged
  • onToolRemoved
  • onMapZoom
  • markerGeocode_Result
  • markerGeocode_Error
  • mapGeocode_Result
  • mapGeocodeError
  • swfMarkerAdded
  • onZoomStop
  • onZoomStart
  • dragStart
  • dragStop
  • getCenter_Result
  • getBounds_Result
  • onLocalSearchResult
  • onLocalSearchError

监听的方法也很简单,只需要用UNIQUEID先初始化一个com.yahoo.webapis.maps.events.MapEventDispatcher(该类初始化时回向HTML中的Object对象添加相应的回调方法以AS2 Maps中有事件发生时告知AS3端),然后再调用MapEventDispatcher.addEventListener添加事件监听就可以了,以下代码监听onZoomStop和onZoomStart事件,在用户缩放地图的时候显示缩放状态:

[xml]
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"  xmlns:yahoo="com.yahoo.webapis.maps.*"
  layout="absolute"  creationComplete="init();" >
  <mx:Script>
      <![CDATA[
         import flash.utils.getTimer;
         import mx.controls.Alert;

         import com.yahoo.webapis.maps.methodgroups.*;
         //new line here
         import com.yahoo.webapis.maps.events.MapEventDispatcher;

         private const SWFDOMID:String = "YahooAS3Maps_Event";
         private const UNIQUEID:int = getTimer();
         private const YAHOOAPIKEY:String = "Bw7URnLV34GfW9XPiq2zQOoVbmh0h7S5s2W6F3qya9uDVR2HDqpodcYvpcWc";
         private const MAPSWF:String = "as2map.swf";
         //new line here
         private var MEDispatcher:MapEventDispatcher;

         private function init():void {
           myAS2Map.addEventListener('onMapLoad', onMapLoaded);
           myAS2Map.addEventListener('onMapError', onMapError);
        }  

        private function onMapLoaded(ev:Object):void {
          var panTools:PanTool = new PanTool(myAS2Map);
          panTools.setPanTool(true);

          var widgets:Widgets = new Widgets(myAS2Map);
          widgets.showNavigatorWidget(true);
          widgets.showSatelliteControlWidget(true);
          //new line here
          MEDispatcher=new MapEventDispatcher(UNIQUEID);
          MEDispatcher.addEventListener("onZoomStart",onZoomStart);
          MEDispatcher.addEventListener("onZoomStop",onZoomStop);
        }
        private function onZoomStart(ev:Object):void{
          lb_status.text="zoom start";
        }
        private function onZoomStop(ev:Object):void{
          lb_status.text="zoom stop";
        }
        private function onMapError(errorCode:String, httpStatus:String):void {
           Alert.show(errorCode + '\n' + httpStatus, 'Load Error');
        }
      ]]>
  </mx:Script>
  <mx:VBox horizontalAlign="center" horizontalCenter="0" verticalCenter="0">
     <yahoo:YahooMapService id="myAS2Map" UUID="{UNIQUEID}"
         swfDomId="{SWFDOMID}" apiId="{YAHOOAPIKEY}" mapURL="{MAPSWF}"/>
     <mx:Label id="lb_status" />
  </mx:VBox>
</mx:Application>

运行示例

怎么样,Yahoo!Maps API很容易使用吧,除了我们上面提到的操作,Yahoo!Maps AS3 API还提供了很多其他的操作,更多信息请查看API文档

大餐已经上齐,就等您去发挥您的创意,创建您自己的Yahoo!Maps Flex应用了!