tile-join を使って重たい geojson を XYZ tile に変換し GitHub でホストする方法

先日、note に [台湾政府がマスクのリアルタイム在庫状況を公開し、数日で50以上のアプリが爆誕](https://note.com/hal_sk/n/nd5d71fa9ff5d) という記事を書いたのですが、その際にベクトルタイル神であられる[@hfu](https://qiita.com/hfu)さんから下記のようなコメントをいただきました。

![image](https://i.gyazo.com/ce5f7ca4fe0a6be46597c5afc20e039e.png)

台湾政府の凄さについては冒頭の記事を読んでいただければと思うのですが、今回はGeoJSONの処理について書きたいと思います。
まず、ここで言及されている GeoJSON ファイルが[こちら]( https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json)。確かに8M近くあります。

hfuさんが書いたように tippecanoe で mbtiles ベクタータイル化して mapbox にアップロードすることで Mapbox Studio などからもデータソースとして使うことができるのですが、できれば無料でやりたいところです。そこでさらに素晴らしいご神託が。

![image](https://i.gyazo.com/7884952de8608cfac716e3d21e2c32f0.png)

これだ！ということで、さっそく実行に移してみました。

こんな感じのマップを表示することができます。
![image](https://i.gyazo.com/a164db7164e6a08679bcf3c5bd415810.png)

URLはこちら
https://halsk.github.io/pharmacies-tiles/index.html

## GeoJSON から XYZ タイルを作る

詳しくは [github](https://github.com/halsk/pharmacies-tiles) の方を見てもらえればと思いますが、以下の処理を CircleCI 経由で行っています

1. tippecanoe をインストール
2. 以下の Rakefile を実行

    ```
task :default do
    sh "curl https://raw.githubusercontent.com/kiang/pharmacies/master/json/points.json | tippecanoe -f -o pharmacies.mbtiles --base-zoom=2"
    sh "tile-join --output-to-directory=zxy --force --no-tile-compression --no-tile-size-limit pharmacies.mbtiles"
end
```

3. gh-pages ブランチに push

重要なのは Rakefile 部分ですが、最初に GeoJSON をダウンロードして、それに対して `tippecanoe` コマンドを使い `.mbtiles` ファイルを生成しています。`--base-zoom=2` をつけないと、勝手に間引いてしまいました。
次に `tile-join` コマンドで XYZ タイルを作成しています。` --output-to-directory` オプションをつけることで、XYZ ファイルの出力先を指定することができます。

ちなみに、この処理は１分毎に CircleCI の cron トリガーで実行されています。詳しくは、[.circleci/config.yml](https://github.com/halsk/pharmacies-tiles/blob/master/.circleci/config.yml) を見てください。

## XYZ タイルを表示する

Mapbox-GL JS を使っている場合、以下のような記述で呼び出せます。

```
map.on('load', function() {
  map.addLayer({
        "id": "pharmacies",
        "type": "circle",
        "source": {
            "type": "vector",
            "tiles": ["https://halsk.github.io/pharmacies-tiles/zxy/{z}/{x}/{y}.pbf"],
            "maxzoom": 14
        },
        "source-layer": "pharmacies",
        "paint": {
            'circle-radius': 5,
            "circle-stroke-width": 1,
            // color circles by ethnicity, using a match expression
            'circle-color': [
                "case",
                [
                    ">",
                    ["get", "mask_adult"],
                    200
                ],
                "hsl(252, 91%, 42%)",
                [
                    ">",
                    ["get", "mask_adult"],
                    100
                ],
                "hsl(65, 97%, 57%)",
                [
                    "<",
                    ["get", "mask_adult"],
                    101
                ],
                "hsl(0, 98%, 53%)",
                "#000000"
            ]
        }
    })
});
```

`tiles` のところで、GitHub Pages の URL を指定しているわけですね。
`circle-color` の指定では、在庫の数ごとに赤、黄、青で色を分けています。

実は、まだいくつか気になる [Issueややりたいこと](https://github.com/halsk/pharmacies-tiles/issues) がいくつかあるのですが、そちらについてはまた今度。

ファイルを分割してXYZベクタータイル化することで、重かった GeoJSON を軽くすることができました。

このデータソースはまだ8M程度なのでそのままでも使えますが、もっと大きなデータを扱う場合、このような方法も検討してみていただけると良いのではないでしょうか。

hfu さん、ありがとうございました！