Preview地理院地図Vectorのベクトルタイルデータ国土地理院から地理院地図のベクトルバージョンが試験公開されました。https://github.com/gsi-cyberjapan/gsimaps-vector-experiment地理院地図の基本図と同じ内容がベクトルデータとして取得できることで、好きな情報を好きなスタイルで表現した地図を作ることができます。2019年7月の段階では、関東の一部地域のみですが、地域が拡大されることを期待したいです。画像のタイルデータと同じ方法でタイル単位のベクトルデータがオンラインで提供されるもので、ベクトルデータの形式は、Mapboxのベクトルタイルに従っているようです。Mapboxを利用して表示等を行う場合は、内部のデータ構造について理解する必要は無いと思いますが、ここでは独自にタイルデータを取得して利用する方法について解説します。MapboxのベクトルタイルデータMapboxのベクトルタイルの仕様はこちらにあります。符号化されているとあります。この仕様に従ってデコードする必要があります。Buffersの仕様についてはこちら。https://developers.google.com/protocol-buffers/これは、Googleが策定した、構造化データをバイナリデータとして効率よく扱うためのものです。名前のついた型付のデータのグループ(message)を入れ子にして表現することができます。Buffersでは、スキーマの定義に従ってエンコード/デコードをします。スキーマ定義ファイルが、protoという拡張子になっています。8191;}だいたい見れば自明だと思います。Tileというmessageは、複数のLayerから成っていて、Layerには、version,name,features,keys,valuesといった内容が含まれています。geometry,extentが含まれます。後述しますが、このtypeとgeometryで実際のベクトルの座標データを表すことになります。地理院地図vectorのタイルデータを読む地理院地図vectorのタイルデータをこのMapboxのスキームに従って読み込めばいいことになります。Buffersのデコードまで自前でやるのは車輪の再発明に過ぎるので、javascriptのライブラリを利用します。実装はいくつかあるようですが、これが使いやすそうだったのでこれでやってみます。https://github.com/protobufjs/protobuf.js#using-proto-filesまず、タイルデータをバイナリデータとして取得するために、XMLHttpRequestで読み込む関数を用意しておきます。})}読み込んだデータをprotobuf.jsを使ってデコードします。テストに固定のタイルパスを指定して読み込んでみます。コールバックの中で、lookupTypeでTileのスキーマを取り出しておきます。準備ができたら、タイルデータをload関数で読み込みます。protobufのデコーダは、Uint8Arrayを入力とするので、読み込んだデータをUint8Arrayにして、tile.decodeでデコードします。デコードしたものを、toObjectメソッドでjavascriptのオブジェクトに変換することができます。取得したオブジェクトをconsoleにダンプした結果が以下のようになりました。layer.nameを見ればどの情報のレイヤであるかはすぐわかりますね。必要なLayerから属性値と座標データを取り出せばいいわけですが、これらのデータの持ち方も独特になっています。属性値まずLayerの中の個々の地物であるfeaturesは、属性値を持っていますが、そのkey-value値がそれぞれLayerの中に配列としてまとめられて、各featureはそのインデックスを参照する、という構造になっています。することで、属性のkeyやvalueの共通するものが1つにまとめられ、データサイズの効率が良くなっています。layer.keysが属性値のキーの配列、layer.valuesが値の配列で、feature.tagがkeyとvalueのインデックス2つの整数を単位とする配列になっています。各々の属性値の意味については、地理院vectorの仕様書の「属性等の仕様詳細」を参照してください。描画コマンドfeature.geometoryが実際に描画されるベクトルデータです。moveToやlineToなどのコマンドと繰り返し回数、それに続く座標値が、整数の配列としてシリアライズされています。この辺りの詳細は、Mapboxのデータの仕様を参照してください。独特なのが数値の表現で、符号付整数の符号が最下位ビットに来るようになっています。これによって絶対値の小さな値の上位ビットが0になることで、圧縮効率が上がることを期待してると思われます。この数値データをデコードするのは次のようなコードになります。1))}描画コマンドの座標値は各タイルの左上を原点として、右下は、layer.extentの値で規定されます。地理院タイルでは4096になっているので、1つのタイルあたりのベクトル分解能は縦横4096ということになります。描画サンプル以上を踏まえて、1つのlayerの線分をcanvasに描画するサンプルです。"road"の道路レイヤー専用で汎用にはなっていません。属性rnkWidthに道路の幅が入っているので、これを使って描画する線幅lineWidthを決めています。}}これで描画したものと、地理院地図の画像タイルデータを並べて出してみるとこんな感じになります。この例では、単一の線の幅を変えただけですが、地理院地図では、太い道路は輪郭のラインと中の塗りつぶしラインの2つのラインを描画する、といったことをしています。地理院地図の画像タイルとベクトルデータの情報内容は、ベクトルデータの方がzoom値で1段階詳細になっています。上の図は、zoom14の画像タイル4枚分(512x512px)と、zoom13のベクトルデータを並べています。実際に動くページはこちらで見られます。