最近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での表示例
(※2017/08/18 OpenLayersのバージョンをv4.2.0→v4.3.1に置き換え)
OpenLayersではバイナリベクトルタイルを読み込むol.format.MVT()
が存在しているのですが、なぜか上手く動作してくれません。もしかしたらMapboxが配信しているタイルに特化しているかもしれません(あるいはラスタタイルとの併用を前提としていないか)。
※2017/08/17追記
2017/08/13にリリースされたOpenLayers v4.3.0ではMVTソースの動作はめちゃくちゃ良くなってます。(最新版はv4.3.1)
ちゃんと調べてないのでアレなんですが、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
- 地球地図バイナリベクトルタイルの整備 -国土地理院