使ってみよう! Bing API/SDK

第16回使ってみよう! Bing Maps AJAX Control─⁠─地図をWebページに貼り付け(4)

はじめに

Bing Maps AJAX Control 4回目の今回はタイルについてです。前回までに地図上に表示できるものとして、プッシュピン、ポリライン、ポリゴンを紹介しました。もうひとつ地図に上に追加できるのが、タイルです。

Bing Mapsの地図は画像をタイル状に並べて構成されています。これを単にタイルと呼んでいます。Bing Maps AJAX Controlを利用するとオリジナルのタイルを重ねて表示でき、いろいろなアプリケーションの作成ができます。

図1は、独自のタイルを使用した例です。昭和49年度の航空写真を重ねて表示しています。

図1 昔の航空写真の表示
図1 昔の航空写真の表示

国土画像情報(カラー空中写真⁠⁠ 国土交通省

タイルの表示

さっそくタイルを表示するコードを書いてみましょう。オリジナルのタイルを利用するには、Bing Mapsと同様に構成したタイル画像を用意する必要があります。ここではサンプルに用意されているタイル画像を表示します図2⁠。

図2 サンプルのタイル
図2 サンプルのタイル

HTMLを含めたすべてのコードは次のようになります。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Sample</title>
    <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&amp;mkt=ja-jp"></script>
    <script type="text/javascript">
 
        var map = null;
        function GetMap() {
            var options = {
                credentials: "BingMapsKey",
                center: new Microsoft.Maps.Location(48.03, -122.4),
                mapTypeId: Microsoft.Maps.MapTypeId.aerial,
                zoom: 12
            };
            map = new Microsoft.Maps.Map(document.getElementById("map"), options);
 
            // TileSource
            var sourceOptions = {
                uriConstructor: 'http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png'
            };
            var tileSource = new Microsoft.Maps.TileSource(sourceOptions);
 
            // TileLayer
            var layerOptions = {
                mercator: tileSource,
                opacity: 0.9
            };
            var tilelayer = new Microsoft.Maps.TileLayer(layerOptions);
 
            // タイルの追加
            map.entities.push(tilelayer);
        }
 
    </script>
</head>
<body onload="GetMap();">
    <div id='map' style="position: relative; width: 640px; height: 640px"></div>
</body>
</html>

コード中のBingMapsKey部分は、Bing Maps Keyに置き換えてください。

タイルの表示は、Pushpinオブジェクトなどと同じく、Mapsオブジェクトのentitiesコレクションに、TileLayerオブジェクトを追加します。TileLayerオブジェクトの生成には、TileSourceオブジェクトも必要です。それぞれのオブジェクトの生成時に指定するオプションは次の通りです。

TileLayerオプション
名前 説明
opacity 不透明度
0(透明)〜1(不透明)
zIndex ほかの地図上のオブジェクトとの表示順序(数値)
値の大きい方を上に表示
mercator TileSourceオブジェクト
TileSourceオプション
名前 説明
height タイル画像の縦幅
64, 128, 256(規定), 512
uriConstructor タイル画像のURLの書式
URL内の{subdomain}, {quadkey}部分が置換されます(後述⁠⁠。
width タイル画像の横幅
64, 128, 256(規定), 512

タイルの構成

タイルは、複数の画像から成っています。Bing Mapsでは256×256ピクセルの画像の集合です。各タイル画像にはQuadKeysと呼ばれる番号が振られていて、QuadKeysは、タイルの地図上の位置とズームレベルによって決まります図3⁠。

図3 タイル構成とQuadKeys
図3 タイル構成とQuadKeys

QuadKeysの求め方については第10回で紹介していますので、そちらを参照してください。経緯度からQuadKeysに変換する方法はこの後に紹介します。

URLの書式

Bing Maps AJAX Controlの場合、表示するタイルはTileSourceオプションのuriConstructorに指定したURLで決まります。先ほどのコードでは次の値を指定しています。

http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png

{quadkey}の部分が、表示されているタイルのQuadKeysに置き換わって、タイルのあるサーバーへアクセスが発生します。もし{quadkey}部分がなければ、すべてのタイルに同じ画像が表示されることになります。また、アクセスして対応する画像がなければ単に表示されないということになります。

Bing Maps AJAX Controlはタイルの指定に関して簡易な仕組みとなっており、今のところタイルのある地域やズームレベルの範囲の指定はできません。また、タイル画像のURLの指定は、QuadKeysを使用したURLの書式を利用する方法しかありません[1]⁠。

uriConstructorには、{subdomain}という置換されるキーワードも使用できます。これは負荷分散用に0から始まる値が置換されます。多くの場合0〜3のいずれかになるようです。大規模なアプリケーションでない限り、使用することは少ないかと思います。いくつのサブドメイン数があるかは、Imagery APIによるメタデータの取得によってわかります。メタデータの取得についても第10回で紹介しています。

経緯度からQuadKeysへの変換

参考までに経緯度とズームレベルからQuadKeysへ変換するコードを載せておきます。LocationオブジェクトとズームレベルをgetQuadkey関数に渡すとQuadKeyが返ります。

function getQuadKey(location, zoom) {

    // Location オブジェクト, ズームレベルからピクセル座標に変換
    var x = (location.longitude + 180) / 360;
    var sinLatitude = Math.sin(location.latitude * Math.PI / 180);
    var y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);

    var mapSize = 256 << zoom;
    var pixelX = Math.round(clip(x * mapSize + 0.5, 0, mapSize - 1));
    var pixelY = Math.round(clip(y * mapSize + 0.5, 0, mapSize - 1));

    // ピクセル座標からタイル番号に変換
    var tileX = pixelX / 256;
    var tileY = pixelY / 256;

    // QuadKey に変換
    var quadKey = "";
    for (var i = zoom; i > 0; i--) {
        var digit = '0';
        var mask = 1 << (i - 1);
        if ((tileX & mask) != 0) {
            digit++;
        }
        if ((tileY & mask) != 0) {
            digit++;
            digit++;
        }
        quadKey += digit;
    }
    return quadKey;
}

上記のコードを動かすには、最初に示したHTMLとJavaScriptのコードに追加したうえで、<body>要素内にまず次の<input>要素を追加します。

<input type="text" id="quadkey" />

そして、GetMap関数内に次のようにコードを記述するとクリックした地点のQuadKeyを表示します。

Microsoft.Maps.Events.addHandler(map, "click", function (e) {
    var location = map.tryPixelToLocation(new Microsoft.Maps.Point(e.getX(), e.getY()));
    if (location != null) {
        document.getElementById("quadkey").value = getQuadKey(location, map.getZoom());
    }
});

タイル画像の作成

最初に示した航空写真を重ね合わせる例では、1枚の画像が地図上に重なっているようにも見えますが、実際には多くの画像を用意して実現しています図4⁠。ファイル名にQuadKeysを使用しています。

図4 タイル画像
図4 タイル画像

これらのQuadKeysに対応した画像は、MapCruncher図5というツールを使用すると簡単に作成できます。

図5 MapCruncher
図5 MapCruncher

MapCruncherを使用すると、タイルとなる元の画像と実際の地図との対応点を指定するだけで、タイル画像を生成できます。MapCruncherについては、連載使ってみよう! Windows Live SDK/API第6回で使い方を紹介しています。当時からツールの内容は変更されていませんので、詳しく知りたい方はそちらの記事を参照してください。

MapCruncherでは画像だけではなくMap Controlを使用したWebページも含めて出力しますが、最新のBing Maps AJAX Controlとは互換性がないため、タイル画像のみ利用しています。

タイルの追加・削除

オリジナルのタイルを使用する場合、通常は局所的に使用することが多いと思います。TileLayerオブジェクトを追加すると、タイル画像が用意されていない場合も、表示はされていないだけで多くのサーバーへのアクセスが発生することになります。Mapオブジェクトのentitiesコレクションへのオブジェクトの追加・削除は自由にできるため、必要なズームレベルや範囲で表示されているときのみ、タイルを追加し表示できます。

次のコードはズームレベル12の場合のみTileLayerオブジェクトを追加するようサンプルコードを変更した場合です。

Microsoft.Maps.Events.addHandler(map, "viewchangeend", function () {
    var zoom = map.getZoom();

    // 指定した TileLayer オブジェクトが Map オブジェクトの entities コレクションに含まれているか
    var contains = map.entities.indexOf(tilelayer) >= 0;

    // TileLayer オブジェクトの追加・削除
    if (zoom == 12) {
        if (!contains) {
            map.entities.push(tilelayer);
        }
    } else {
        if (contains) {
            map.entities.remove(tilelayer);
        }
    }
});

// 下記の記述をコメントアウトする
//// タイルの追加
//map.entities.push(tilelayer);

コードでは、ズームレベルが変更されたというイベントは用意されていないため、地図の表示が変更された(変更が終了した)時点で発生するviewchangeendイベントを使用しています。

おわりに

Bing Maps AJAX Controlでは、あくまでタイルを重ねて表示できるだけで、差し替えるものではありません。タイルを追加した場合も、ズームアニメーションしている間は元のBing Mapsの地図が見えています。完全に差し替えたように見せたい場合は、Bing Maps Silverlight Controlの利用や、タイル状の画像の表示の仕組みだけならSilverlightのDeep ZoomSeadragon Ajaxを検討してみるとよいかもしれません。

今回はここまでです。いかがでしたでしょうか。次回もBing Maps AJAX Controlについて紹介します。

おすすめ記事

記事・ニュース一覧