はじめに
Bing Maps AJAX Control 4回目の今回はタイル についてです。前回 までに地図上に表示できるものとして、プッシュピン、ポリライン、ポリゴンを紹介しました。もうひとつ地図に上に追加できるのが、タイルです。
Bing Mapsの地図は画像をタイル状に並べて構成されています。これを単にタイルと呼んでいます。Bing Maps AJAX Controlを利用するとオリジナルのタイルを重ねて表示でき、いろいろなアプリケーションの作成ができます。
図1 は、独自のタイルを使用した例です。昭和49年度の航空写真を重ねて表示しています。
図1 昔の航空写真の表示
国土画像情報(カラー空中写真) 国土交通省
タイルの表示
さっそくタイルを表示するコードを書いてみましょう。オリジナルのタイルを利用するには、Bing Mapsと同様に構成したタイル画像を用意する必要があります。ここではサンプルに用意されているタイル画像を表示します(図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&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 );
var sourceOptions = {
uriConstructor : 'http://www.microsoft.com/maps/isdk/ajax/layers/lidar/{quadkey}.png'
};
var tileSource = new Microsoft . Maps . TileSource ( sourceOptions );
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
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 ) {
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 ;
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 タイル画像
これらのQuadKeysに対応した画像は、MapCruncher (図5 )というツールを使用すると簡単に作成できます。
図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 ();
var contains = map . entities . indexOf ( tilelayer ) >= 0 ;
if ( zoom == 12 ) {
if (! contains ) {
map . entities . push ( tilelayer );
}
} else {
if ( contains ) {
map . entities . remove ( tilelayer );
}
}
});
コードでは、ズームレベルが変更されたというイベントは用意されていないため、地図の表示が変更された(変更が終了した)時点で発生するviewchangeendイベントを使用しています。
おわりに
Bing Maps AJAX Controlでは、あくまでタイルを重ねて表示できるだけで、差し替えるものではありません。タイルを追加した場合も、ズームアニメーションしている間は元のBing Mapsの地図が見えています。完全に差し替えたように見せたい場合は、Bing Maps Silverlight Controlの利用や、タイル状の画像の表示の仕組みだけならSilverlightのDeep Zoom 、Seadragon Ajax を検討してみるとよいかもしれません。
今回はここまでです。いかがでしたでしょうか。次回もBing Maps AJAX Controlについて紹介します。