Yahoo!地図情報API Flash版をActionScriptで操作する

なんでこんなことを

どうしても地図をFlashの中で動かしたかったので。
GoogleMapならUMAPがありますが、Yahoo!地図情報の方が、(少なくともうちみたいな田舎では)見やすい感じだったのと、UMAPのサンプルよりもFlash版のYahoo!地図情報APIのほうがスムースに動く感じだったので、やってみました。

参考
Yahoo Flash版地図API を swf に読み込む
Yahoo Map Flash版API を Flash から操作

注意

僕はActionScript3初心者です。1も2もさわったことないActionScript3初心者です。
Flashもあんまし使いません。
ですので、ActionScript3でできる、基本的なことも知らず、おかしなことをしてるところがあると思います。
というかあります。絶対。
そういう点が見つかりましたら、ご指摘いただけると幸いです。

結果

<html>
  <head>
    <title>サンプル</title>
  </head>
  <body>
    <div id="mapdiv" style="width:800px;height:300px;border:solid 1px">
   <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
    codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/
swflash.cab#version=8,0,0,0"
    width="100%" height="100%" id="map" align="middle">
   <param name="allowScriptAccess" value="always" />
   <param name="movie" value="Sample.swf" />
   <param name="quality" value="high" />
   <param name="bgcolor" value="#ffffff" />
   <embed src="Sample.swf"
    quality="high" bgcolor="#ffffff" width="100%" height="100%"
    name="map" align="middle" allowScriptAccess="always"
    type="application/x-shockwave-flash"
    pluginspage="http://www.macromedia.com/go/getflashplayer" />
   </object>
  </body>
</html>
// Sample.as
package {
  import flash.display.Sprite;
  public class Sample extends Sprite {
    private var ymap:YMap;
    
    public function Sample() {
      var options:Object = {
        pos: "35.072555,134.009318",
        datum: 'wgs84',
        layer: 4,
        appid: "sampleapplication",
        initialized: onInitHandler
      };
      ymap = new YMap(options);
      addChild(ymap);
    }

    private function onInitHandler():void {
      ymap.call('addIcon', 'icon1', 35.080964, 134.013189, '津山高専')
    }

  }
}
// YMap.as
package {
  import flash.display.Sprite;
  import flash.display.Loader;
  import flash.net.URLRequest;
  import flash.external.ExternalInterface;
  import flash.utils.setTimeout;

  public class YMap extends Sprite {
    private var initHandler:* = null;
    private var mapID:String = ExternalInterface.objectID;
    private var baseUrl:String = "http://api.map.yahoo.co.jp/MapsService/Flash/V2/";
    // new YMap({pos:"lat,lon", appid:"demo", initialized: function(){});
    public function YMap(options:Object) {
      var params:Array = [];
      for (var key:String in options) {
        if(typeof(options[key]) == "function") {
          // コールバック設定
          params.push(key + '=' + mapID + 'Instance.on' + key);
          var callback:* = options[key];
          if(key == 'initialized') callback = initHandlerWrapper(callback);
          ExternalInterface.addCallback('on' + key, callback);
        } else {
          params.push(key + '=' + options[key]);
        }
      }
      ExternalInterface.call("function(id){var script = document.createElement('script'); script.type = 'text/javascript'; script.language = 'javascript'; script.text = 'var '+id+'Instance = null; if(navigator.appName.indexOf(\"Microsoft\") != -1){'+id+'Instance = window[\"'+id+'\"];}else{'+id+'Instance = document[\"'+id+'\"];};'; document.body.appendChild(script);}", mapID);
      var url:String = baseUrl + '?' + params.join('&');
      var request:URLRequest = new URLRequest(url);
      var loader:Loader = new Loader();
      loader.load(request);
      addChild(loader);
    }

    // 地図APIを使う
    // map.call('addIcon', 'icon1', latlon[0], latlon[1], '津山高専')
    // map.call('getCenter').lat
    public function call(method:String, ...args:Array):* {
      var methodName:String = mapID + "Instance." + method;
      switch(args.length) {
      case 0: return ExternalInterface.call(methodName);
      case 1: return ExternalInterface.call(methodName, args[0]);
      case 2: return ExternalInterface.call(methodName, args[0], args[1]);
      case 3: return ExternalInterface.call(methodName, args[0], args[1], args[2]);
      case 4: return ExternalInterface.call(methodName, args[0], args[1], args[2], args[3]);
      case 5: return ExternalInterface.call(methodName, args[0], args[1], args[2], args[3], args[4]);
      default: throw "argument too many";
      }
    }

    public function initHandlerWrapper(func:*):* {
      initHandler = func;
      return function():void {setTimeout(initHandler, 300)}
    }

    // wgs84→tokyo97変換(手軽なもの)
    public static function wgs2tokyo(lat:Number, lon:Number):Array {
      var result:Array = [];
      result[0] = lat - 0.003236111111111111;
      result[1] = lon + 0.0032027777777777775;
      return result;
    }
  }
}


追記1

IEOperaではonInitHandler内のアイコン追加などが動かなかった。
いろいろ検証してみたところ、どうやら上記ブラウザでは、onInitHandlerが呼ばれた時点(APIのinitialized=読み込み完了)でも、実はまだマップの表示が完了していなかったようです。
→initializedはsetTimeoutで少し遅らせるようにした。

追記2

IEOperaでは、ドラッグで移動した際にタイルをうまく読み込まず崩れちゃう模様(結構な頻度で)
んー、なんでだよorz