園田 誠(そのだ まこと)

 地図というのはどうしてこうも男心をくすぐるんでしょうか。一通り知り合いの家あたりを見終わると,目に付いた道をまっすぐたどってどこまでいくのか見てみたくなります。そして突き当たると,この国道にも起点や終点があったんだなとか変なことに感動してみたり。プログラムなんかしなくてもこれはこれで楽しめるのかもしれま…いや,ちゃんと記事書きます。ごめんなさい。1965年生まれ。愛知県名古屋市出身のフリーライター。

 Virtual Earthは,グラフィックス・ソフトなどでおなじみのレイヤー機能を実装しています。レイヤーは,元になる画像の上に透明なセルシートを重ねていくような仕組みです。例えば,背景画の上に人物を描いたセル画を重ねると,背景と人物がうまくミックスされて,一枚の画像のように見えます(図1)。

図1●レイヤーの概念(a)
下向き矢印
図1●レイヤーの概念(b)
図1●レイヤーの概念。背景だけの絵に人物を描いたレイヤーを重ねると,透明部分は下になった絵が透けて見えるので,風景の中に人がいるような絵になる

 Virtual Earthでは,この機能を使って,地図の上に説明の文章を載せたり,線画を描いて経路や領域を表示するといったことが自由にできます。今回は,レイヤー機能に関するAPIの使い方を説明します。

2種類のレイヤー機能がある

 Virtual Earthは,基となる地図画面の上に,プログラムで自由にレイヤーを追加して重ねていくことができます。地図の上に地図を重ねるのではなく,地図の上に透明のレイヤーを重ねます。

 Virtual Earthには2種類のレイヤーがあります。マニュアルやリファレンスを読むときに混同しないように,最初に整理しておきましょう。一つはタイル・レイヤー(Tile Layers)で,もう一つはシェイプ・レイヤー(Shape Layers)です。

 タイル・レイヤーは,Virtual Earth SDK 3.2で実装された機能です。リファレンスが整備されていないので(コンストラクタのまともな引数説明すらない!),実体がわかりにくいかもしれません。地図上の任意の場所に透明レイヤーを重ね,そこに画像ファイルを読み込んで表示するものです。

 タイルレイヤーは名前の通り,指定された画像ファイルをタイル状に並べます。敷き詰めるという感じです。レイヤーを動的に追加する,削除する,隠す(表示されないけれど存在する),透明度や重ねる順番を指定する,といったことが可能です。

 一方のシェイプ・レイヤーは,SDK 5.0からの新機能です。画びょう,Polyline(連続した線),多角形図形を描画できます。これらの図形をVirtual Earthでは「シェイプ」と総称します。シェイプはVirtual Earthが持っている,あるいはVirtual Earthの関数で描画できます。つまり,簡単な図形描画機能を持っているというわけですね。シェイプ・レイヤーも動的に追加や削除,隠すといったことができます。

 シェイプは,レイヤーを用意しなくても直接地図の上に描画できます。背景になっている地図そのものも背景レイヤーという考え方です。例えば,「飲食店を表示」「コンビニエンスストアを表示」のようなチェックボックスがあって,ボタンを押すとチェックが入っている物だけを表示したいといった要望もあるわけです。それぞれのシェイプが別のレイヤーに描画されていれば,レイヤーを出したり隠したりするだけで,パッパッと表示の切り替えができます。こうしたレイヤー操作によって,プログラムそのものも簡略化できます。

タイル・レイヤーの実装

 では,最初にタイル・レイヤーのサンプルを作ってみましょう。タイル・レイヤーの作成には,VETileSourceSpecificationクラスを使います。サンプルの作成には画像ファイルが必要です。地図面が透ける物を用意したかったので,自分で透過ありのPNGファイルを作成しました(図2)。

図2●サンプルを実行するのに必要な画像。右クリックして画像を保存しtest.pngの名前でサンプルHTMLと同じディレクトリに入れてください
図2●サンプルを実行するのに必要な画像(test.png)。右クリックして画像を保存しtest.pngの名前でサンプルHTMLと同じディレクトリに入れてください

 タイル・レイヤーが読み込める画像形式には,特に制限はないようです。インターネットで一般的に使われているJPEG/GIF/PNGはどれも使用可能でした。透過GIFまたは透過PNGであれば,透明部分はそのままでレイヤーの下にある地図が透けます。もし塗りつぶした画像を使う場合は,透過度指定をして透けさせないと,完全に地図が隠れて見えなくなってしまいます。

 ただ敷き詰めるだけでは面白くないので,サンプル(リスト1)にはリンクを押すとレイヤーが段々と薄くなって消えていくというギミックを加えてみました。サンプルは,test.pngと同じディレクトリにtest4.htmlなどの名前で置いてください。例によってサーバーにアップロードする必要はなく,ローカルでダブルクリック実行できます。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html><head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src=
  "http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5">
