eegeo.jsは、人気の地図ライブラリーLeafletをベースにしたオープンソースの3DマップAPIです。
シンプルな2Dマップを埋め込んだり、作成したりできる地図ライブラリーはたくさんあります。特に有名なのはGoogle Maps、Bing Maps、HERE、Mapbox、OpenStreetMapです。また、地図抽象化ライブラリーとして人気の高いOpenLayersやLeafletなどでは、アプリケーションの仕組みはそのままで、地図の「ベースレイヤー」を変更できます。
Google Earth APIの使用がNPAPIのセキュリティを理由に非推奨になったことで、3DマップAPIの選択肢は限られてしまいました。それでも代替手段はいくつかあり、Cesiumなどのライブラリーが人気です。eegeo.jsもその1つで、ダイナミックで極めてシームレスな3Dマップを提供し、その範囲は空間から屋内マップの机まで多岐にわたります。eegeo.jsはWebGLを使ってブラウザーで動作します。
はじめに
この記事では、ロンドンの華麗な3Dマップの埋め込みや、ロンドン市交通局(TfL: Transport for London)が公開するAPIを使った基本的な機能の追加を紹介し、とても簡単にできることを説明します。
一言:3Dマップは2Dマップと同じくらい簡単です。
注記:私はeeGeoのソフトウェア開発担当シニア・バイスプレジデントで、eegeo.jsの開発を管理しています。
Leafletの使い方の記事はたくさんあります。eegeo.jsはLeafletをよく知っている開発者がすぐに使用できるように、意図的にLeafletをベースにして開発されました。Leafletのサンプルとドキュメントを参照することを強くおすすめします。
本記事で扱う内容はHTML、CSS、JavaScriptの基礎と、簡単なマッピングの概念を含みます。
必要なもの
記事で使う主なコンポーネントは以下のとおりです。
- Leaflet(ドキュメント、サンプル)
- eegeo.js(ドキュメント、サンプル)
- ロンドン市交通局のAPI
- PythonまたはそのほかのHTML、CSS、JavaScriptをアップロードする場所
ロンドンの2Dマップを表示する
最初にLeafletとOpen Street Mapを使ってロンドンの2Dマップを作成します。Leafletは本当に簡単です。必要なものはページをセットアップするための短いHTML、地図を格納するための<div>、初期位置を設定するための数行のJavaScriptだけです。
HTMLの作成
以下をマークアップしてHTMLファイルを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Building Gorgeous 3D maps with eegeo.js and Leaflet</title>
</head>
<body>
<div id="map" style="width: 600px; height: 400px;"></div>
</body>
</html>
Leafletのインクルード
LeafletのJavaScriptライブラリー、CSSを追加するだけで簡単にLeafletをインクルードできます。これらを<head>タグで囲みます。
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.3/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.0.3/dist/leaflet.js"></script>
Leaflet JavaScriptの追加
以下のJavaScriptによりLeafletを初期化しOpenStreetMapをタイルレイヤーとして使います。コードは外部のJavaScriptファイルとして追加できるほか、単に<div id="map"/>の下に<script></script>ブロックとして追加もできます。
var map = L.map('map', {
center: [51.517327, -0.120005],
zoom: 15
});
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
このコードは、WGS84(世界測地系)の10進数表記による緯度、経度が51.517327, -0.120005の位置にある地下鉄ホルボーン駅を中心として地図を初期化します。こうした座標はmaps.eegeo.comやGoogle Mapsなどのデジタルマップで右クリックし「この場所について(What’s here)」を選択すると取得できます。あとで出てきますが、TfL APIを含むほとんどの地理空間情報APIは、標準的な測地系であるWGS84の10進数表記による緯度、経度で位置を返します。
2Dマップの起動
HTMLをアップロードするか、ローカルで確認します。ファイルシステムから直接読み込むのではなく、ローカルなWebサーバーを使って読み込むことをおすすめします。HTMLをindex.htmlとして保存し、同じフォルダーでpython -m SimpleHTTPServer 8000を実行すると、ブラウザーからhttp://localhost:8000/にアクセスできるようになります。
ホルボーン駅を中心としたロンドンの地図が表示されます。
ロンドンの3Dマップを表示する
eegeo.jsはLeafletをベースに作られているため、わずかな変更でロンドンの2Dマップを鮮やかな3Dマップに変えられます。
上で追加したJavaScriptのvar map = L.map ...の部分を以下に変更します。eeGeoのAPIキー(無料)が必要です。L.tileLayerを呼び出すJavaScriptはもう必要ないので削除します。
JavaScriptは次のようになります。
var map = L.eeGeo.map('map', '<your_api_key>', {
center: [51.517327, -0.120005],
zoom: 15
});
<head>に追加しておいた<script>インクルードを変更し、Leafletの代わりにeegeo.jsをインクルードします。Leafletはeegeo.jsファイル内部にすでに含まれているため、両方をインクルードする必要はありません。
<script src="https://cdn-webgl.eegeo.com/eegeojs/api/v0.1.780/eegeo.js"></script>
以上です! 表示しているのはまったく同じホルボーン駅ですが、数行の変更だけでゴージャスな3Dに変わりました。
縮尺、傾き、方位の変更
eegeo.jsは完全な3Dでできているので、地図を回転させたり傾けたりできます。LeafletのsetView関数がサポートされており、さらにオプションとして地図の3D反応をサポートするための傾きと方位の引数が用意されています。
以下のJavaScriptを追加すると10秒間のシームレスな3Dアニメーションによってホルボーン駅から同じロンドン市内の30セント・メリー・アクスへ地図が移動します。
setTimeout(function() {
map.setView([51.514613, -0.081019], 17, {headingDegrees: 204.374, tiltDegrees:15.0});
}, 10000);
スクリーンショットでは動作が分かりませんが、CodePenでアニメーションを確認できます。
setView()の追加引数は以下のとおりです。
フィールド | タイプ | 説明 |
---|---|---|
headingDegrees | 10進数 | 北を始点とする時計回りの、10進数による角度。北は0.0 |
tiltDegrees | 10進数 | 傾きを角度で表し、45.0が真上で0.0が初期値 |
ロンドンの3Dマップを操作する
地図に便利な機能を追加します。Leafletの基本的な要素のほとんどがサポートされており、マーカー、ポリライン、ポリゴンなどが使えます。
地図にホルボーン駅のマーカーを追加するにはL.marker()を呼び出します。
L.marker([51.517327, -0.120005]).addTo(map);
ラッセル・スクウェアにポリゴンを追加するにはL.polygon()を呼び出します。ラッセル・スクウェアの北東の角にあるバーナード通りとワーバン街の交差点を始点として、時計回りで表される4つの頂点でポリゴンを定義します。
L.polygon([[51.522771, -0.125772],
[51.521520, -0.124192],
[51.520631, -0.126358],
[51.521963, -0.127895]]).addTo(map);
グレート・ジェームス通りを始点として、ブルームズベリーを通り、ミュージアム通りを終点とする道を示すポリラインを追加するには、次のようにします。
L.polyline([[51.521788, -0.117101],
[51.520732, -0.116524],
[51.520430, -0.117641],
[51.519873, -0.119602],
[51.519034, -0.120993],
[51.518784, -0.121537],
[51.517265, -0.125088],
[51.516257, -0.124466]]).addTo(map);
更新すると、Leafletの3つの基本要素が地図に表示されます。
気づいているかもしれませんが、L.marker()、L.polyline()、L.polygon()はすべてLeafletのAPIコールです。地図を元のOpenStreetMapに戻しても、同じAPIコールが2DのOpenStreetMapベースレイヤーに引き継がれます。
ロンドン市交通局のAPI
次に、現実世界のAPIからデータを取り出してロンドンの3Dマップに追加します。
ロンドン市交通局(TfL)のAPIは大規模で複雑です。APIはバス、地下鉄、オーバーグラウンド、cycle hire(コミュニティサイクル)を含むロンドン市内のすべての交通機関を網羅し、リアルタイムな運行状況と到着時間のデータを提供します。
TfL APIの範囲はあまりに広く、この記事だけでは扱いきれません。例では、ロンドン地下鉄に関連する少数のAPIエンドポイント、具体的には以下に関係するものに絞ります。
- 利用できる地下鉄の路線はどれだけあるか?
- 地下鉄の各路線はどの駅に停車するのか?
- 各駅の「到着案内板」はどうなっているか?
レート制限は厳しくなりますが、APIキーがなくてもTfL APIを使用できます。TfLを実際の製品開発で使う場合は、APIキーのサインアップが必要です。
利用できる地下鉄の路線はどれだけあるか?
利用できる地下鉄の路線について、TfL APIは路線情報のエンドポイントを提供しています。
必要なのは交通機関の「tube」モードだけなので、以下のコールを作成します。
curl -v https://api.tfl.gov.uk/line/mode/tube
JSON形式で路線情報の配列が返されます。必要となるのは各エントリのidプロパティだけです。
[{
"id": "bakerloo",
"name": "Bakerloo",
"modeName": "tube",
"disruptions": [],
"lineStatuses": [],
"routeSections": [],
...
},...]
TfL APIとのやりとりを簡略化するためにjQueryを使いますが、jQueryの使用はあくまでオプションです。以下のJavaScriptによりLineエンドポイントを呼び出し、Line IDを取得します。
$.getJSON( "https://api.tfl.gov.uk/line/mode/tube", function(data) {
var lines = [];
$.each(data, function(k, line) {
lines.push(line.id);
});
});
Line IDは、あとで各路線の駅を返すエンドポイントにクエリを発行するために使います。
ロンドン地下鉄をグラフとしてモデリングする
ロンドン地下鉄はグラフと見なせます。グラフは頂点と辺からなり、ロンドン地下鉄においては駅を頂点、路線を辺と考えます。
セントラル線(赤色)をグラフとしてモデリングすると、ノース・アクトン、ウェスト・アクトン、ハンガー・レーンが頂点になります。ノース・アクトンから西は枝分かれしているため、ノース・アクトンとウェスト・アクトンの間、そしてノース・アクトンとハンガー・レーンの間がセントラル線の辺になります。
セントラル線の東にはノッティング・ヒル・ゲートがあります。ノッティング・ヒル・ゲート駅は1つだけですが、駅には3つの路線(セントラル線:赤、サークル線:黄、ディストリクト線:緑)のためのプラットホームがあります。ノッティング・ヒル・ゲートに追加するLeafletマーカーは3つではなく、1つです。ノッティング・ヒル・ゲートを頂点としてモデリングすると、セントラル線の辺(ホランド・パークへ向かう辺、クィーンズ・ウェイへ向かう辺)、サークル線とディストリクト線の辺(ベイズウォーターへ向かう辺、ハイ・ストリート・ケンジントンへ向かう辺)ができます。
TfL APIは地下鉄を有向グラフとしてモデリングしているため、この点は重要です。
地下鉄の各路線にはどのような駅があるのか?
地下鉄のすべての路線のLine IDを取得しました。駅と路線をそれぞれグラフの頂点、辺として地下鉄を大まかにモデリングしていきます。Line IDを使うことで、各路線の停車駅をTfL APIから取得できます。TfL APIではこれらの駅をStopPointsと呼んでいます。呼び出すエンドポイントは、StopPointsのシーケンスを含む路線や経路です。
セントラル線の下りを取得するTfL APIコールを作成します。
curl -v https://api.tfl.gov.uk/line/central/route/sequence/outbound
8000行を超える整形された、とても大きなJSONペイロードが返されます。幸い、必要なのはstopPointSequencesキーだけです。
"stopPointSequences": [
{
"lineId": "central",
...
"stopPoint": [
...
{
"id": "940GZZLUNHG",
"name": "Notting Hill Gate Underground Station",
...
"lat": 51.509128,
"lon": -0.196104
},
{
"id": "940GZZLUQWY",
"name": "Queensway Underground Station",
...
"lat": 51.510312,
"lon": -0.187152
},
...
],
},
...
]
このプロパティは、路線を連続するセクションでグループ化したJSONオブジェクトのリストです。StopPointSequenceの中には、その路線にあるすべてのStopPointsが順に並んで入っています。
以下のJavaScriptは地下鉄路線の辺を書くために、重複しないユニークな駅とポリラインを作成します。
var stopPoints = {};
$.getJSON( "https://api.tfl.gov.uk/line/central/route/sequence/outbound", function( data ) {
var lineSegments = [];
$.each(data.stopPointSequences, function(k, v) {
var line = [];
$.each(v.stopPoint, function(k, sp) {
line.push([sp.lat, sp.lon]);
if (!(sp.id in stopPoints)) {
stopPoints[sp.id] = {"id":sp.id, "name":sp.name, "lat":sp.lat, "lon":sp.lon};
}
});
lineSegments.push(line);
});
});
地下鉄のそれぞれの路線に対して上のJavaScriptを呼び出します。あとで、すべてのユニークな駅をstopPointディクショナリーにまとめます。また、路線内の各区間を示すポリラインの集合をlineSegments配列に格納します。
Leafletのマーカーとポリラインを追加して地下鉄の駅と路線を視覚化する方法はあとで説明します。
どの電車が駅に到着する予定か?
最後に必要なTfL APIエンドポイントは、最新の到着情報です。上で説明したように、駅はAPI内でユニークなIDを持っていることが分かります。ノッティング・ヒル・ゲートの場合、IDは940GZZLUNHGです。
{
"id": "940GZZLUNHG",
"name": "Notting Hill Gate Underground Station",
...
"lat": 51.509128,
"lon": -0.196104
}
TfL StopPoint APIを呼び出しStopPoint IDを渡します。
curl -v https://api.tfl.gov.uk/stoppoint/940GZZLUNHG/arrivals?mode=tube
到着情報の配列が返されます。
[{
...
"naptanId": "940GZZLUNHG",
"stationName": "Notting Hill Gate Underground Station",
"lineId": "central",
"platformName": "Eastbound - Platform 3",
"direction": "outbound",
...
"destinationName": "Epping Underground Station",
"timeToStation": 290,
"currentLocation": "Between White City and Shepherd's Bush",
"towards": "Epping",
...
},
...]
東回り(Eastbound)のエッピング行きの列車が、3番乗り場(Platform 3)に5分以内(290秒)に到着予定であることを示します。
まとめると
ここまで、以下について説明してきました。
- Leafletを使ったシンプルなOpenStreetMapの2Dマップを作成
- 作成したシンプルな2Dマップをeegeo.jpとLeafletを使って華麗な3Dマップに変更
- Leafletマーカー、ポリライン、ポリゴンによる簡単な目印を地図に追加
- ロンドン市交通局のAPIの基本的な操作を実施
こうしたシンプルな発想を1つにまとめて、地下鉄の路線と駅を表示しすべての駅のリアルタイムな到着予定時刻を確認できる、インタラクティブなロンドンの3Dマップを生成します!
地下鉄の各駅にマーカーを追加
前に説明したhttps://api.tfl.gov.uk/line/central/route/sequence/outboundをリクエストする$.getJSON()コールで、各駅に対しL.marker()を呼び出します。
$.each(stopPoints, function(k, sp) {
L.marker([sp.lat, sp.lon],
{
title: sp.name,
options: {"id":sp.id, "name":sp.name}
}).addTo(map);
});
マーカーに追加の「オプション(options)」を渡しています。あとでマウスホバーイベントを処理するときに、マウスを重ねた駅のIDと駅名が分かるようになります。
地下鉄の各路線にポリラインを追加
同様に、https://api.tfl.gov.uk/line/central/route/sequence/outboundをリクエストするAjaxコールで、それぞれの路線セグメント(line segments)にL.polyline()の呼び出しを追加します。
$.each(lineSegments, function(k, ls)
{
L.polyline(ls, {weight:8, color:"#CC3333"}).addTo(map);
});
色はLine IDを調べることで決められます。例では、TfLデザインガイドに従ってサークル線を赤でハードコードしています。
Leafletマーカーにマウスオーバーするイベントの処理
TfL APIからリアルタイムな到着情報を取得し表示します。Leafletマーカーにマウスオーバーしたときにコールバックを受け取れます。また、Leafletポップアップによる駅名の表示もできます。
$.each(stopPoints, function(k, sp) {
var marker = L.marker([sp.lat, sp.lon],
{
title: sp.name,
options: {"id":sp.id, "name":sp.name}
}).addTo(map);
marker.bindPopup(sp.name);
marker.on('mouseover',_hovercard.overstation);
marker.on('mouseout',_hovercard.outstation);
});
下に示したより複雑なCodePenでは、「_hovercard.*」コールバックがTfL APIにリクエストし、駅のリアルタイム到着情報を表示するコールアウトカードを作成しています。
すべてをまとめる
関心の分離とモデリングの改善を加えた、eegeo.js、Leaflet、TfL APIの完成版デモをCodePenで確認できます。
3Dマップは難しくない
記事では、JavaScriptとLeafletを使ってWebサイトに2Dマップを追加する方法と、マーカー、ポリライン、ポリゴンといったシンプルなマップ機能を追加する方法を説明しました。そして、ロンドン市交通局のAPIのような現実世界のAPIデータを簡単に追加できることも示しました。
OpenLayersやLeafletなどの地図抽象化ライブラリーを使ってコーディングするメリットを解説しました。コードに変更をほとんど加えずに地図の見た目を大きく変えられます。また、eegeo.jsを使えば3Dマップを簡単に作れることも紹介しました。
(原文:Building Gorgeous 3D Maps with eegeo.js and Leaflet)
[翻訳:薮田佳佑/編集:Livit]