2017年08月12日
バイナリベクトルタイルを作ってみた
最近WEB地図界隈で話題になっているバイナリベクトルタイルを作ってみました。
この記事は、 バイナリベクトルタイルの作り方(GUNMA GIS GEEK) という記事にある作り方をそのままそっくりやってみたという内容の記事です。クックパッドで言うところの「つくれぽ」ですね。 なので、バイナリベクトルタイルや途中で出てくるMBTilesなどの仕様や仕組みについてはあまり理解していません。ご了承ください。
1.データをダウンロード
データは何でも良いのですが、とりあえず 国土数値情報 を使ってみます。 今回は点データである「学校」(平成25年度)のデータを利用しました。zipファイルをダウンロードし、解凍するとシェープファイルが手に入ります。 フォルダごと作業ディレクトリのどこかに放り込んでおきましょう。
2.シェープファイルをGeoJSONに変換
一般的にはGDALの ogr2ogr を使う場面だと思いますが、より楽な shp2json を使いました。npmでサクッとインストールできるので、D3.js、特にTopoJSON関連を使うなら導入して損はないと思います。
$ shp2json --encoding Shift-JIS source.shp > output.geojson
国土数値情報はShift-JISで提供されているので、--encoding Shift-JIS
を忘れずに。
次の手順で使う tippecanoe では ndjson 形式を扱うことができるので、shp2json
で-n
オプションをつけて、ndjsonで出力してもいいです。tippecanoeのドキュメントによると、ndjsonだとちょっとだけ早くなるとのこと。
3.GeoJSONからMBTilesを作成
MBTiles はSQLiteベースで作られたタイルセットを格納するためのファイル形式です。GeoJSONからMBTilesを作るために tippecanoe を手に入れます。macなのでhomebrewを使いました。
tippecanoeのオプションですが、基本的には「作り方」の例に従っています。-r
オプションで設定するレートも、数値ではなく-rg
オプションにしました。実用的なものを作る場合は適切なレートを設定した方がいいと思います。要検証。
入力が先述の ndjson 形式の場合は-P
オプションをつけます。
下記のように、-L
オプションを使うことで複数のデータをレイヤーとして一つのmbtilesファイルにまとめることもできます。
$ tippecanoe -L hoge:./data/hoge.json -L fuga:./data/fuga.json -o output.mbtiles
tippecanoe
の公式ドキュメントはもう少しちゃんと読んでおきたいです。
4.mbutilを使ってpbfファイルへ展開
mbutil は MBTiles とタイルを構成するディレクトリの相互変換を行うツールです。「作り方」ではeasy_installでしたがpipを使ってインストールしました。 拡張子は「作り方」でも言及されていたように、.pbfではなく**.mvt**としました。
$ find . -type f -exec mv -v '{}' '{}'.mvt \;
これで、mbutilで指定したディレクトリにmvtという拡張子がついたファイルが入ったフォルダが出来ているはずです。
5.表示してみる
「作り方」の記事に則って Leaflet を使用して表示します。 ここで注意点が一つ。バイナリベクトルタイルの表示に使用する Leaflet.MapboxVectorTileプラグイン はLeaflet v1.0.0以降のバージョンでは動きません。ガーン。 また、上記のデモでも実証されるように、地物の数が多すぎるタイルは読み込んでくれませんでした(タイルの欠損があるわけではないはず)。この辺の閾値なども調べていきたいです。
const schools = new L.TileLayer.MVTSource({
url: "./tile/schools/" + "{z}/{x}/{y}.mvt",
maxZoom: 18,
maxNativeZoom: 15,
attribution: '<a href="http://nlftp.mlit.go.jp/ksj/" target="_blank">国土数値情報(学校)</a>',
mutexToggle: true,
getIDForLayerFeature: function(feature){
return feature.properties.P29_001 + feature.properties.P29_005;
},
onClick: hoveronFeature, //別途設定した関数
style: function(feature){
let color = feature.properties.P29_004 === "16001" ? "yellow" :
feature.properties.P29_004 === "16002" ? "gold" :
feature.properties.P29_004 === "16003" ? "#aca777" :
feature.properties.P29_004 === "16004" ? "#ff963e" :
feature.properties.P29_004 === "16005" ? "#ac815c" :
feature.properties.P29_004 === "16006" ? "#78109d" :
feature.properties.P29_004 === "16007" ? "#d90096" : "#3f9386";
return {color: color, radius: 6, selected: {color: "red", radius: 10}};
}
});
LeafletのMVTレイヤ設定の例です。 プラグインのドキュメント によると、必須となるオプションはurl
、getIDForLayerFeature
、filter
のようです(ただしfilterオプションはなくても動く)。重要なのがgetIDForLayerFeature
で、これを設定しないと地物のスタイリングやクリックイベント時に正しい挙動をしてくれません。地物のプロパティに固有のidがある場合はそれを設定すればいいのですが、国土数値情報の学校データには存在しないので、行政区域コード(P29_001)に名称(P29_005)を繋げたものを設定しました。
その他のライブラリ
OpenLayers ではバイナリベクトルタイルを読み込むol.source.MVTSource()
が存在しているのですが、なぜか上手く動作してくれません。もしかしたら Mapboxが配信しているタイル に特化しているかもしれません。(あるいはラスタタイルとの併用を前提としていないか)
※追記 2017/08/13にリリースされたOpenLayers v4.3.0ではMVTソースの動作はめちゃくちゃ良くなってます。
ちゃんと調べてないのでアレなんですが、WEBGLベースの Mapbox GL JS が一番良いみたいですね。後々試してみます。
6.GitHub Pagesでホストしてみる
作成したバイナリベクトルタイルをGitHub Pagesを使ってホストしてみます。 2016年からの新機能でmasterブランチのdocsフォルダの中身をホストできるようなので(参考: 2016年新機能! GitHubのmasterブランチをWebページとして公開する手順 )、それに則ってやってみました。
- レポジトリ: https://github.com/cieloazul310/mvt-tiles
- ホストしたタイル:
https://cieloazul310.github.io/mvt-tiles/tile/schools/{z}/{x}/{y}.mvt
- ホストしたページ: https://cieloazul310.github.io/mvt-tiles
課題
- tippecanoeの機能をもっと試していきたい。
- Leafletでのクリックイベントや複雑なスタイリングなどを試していきたい。
- LeafletのMapboxVectorTileプラグインは最終更新が2015年9月で、Leafletの最新バージョンに対応する可能性はなさそう。それでもLeafletを使うべきか悩みどころ。
感想
難易度が高い印象があったバイナリベクトルタイルが意外なほどあっさり作れてしまって驚きました。 レシピを公開してくれた GUNMA GIS GEEK の清水正行氏には感謝申し上げたいです。
参考リンク
- VectorTilesSpecification mapbox
- MbTiles mapbox
- バイナリベクトルタイルの作り方 GUNMA GIS GEEK
- anyone can host vector tiles hfu’s Qiita
- Vector Tiles to start in Japan hfu’s Qiita
- 地球地図バイナリベクトルタイルの整備 国土地理院
地図
OpenLayersなどの地図に関するJavaScriptライブラリや、ベクトルタイルといった地図に関する技術情報です。