</script>
<script>
    var map = null;
    //タイル・レイヤー生成
    var TILE = new VETileSourceSpecification("TL1","test.png");

    //フェードアウトのカウント用変数
    var i = 1;

    //初期表示
    function GetMap(){
      map = new VEMap('myMap');
      var latLon = new VELatLong(35.6,139.7); 
      map.LoadMap(latLon, 12 ,'r' ,false);
      //邪魔な縮尺変更コントロールを消します
      map.HideDashboard();

        //タイル・レイヤーのプロパティを設定
            TILE.NumServers = 1;
            TILE.MinZoomLevel = 10;
            TILE.MaxZoomLevel = 18;
            TILE.Opacity = 1;
            TILE.ZIndex = 100;

        //これを実行するとレイヤー表示
            map.AddTileLayer(TILE, true);
    }

    //フェードアウトの処理
    //setIntervalで1/10秒ごとにFade関数を呼び出し
    function FadeLayer(){
        setInterval("Fade()",100);
    }

    //フェードアウト処理
    function Fade(){
      //呼び出し1回ごとに0.05ずつ透過度を増加
      if(i>0.05){
        TILE.Opacity = i;
        map.ShowTileLayer("TL1");
        i = i - 0.05;
      }else{
        //透明度が0.05以下になったらレイヤーを隠す
        map.HideTileLayer("TL1");
      }
    }

</script>
</head>
<body onload="GetMap();">
<br>
<div id='myMap' style=
  "position:relative; width:800px; height:400px;margin-left:10px;">
</div>
<br />
<a href="#" onclick="FadeLayer();">レイヤーをフェードアウト</a>
</body></html>
リスト1●タイル・レイヤーを使ったサンプル。下部のリンクをクリックすると,レイヤーが徐々に薄くなって消えていく

 実行後に「レイヤーをフェードアウト」というリンクをクリックすると,レイヤーが徐々に薄くなって消えます(図3)。

図3●リスト1を実行したところ。「レイヤーをフェードアウト」リンクをクリックするとタイル・レイヤーが消える
図3●リスト1を実行したところ。「レイヤーをフェードアウト」リンクをクリックするとタイル・レイヤーが消える
[画像のクリックで拡大表示]

 タイル・レイヤーは,次のコンストラクタで生成します。

var オブジェクト名 = new VETileSourceSpecification(レイヤーID,画像URLまたはパス);

 レイヤーIDは,任意の名前を付けられます。このIDは,レイヤーのプロパティを更新したり,レイヤーの表示/非表示を切り替えるときに使用します。

 二つ目の引数の画像名は,今回のように同一ディレクトリの画像を使うのであればファイル名だけでかまいません。URL指定が可能なので,インターネット上に置かれている画像ファイルを読み込んで表示するといったこともできます。Virtual Earthは,基本的にはインターネット上に置かれたHTMLに貼り付けて使用されることを想定しているので,画像はURL指定というのが基本スタイルになっていて,リファレンスにも「画像URLを指定」と書かれています。

 タイル・レイヤーはコンストラクタで生成されますが,その後,いくつかのプロパティを設定する必要があります。リスト1では,GetMap()の中でプロパティの追加処理をやっています。「オブジェクト名.プロパティ=値;」の書式です。表1に主なプロパティをまとめました。

表1●タイル・レイヤーの主なプロパティ
プロパティ 概要
NumServers 特に意識する必要はない。1のまま使う
MinZoomLevel 地図の表示倍率がこの倍率以上のときにレイヤーを表示
MaxZoomLevel 地図の表示倍率がこの倍率以下のときにレイヤーを表示
Opacity 透過度。1は100%不透過で,0は完全透過(つまり見えない)
ZIndex 表示順序。数字が大きいほど手前に表示

 コンストラクタでオブジェクトを生成し,プロパティを設定し終わったら,レイヤーを表示させる関数を実行します。これがAddTileLayer()メソッドです。

地図オブジェクト.AddTileLayer(オブジェクト名, 表示属性);

 オブジェクト名は,コンストラクタでvar XXXXXXXと宣言したXXXXXXXの部分です。表示属性は,trueにするとレイヤーが表示されます。falseにすると,レイヤーは生成されるが非表示になります。レイヤーを生成して表示するという流れはここまでで完了です。

表示プロパティの変更後は再描画が必要

 前述の通り,このサンプルにはあえてフェードアウトというあまり意味のない機能を入れました。これには理由があります。実は,レイヤーを操作する際,プロパティを変更しただけでは結果は画面に反映されません。レイヤーの再描画が必要です。フェードアウトを加えたのは,このようなVirtual Earthのレイヤーの仕様を知っていただくのが目的です。

 フェードアウトには,JavaScriptのsetInterval()関数を使っています。setInterval()は,一定時間経過ごとに処理を繰り返すという関数です。これを使って,レイヤーの透明度を少しずつ減らしているわけです。

 レイヤーの透過度を変更するには,TILE.Opacityプロパティを,初期値の1から完全に透過する0まで徐々に減らしていけばいいんですが,プロパティを変更しただけでは画面上は何も変わりません。

 そこでレイヤーに強制的に再描画しろという命令を与えなくてはなりません。それがShowTileLayer()です。書式は次のようになります。

地図オブジェクト.ShowTileLayer("レイヤーID");

 ShowTileLayer()の本来の機能は,非表示になっているレイヤーを再度表示させるものです。サンプルでは最後にレイヤーを消すときにHideTileLayer()というメソッドを使っています。本来,ShowTileLayer()は,HideTileLayer()で隠したもの,またはAddTileLayer()で表示属性をfalseで生成したレイヤーを再度出すときに使うものです。

 しかしながら,リファレンスのどこを見ても,ReloadLayerのようなメソッドはなく,プロパティを変更した後にどうやって強制再描画をさせるかが説明されていません。これで正しいのかどうかはちょっと目をつぶって,試してみた結果としてうまくいったのがShowTileLayer()だったのです。とりあえず,レイヤーにかかわる動的な表示プロパティの変更時には“ShowTileLayer()で再描画”と覚えておいてください。