こんにちは。
この記事は、**ベクトルタイルのアドベントカレンダー(2021)の3日目(12月3日)**の記事として書きました。(限定公開するということを知りませんでしたので、少し前から見られる状態になっておりましてすみません。)
@naogify さんの12月2日の記事に続いて投稿させていただきます。@naogify さん、ご紹介ありがとうございました。
Qiitaは書き始めてちょうど一ヶ月くらいの初心者ですが、どうぞよろしくお願いします。
この記事では、皆さんのベクトルタイルを簡単にArcGIS Onlineで表示する方法を紹介したいと思います。
はじめに
ベクトルタイルは様々なところで利用されています。ここでは、MapLibreやmapbox gl jsなど様々なライブラリで消費されているベクトルタイルのうち、ArcGISサーバー以外から供給されているものをArcGISで表示してみるということを試しました。今回は、地理院地図Vector(仮称)のベクトルタイル(の一部のレイヤ)をArcGIS onlineで表示してみます。
今回の試行にあたっては、Google Cloud Storageに格納したベクトルタイルをArcGIS onlineで表示するというこのページの記事(David Hollema, 2020)を参考にしています。
使った素材(スタイル)
- 地理院地図Vector(仮称)のいくつかのレイヤを作って使った簡単なスタイル:
https://ubukawa.github.io/plib-mlb01/test-style.json
MapLibreで描くとこんな地図になります。
本当は、地理院地図Vector(仮称)のmapbox gl js に準拠したスタイル(標準地図風)を使いたかったのですが、レイヤ数が多くスタイルの記載が複雑なので、まずは上記の簡単なスタイルを利用します。(上記スタイルを作った際の記事はこちら)
作業環境
-
GitHub
レポジトリを作って、GitHubページにしました。 -
ArcGIS online
読み込みを試しましたが、ArcGIS EnterpriseのArcGIS onlineだと思います。(バージョンはいくつかわかりません。) -
テキストエディタ
JSONファイルの作成に使いました。
手順
Step1. ArcGIS REST APIの研究
ArcGIS onlineでArcGISサーバー以外から供給されているベクトルタイルを利用するためには、ArcGIS REST APIsのVector Tile Serviceを返すことができるサーバーが必要になるようです(David Hollema, 2020)。
そこで、ArcGIS REST APIsのベクトルタイル関係のところについて、まずはREST APIの文書をよんでみたところ、主な機能は以下の通りです。ここは参考程度なので、難しいと思われる人はStep.2に行きましょう。
名前 | 文書の説明 | 私の感想など |
---|---|---|
Vector Tile Service | VectorTileServiceのパスで、ベクトルタイルサービスに関する情報(タイル情報、空間参照系、初期及び最大範囲等)を返す。 | jsonでつくればよさそう。 |
Vector Tile | VectorTileService/tile/{z}/{y}/{x}.pbf というパスでpbfタイルを返す機能。 | ベクトルタイルサーバーを指定してあげれば大丈夫そう。z, y, xは、level, row, columnという表現で説明されています。xyzの順番が会社によって違いますが、パスをきちんと指定すれば大丈夫です。 |
Vector Tile Style | VectorTileService/resources/styleというパスでMapbox GLスタイル仕様(ver.8)のスタイル情報を返すとのこと。このスタイルはspriteとフォント(glyphs)を相対パスで含むということ。 | このパスにroot.jsonというスタイルファイルを置いておけばよい。実際には多分mapbox gl のスタイルに対応していない部分があると思います(属性で色を塗分けようとして、colorの中でmatchを使うと失敗する 等)。また、ここのspriteとfontの場所を調整すれば下の2つは違うパスでもいいと思います。 |
Vector Tile Font | VectorTileService/resources/fonts/{fontstack}/{range}.pbfでフォントを返します。 | glyphsの場所だと理解すればいいと思います。 |
Vector Tile Sprite | VectorTileService/resources/sprites/sprite.json, sprite.png などで、sprites関係のものを返します。 | これもspritesの場所と理解すればいいと思います。 |
Vector Tile Resource Info | VectorTileService/resources/infoで、リソースの場所を返しているようです。 | fontとspriteのパスをリストしておけばよさそうです。(しかし、なくても動きました。) |
Vector Tilemap | 各ズームレベルのタイルの有無を記述しているもののようです。 | 多分、オーバーズーミングをうまく働かせるためには、ここの準備が必要なのではないかと思います。今はわかりませんが今後研究したいです。 |
Step2. ArcGIS REST APIに準じたサーバーの準備1:GitHubページ作成
今回参考にしたDavid Hollema (2020)の例では、Google Cloud Storageで対応していましたが、私はJSONファイルをつくってGitHubページにホストしてみることにします。
David Hollema (2020)をよく読んでみると、VectorTileServer/index.json のパスでベクトルタイルサービスの概要を返すJSONファイルと、VectorTileServer/resources/styles/root.jsonのパスでスタイルを返すJSONファイルがあればよさそうなことがわかりますので、この二つを作ってホストすると方針を立てました。
まずはこのようなGitHubのレポジトリ(下図)をつくって、そこにVectorTileServerをつくりました。そのなかには、resources/stylesというフォルダも作りました。作ったレポジトリはGitHubページとしてホストしました。
Step3. ArcGIS REST APIに準じたサーバーとファイルの準備2:index.jsonをつくる
REST APIのサンプルのページなどを参考にして、以下のようなindex.jsonを作成しました。間違っている部分もあるかもしれませんが書いてみました。
{
"currentVersion": 10.9,
"name": "VT Test 3",
"capabilities": "TilesOnly",
"copyrightText": "地理院地図Vector(仮称)",
"type": "indexedFlat",
"defaultStyles": "resources/styles",
"tiles": [
"https://cyberjapandata.gsi.go.jp/xyz/experimental_bvmap/{z}/{x}/{y}.pbf"
],
"exportTilesAllowed": false,
"initialExtent": {
"xmin": -2.0037507842788246E7,
"ymin": -2.0037508342787E7,
"xmax": 2.0037507842788246E7,
"ymax": 2.0037508342787E7,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"fullExtent": {
"xmin": -2.0037507842788246E7,
"ymin": -2.0037508342787E7,
"xmax": 2.0037507842788246E7,
"ymax": 2.0037508342787E7,
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
}
},
"minScale": 2.958287637957775E8,
"maxScale": 4513.9887055,
"tileInfo": {
"rows": 512,
"cols": 512,
"dpi": 96,
"format": "pbf",
"origin": {
"x": -2.0037508342787E7,
"y": 2.0037508342787E7
},
"spatialReference": {
"wkid": 102100,
"latestWkid": 3857
},
"lods": [
{
"level": 0,
"resolution": 78271.516964,
"scale": 2.958287637957775E8
},
{
"level": 1,
"resolution": 39135.75848199995,
"scale": 1.479143818978885E8
},
{
"level": 2,
"resolution": 19567.87924100005,
"scale": 7.39571909489445E7
},
{
"level": 3,
"resolution": 9783.93962049995,
"scale": 3.6978595474472E7
},
{
"level": 4,
"resolution": 4891.96981024998,
"scale": 1.8489297737236E7
},
{
"level": 5,
"resolution": 2445.98490512499,
"scale": 9244648.868618
},
{
"level": 6,
"resolution": 1222.992452562495,
"scale": 4622324.434309
},
{
"level": 7,
"resolution": 611.496226281245,
"scale": 2311162.2171545
},
{
"level": 8,
"resolution": 305.74811314069,
"scale": 1155581.1085775
},
{
"level": 9,
"resolution": 152.874056570279,
"scale": 577790.5542885
},
{
"level": 10,
"resolution": 76.4370282852055,
"scale": 288895.2771445
},
{
"level": 11,
"resolution": 38.2185141425366,
"scale": 144447.638572
},
{
"level": 12,
"resolution": 19.1092570712683,
"scale": 72223.819286
},
{
"level": 13,
"resolution": 9.55462853563415,
"scale": 36111.909643
},
{
"level": 14,
"resolution": 4.777314267817075,
"scale": 18055.9548215
},
{
"level": 15,
"resolution": 2.388657133974685,
"scale": 9027.977411
},
{
"level": 16,
"resolution": 1.19432856698734,
"scale": 4513.9887055
}
]
},
"maxzoom": 16,
"resourceInfo": {
"styleVersion": 8,
"tileCompression": "gzip",
"cacheInfo": {
"storageInfo": {
"packetSize": 128,
"storageFormat": "compactV2"
}
}
},
"minLOD": 4,
"maxLOD": 16,
"maxExportTilesCount": 100000,
"supportedExtensions": ""
}
なお、上記のjsonファイルはこちらにあります。このファイルを書いた際に注意点したは以下の通りです。
- 今回準備するページではREST APIの機能はあまりないので、capabilityはTilesOnlyにしてあります。
- typeはindexedFlatでも、indexedVectorでも違いはなかったように思います。
- tilesは、相対パスでpbfの場所を指定するのが一般的なようですが、今回は外部のタイルをつかうので絶対パスで外部のURLを指定しました。地地理院地図ベクター(仮称)のタイルのURLに( https://cyberjapandata.gsi.go.jp/xyz/experimental_bvmap/{z}/{x}/{y}.pbf )にしています。
- inititalExtentとfullExtentの投影法はウェブメルカトル(EPSG3857)なので、単位がメートルです。空間参照系の記載ぶりは同じwkid102100でもいくつかパターンがあるようです(csとwkidで記載するもの、wkidとlatestwkidで記載するもの)。また、日本ではなくグローバルデータセットと同じ範囲をつかっていますので将来微修正してみる余地があります。
- minScaleとmaxScaleはそれに相当するズームレベルのスケールを拾ってきます。
- タイルのrows, cols, dpiはpbfタイルなら、512, 512, 96で決まっているようです。
- lodsはズームレベルごとに値が決まっているようです。他の例を参考に必要なズームレベルまで書くとよいと思います。なお、lod(Level of detail)の説明はこちらにありました。
- MinLODとMaxLODはオーバーズーミングに関係するかなと思って追加しています。参考にしてたサンプルページにはないのでなくてもいいかもしれません。
- resourceInfoがない例もあるので、なくても大丈夫かもしれません。
出来たファイルはGitHubにアップして、GitHubページから公開しました。以下のどのURLにアクセスしても同じファイルがみられると思います。
https://ubukawa.github.io/VTtest3/VectorTileServer/index.json
https://ubukawa.github.io/VTtest3/VectorTileServer
https://ubukawa.github.io/VTtest3/VectorTileServer?f=pjson
https://ubukawa.github.io/VTtest3/VectorTileServer?f=json
Step4. ArcGIS REST APIに準じたサーバーとファイルの準備3:スタイルファイル(VectorTileServer/resources/styles/root.json)をつくる
もう一息です。次は、スタイルファイルを準備しました。今回は実験用にシンプルなスタイルを用意しました。
過去にArcGIS Onlineでスタイルを変えて表示した経験から、いきなり地理院地図Vector(仮称)のmapbox gl js に準拠したスタイル(標準地図風)を使ってもうまくいかないだろうと考えました。ArcGISのベクタータイルのスタイルはmapboxのスタイル仕様に準じていますが、100%は対応していない部分があると思っています(例えば、fill-color やline-colorの中でmatchを使って属性ごとに色を塗ろうとしてもうまくいかなかったり、スタイルで複数のベクトルタイルソースを指定してもうまくいかなかったことがあった)。
以下が作成したスタイルファイルです。
{
"version": 8,
"name": "GSI test",
"sources": {
"s": {
"type": "vector",
"url": "https://ubukawa.github.io/VTtest3/VectorTileServer/",
"minZoom": 4,
"maxZoom": 16
}
},
"sprite": "https://gsi-cyberjapan.github.io/gsivectortile-mapbox-gl-js/sprite/std",
"glyphs": "https://maps.gsi.go.jp/xyz/noto-jp/{fontstack}/{range}.pbf",
"layers": [
{
"id": "background",
"paint": {
"background-color": "#D6EBF5"
},
"type": "background"
},
{
"id": "ls-coastline",
"type": "line",
"source": "s",
"maxzoom": 9,
"minzoom": 4,
"source-layer": "coastline",
"paint": {"line-color": "#636566"}
},
{
"id": "pg-watera",
"type": "fill",
"source": "s",
"source-layer": "waterarea",
"minzoom": 4,
"maxzoom": 7,
"paint": {"fill-color": "rgba(46, 0, 255, 1)"}
},
{
"id": "ls-boundary-pref",
"type": "line",
"source": "s",
"source-layer": "boundary",
"minzoom": 6,
"maxzoom": 8,
"filter": ["all", ["==", "ftCode", 51212]],
"layout": {"line-cap": "square"},
"paint": {
"line-color": "#000000",
"line-dasharray": [10, 2, 1, 2]
}
},
{
"id": "ls-boundary-cty",
"type": "line",
"source": "s",
"source-layer": "boundary",
"minzoom": 4,
"maxzoom": 8,
"filter": ["all", ["==", "ftCode", 51221]],
"layout": {"line-cap": "square"},
"paint": {"line-color": "rgba(34, 24, 21, 1)"}
}
],
"_ssl":true
}
作成したファイルは、GitHubレポジトリのVectorTileServer/resources/stylesの中にroot.jsonとして保存しました(こちら)。注意した点は以下の通りです。
- sourceのところではpbfの場所を指定するのではなくて、前のstepでつくったindex.jsonを返してくれるサーバーを指定します。(私はここをpbfにしていたので、うまくいかなかった。)
- spriteとglyphsは相対パスで指定するのではなく、絶対パスで地理院地図Vector(仮称)の使っているURLを指定しました。もし、これらをresourcesの中に自分で準備すれば相対パスでの指定でいいと思います。
- 最後の_sslはmaoboxスタイル仕様にはないと思うのですが、ArcGISサーバーからでているベクトルタイルのスタイルでは使っていることがあるので、つけています。ここのセッティングがどう影響しているのかはまだよくわかりません。
- metadataは特に書いていません。
Step5. ArcGIS Onlineで読み込む。
前のStepまでで、ArcGIS REST APIに準じたサーバーができました。index.jsonを返してくれるパスはhttps://ubukawa.github.io/VTtest3/VectorTileServer になります。これをベクトルタイルサービスとしてArcGIS Onlineに登録します。
5-1. ArcGIS Online で Map を開く
David Hollema (2020)に書いてある通り、ArcGIS OnlineのContentsからはベクトルタイルの登録ができません。ですので、一度Mapを開いてそこにコンテンツを読み込んでから保存するという手順を取ります。(コンテンツで読み込めない理由はREST APIの何かの機能がかけているからだろうと書かれています。)
5-2. Map にレイヤを追加する
マップを開いたら、"Add"ボタンから、"Add Layer from Web"を選びます。
そして、An ArcGIS SErver Web ServiceのURLに、今回作ったサーバーのURL(index.jsonを返してくれるURL)を指定します。ここでは、https://ubukawa.github.io/VTtest3/VectorTileServer になります。
すると、ベクトルタイルの地図が見られます。右下にデータの出典も出てきています。
5-3. Map に追加したレイヤを保存する
レイヤのメニューから、レイヤの保存を選んでコンテンツとして保存します。
タイトルはサーバーの名前できまるので、タグやサマリーを追加します。
ここまでで、外部ベクトルタイルをArcGIS Onlineで読み込むということを試しました。無事に表示されたかと思います。(なお、ArcGIS Online のバージョンによっては、投影法の関係のエラーがでて読み込めないケースもあるようです。)
今後の作業
今回はシンプルなスタイルファイルを使いましたが、ここのスタイルファイルを地理院地図Vector(仮称)のmapbox gl js に準拠したスタイル(標準地図風)に近づけることで、ArcGIS Onlineで地理院地図が使えるようになります。どの表現がOKでどの表現がダメか確認しながら調整する作業が必要です。
また、地理院地図Vector(仮称)のタイルはZL16までですが、オーバーズーミング(例えばZL17とかZL18とかでZL16のタイルを表示する)ができるかどうかも重要な点です。今後、もう少し調査を進めたいと思っています。
#####追記
オーバーズーミングについて、小縮尺で簡単な実験をしてみました。こちらに記事があります。
GitHubページでArcGIS Onlineでも表示できるベクトルタイルサーバーを作る(オーバーズーミングつき)
謝辞
すでに記していますように、本作業は私のオリジナルではなく、このページの記事(David Hollema, 2020)を参考にしています。ありがとうございます。また、このページのことを教えてくだった皆様にも感謝しています。