2018年10月31日
バイナリベクトルタイルを地図ライブラリ以外で扱う
Mapbox GL JS や Leaflet といった地図ライブラリを使わずに JavaScript でバイナリベクトルタイルを使う方法です。
やること
fetch
で pbf (mvt)
形式のファイルを取得し、GeoJSON Feature の配列に変換する。
コード
npm で pbf と @mapbox/vector-tile モジュールをインストールします。
$ npm install --save pbf @mapbox/vector-tile
fetch
して response → ArrayBuffer → Pbf の順に変換し、GeoJSON Feature の配列を取得
import Pbf from 'pbf';
import { VectorTile } from '@mapbox/vector-tile';
const tileCoord = { x: 14582, y: 6414, z: 14 };
const baseUrl = 'https://cieloazul310.github.io/mvt-tiles/tile/population_250m/';
const layerName = '250mesh';
fetch(baseUrl + `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}.mvt`)
.then(res => res.arrayBuffer())
.then(buffer => new Pbf(buffer))
.then(pbf => {
const layer = new VectorTile(pbf).layers[layerName];
const features = [];
if (layer) {
for (let i = 0; i < layer.length; i++) {
const feature = layer.feature(i).toGeoJSON(tileCoord.x, tileCoord.y, tileCoord.z);
features.push(feature);
}
}
return features;
})
.then(features => {
console.log(features);
// => Array(46) [ feature, feature, feature, ..., feature ]
});
バイナリベクトルタイルの拡張子は作成時に mvt にしていたので、この記事でも mvt としています。
しかし、この分野の国内における先駆者である @hfu さんの記事 バイナリベクトルタイルの拡張子が mvt であったり pbf であったりするのはなんでだろう に下記のようなコメントが付いていたので、今後は pbf にします。
その後、Mapzen (Tilezen) のサービスが(いったん)終了して状況が変化したので、hfu も拡張子を pbf に変更しました。
応用
fetchTile
という関数を作成します。
この関数はタイル座標のオブジェクト tile
を入力し、Promise オブジェクト(fetch)を返します。
fetch
が成功したら mvt (pbf) 形式のファイルの変換を行ない、GeoJSON Feature の配列 features を返し、失敗したら空の配列を返します。
import Pbf from 'pbf';
import { VectorTile } from '@mapbox/vector-tile';
/**
* @param {object} tile
* @returns {Promise} Promise object
*/
function fetchTile(tile) {
return fetch(baseUrl + `${tile.z}/${tile.x}/${tile.y}.mvt`)
.then(res => res.arrayBuffer())
.then(buffer => new Pbf(buffer))
.then(pbf => {
const layer = new VectorTile(pbf).layers[layerName];
const features = [];
if (layer) {
for (let i = 0; i < layer.length; i++) {
const feature = layer.feature(i).toGeoJSON(tileCoord.x, tileCoord.y, tileCoord.z);
features.push(feature);
}
}
return features;
})
.catch(() => []);
}
d3-tile などで求めたタイル座標の組の配列 tiles
から、array.map
で Promise オブジェクトの配列 tasks
を生成します。
Promise オブジェクトの配列 tasks
を生成することで、 Promise.all(tasks)
で全てのタイルの取得が終わった後に、一括で処理を行なうことができます。
const tiles = [{ x, y, z }, { x, y, z }, /* ..., */ { x, y, z }];
const tasks = tiles.map(tile => fetchTile(tile));
// => Array [ Promise, Promise, ..., Promise ]
Promise.all(tasks)
.then(data => {
console.log(data);
// => Array [ features, [], features, features, [], ...]
// 二次元配列である data を一次元の配列 features に変換
const features = data.reduce(
(accum, curr) => [...accum, ...curr],
[]
);
return features;
// => Array [ feature, feature, ..., feature ]
});
国内のサッカースタジアム周辺の人口を求める という記事では、上記の方法で人口データの入ったバイナリベクトルタイルを取得し、 Turf.js を使って距離円との演算を行いました。
参照
- pbf / GitHub
- @mapbox/vector-tile / GitHub
- Protocol Buffers / Google Developers
- Array Buffer / MDN web docs
幼い二人 / 寺尾紗穂 (2017)
地図
OpenLayersなどの地図に関するJavaScriptライブラリや、ベクトルタイルといった地図に関する技術情報です。