はじめに
ArcGIS Onlineで外部ベクトルタイルを表示することは以前の記事で行い、ArcGISベクトルタイルサーバの観察はこちらの記事で行いました。本記事では、ArcGIS Onlineでベクトルタイルのオーバーズーミングをする過程を記載します。
本記事はこちらの記事を参考にさせていただいています。
特に、ズームレベルを上げていく際に、maxLODやmaxZoom、スタイルファイルでのズームレベル設定など、様々な設定項目があり、それが地物の表示にどのような役割を果たしているのかを実験しながら確かめたいと思います。
1. ベクトルタイルの作成
参考記事と同様にNaturalEarthのデータを使用します。ダウンロードページから、「1:110m Physical Vectors」の「Coastline」、「Land」、「Rivers,Lake Centerlines」、「Graticules 30」をダウンロードします。
以下のようなベクトルタイル構成とします。参考記事では、ズームレベル2で作成されていますが、ここではズームレベルに関して色々と実験したいので、2と3で作成しました。
レイヤ名 | ソース | Min Zoom | Max Zoom |
---|---|---|---|
coastl | ne_110m_coastline.shp | 0 | 3 |
landmass | ne_110m_land.shp | 0 | 3 |
riverl | ne_110m_rivers_lake_centerlines.shp | 0 | 2 |
graticules30 | ne_110m_graticules_30.shp | 0 | 2 |
ベクトルタイルの作成方法はこちらの記事に記載しています。記事にある通り、shp→GeoJSON→ベクトルタイルの順番でデータを変換します。
ズームレベル2,3をそれぞれ作成する必要があるため、以下の2つのコマンドを使用しました。
ズームレベル3を作成
tippecanoe -e VTcoastl_landmass_zl3 --no-tile-compression --no-feature-limit --no-tile-size-limit --drop-rate=1 -Z0 -z3 -L coastl:coastl.geojson -L landmass:landmass.geojson
ズームレベル2を作成
tippecanoe -e VTriverl_graticules30_zl2 --no-tile-compression --no-feature-limit --no-tile-size-limit --drop-rate=1 -Z0 -z2 -L riverl:riverl.geojson -L graticules30:graticules30.geojson
その後、tile-joinを使用して、2つのベクトルタイルを統合しました。
tile-join -e VT --no-tile-size-limit --no-tile-compression --minimum-zoom=0 --maximum-zoom=3 VTcoastl_landmass_zl3 VTriverl_graticules30_zl2
コマンドを実行すると、ベクトルタイルのズームレベルが合致していないという以下の警告が出ましたが、ベクトルタイル自体は作成出来ました。
Warning: mismatched maxzooms: 3 in VTcoastl_landmass_zl3 vs previous 2
ついでにmbtilesも作成しておきます。
tile-join -o VTtest.mbtiles --no-tile-size-limit --minimum-zoom=0 --maximum-zoom=3 VTcoastl_landmass_zl3 VTriverl_graticules30_zl2
以下に格納されています。
https://github.com/k96mz/20250117tilemap/tree/main/VectorTileServer/data/mbtiles
2. GitHubページでのホスティング
Gethubページに新しいレポジトリを作成しました。
Esriさんのページに記載されているようにフォルダを構成します。
具体的には、VectorTileServerフォルダの下にtileフォルダを作成し、そこにベクトルタイルを格納します。ベクトルタイルはz/x/y.pbfという構造にする必要があります。
ベクトルタイルを作成する際にVTという名前を使用していましたが、ここもtileという名前で作ると便利だったかもしれません。
Github > Settings > Pages からデータをホストする設定を行います。これで、以下のURLからベクトルタイルへのアクセスが可能となります。
https://k96mz.github.io/20250117tilemap/VectorTileServer/tile/{z}/{x}/{y}.pbf
3. スタイルファイル作成
アップロードしたベクトルタイルを見るためにMaputnikを使用してスタイルファイルを作成します。Maputnikの使用方法はこちらの記事で解説しています。
Maputnikを使用して以下のようにスタイリングを行いました。
スタイルは参考記事同様に以下のように整理しています。
レイヤID | Type | Min Zoom | Max Zoom |
---|---|---|---|
background | background | na | na |
coastl | line | na | 6 |
landmass | fill | na | 6 |
riverl | line | na | 6 |
graticules30 | line | na | 2 |
Max Zoom以上に拡大すると該当レイヤは見られなくなります。
注意
Maputnikが不安定なのか、作成したMaxズームレベル + 1まで(例えばlandmassなら4)しか見られないときもあります。つまりはズームレベルが4になった瞬間に見られない時がありました。(ズームレベル6まで継続して見られませんでした。)
これは、もしかしたら、tile-joinを使用した影響があるのかもしれません。
Maputnikの使用方法を説明した記事でも言及していますが、sourcesの"maxzoom"はレイヤの表示に影響を与えないようです。
作成したスタイルファイルを利用した地図は、Maputnikを利用してこちらから見られます。
作成したスタイルファイルは、tileのパスが指定されていますが、ArcGIS OnlineではサーバURLを記載する必要があるようですので、以下に変更する必要があります。
https://k96mz.github.io/20250117tilemap/VectorTileServer/
また、tilesをurlに変更する必要があること、タイルを指定する際にあった[]を削除することにも、注意が必要です。urlの最後のスラッシュは削除しています。
変更後のスタイルファイルは以下のとおりです。Esriさんのドキュメントに記載のある通り、VectorTileServerフォルダの下にresources/stylesフォルダを作成して、root.jsonとして保存します。
{
"version": 8,
"name": "Empty Style",
"metadata": { "maputnik:renderer": "mlgljs" },
"sources": {
"v": {
"type": "vector",
"url": "https://k96mz.github.io/20250117tilemap/VectorTileServer",
"minzoom": 0,
"maxzoom": 8,
"scheme": "xyz"
}
},
"sprite": "",
"glyphs": "https://orangemug.github.io/font-glyphs/glyphs/{fontstack}/{range}.pbf",
"layers": [
{
"id": "background",
"type": "background",
"paint": { "background-color": "rgba(35, 113, 123, 1)" }
},
{
"id": "coastl",
"type": "line",
"source": "v",
"source-layer": "coastl",
"maxzoom": 6,
"paint": { "line-color": "rgba(15, 16, 14, 1)" }
},
{
"id": "landmass",
"type": "fill",
"source": "v",
"source-layer": "landmass",
"maxzoom": 6,
"paint": { "fill-color": "rgba(191, 142, 92, 1)" }
},
{
"id": "riverl",
"type": "line",
"source": "v",
"source-layer": "riverl",
"maxzoom": 6,
"paint": { "line-color": "rgba(8, 45, 214, 1)" }
},
{
"id": "graticules30",
"type": "line",
"source": "v",
"source-layer": "graticules30",
"maxzoom": 2,
"paint": { "line-color": "rgba(222, 16, 16, 1)" }
}
],
"id": "9vv30hv"
}
Esriドキュメントにない、"metadata"や"_ssl"の記載があっても問題ないようです。
4. ベクトルタイルサーバ情報の作成
Esriドキュメントを参照して、VectorTileServerフォルダの下に、index.jsonを作成します。
{
"currentVersion": 10.9,
"name": "20250117tilemap",
"capabilities": "TilesOnly,Tilemap",
"copyrightText": "NaturalEarth",
"type": "indexedVector",
"tileMap": "tilemap",
"defaultStyles": "resources/styles",
"tiles": [
"https://k96mz.github.io/20250117tilemap/VectorTileServer/tile/{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": 1155581.1085775,
"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
}
]
},
"maxzoom": 8,
"resourceInfo": {
"styleVersion": 8,
"tileCompression": "gzip",
"cacheInfo": {
"storageInfo": {
"packetSize": 128,
"storageFormat": "compactV2"
}
}
},
"minLOD": 0,
"maxLOD": 2,
"maxExportTilesCount": 100000,
"supportedExtensions": ""
}
「"maxzoom": 8」と「"maxLOD": 2」の関係性
chatGPTによると、maxzoomがサーバが提供するタイルの最大ズームレベルを指定し、maxLODがクライアント側で表示する最大ズームレベル(LOD: Level of Detail, 詳細レベル)を制限します。つまり、ズームレベル3に達すると、クライアントは新しいタイルをリクエストせず、ズームレベル2のタイルをそのまま拡大して表示します。
"capabilities"には、"Tilemap"も含めています。
このファイルは以下のどのURLでも同じファイルにアクセスできます。
https://k96mz.github.io/20250117tilemap/VectorTileServer/index.json
https://k96mz.github.io/20250117tilemap/VectorTileServer/
https://k96mz.github.io/20250117tilemap/VectorTileServer/?f=json
※試しにベクトルタイルサーバ情報のファイル名をindex2.jsonとしてみたところ、ファイルにアクセス出来ませんでした。index.jsonとする必要があるようです。
5. tilemapの作成
次にタイルの有無を返すtilemapファイルを作成します。こちらの記事で見た通り、返すタイルが存在する場合は、ズームレベル5までは一つのファイルが必要で、ズームレベル6以上では4個以上のファイルが必要です。参考記事にもある通り、今回はズームレベル0~6のtilemapを用意します。
ベクトルタイルを作成した際のズームレベルによる挙動の違い(riverlはZL2、landmassはZL3)を確かめるために、ズームレベル3まではベクトルタイルが存在するという情報のtilemapを作成し、それ以降はベクトルタイルが存在しないという情報のtilemapを作成します。
tilemapのURL構成は以下の通りです。
VectorTileServer/tilemap/<level>/<row>/<column>/<width>/<height>
日本語で書くと、
VectorTileServer/tilemap/ズームレベル/行(縦方向)/列(横方向)/横幅/縦幅
です。
先ほど記載したとおりズームレベル5までは一つのファイルです。それぞれのtilemapは、ズームレベル毎のタイル数だけ1を持ちます。そして、1を表示する位置は32×32のタイル該当部分となります。
ズームレベル毎のtilemapを以下に示します。
ズームレベル0
{
"adjusted": false,
"location": {
"left": 0,
"top": 0,
"width": 32,
"height": 32
},
"data": [
1, 0, 0, 0, 0, 0, 0...
]
}
タイルの数は1つなので、1は最初の一個だけです。
ズームレベル1
{
"adjusted": false,
"location": {
"left": 0,
"top": 0,
"width": 32,
"height": 32
},
"data": [
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,...
]
}
タイルの数は4つなので、1,1の組み合わせが2個出てきます。
ズームレベル2
{
"adjusted": false,
"location": {
"left": 0,
"top": 0,
"width": 32,
"height": 32
},
"data": [
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0, 0,....
]
}
タイルの数は16個なので、1,1,1,1の組み合わせが4個出てきます。
ズームレベル3
{
"adjusted": false,
"location": {
"left": 0,
"top": 0,
"width": 32,
"height": 32
},
"data": [
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,...
]
}
タイルの数は64個なので、1,1,1,1,1,1,1,1の組み合わせが8個出てきます。
ズームレベル4
リクエストされたバンドル(範囲)がない、もしくは対応するズームレベルでない場合は、以下のとおり422を返します。
{ "error": { "code": 422, "message": "Tiles not present", "details": [] } }
ズームレベル5
{ "error": { "code": 422, "message": "Tiles not present", "details": [] } }
ズームレベル6
ズームレベルが6になると、32×32のタイルが4つあるので、4つのtilemapファイルを用意します。
tilemap/6/0/0/32/32/index.json
tilemap/6/32/0/32/32/index.json
tilemap/6/0/32/32/32/index.json
tilemap/6/32/32/32/32/index.json
いずれもズームレベル4、5の時と同様の以下のファイルです。
{ "error": { "code": 422, "message": "Tiles not present", "details": [] } }
6. 確認
今まで準備したものをまとめます。
ベクトルタイル:
https://k96mz.github.io/20250117tilemap/VectorTileServer/tile/{z}/{x}/{y}.pbf
スタイルファイル:
https://k96mz.github.io/20250117tilemap/VectorTileServer/resources/styles/root.json
ベクトルタイルサーバ情報:
https://k96mz.github.io/20250117tilemap/VectorTileServer/index.json
tilemap:
https://k96mz.github.io/20250117tilemap/VectorTileServer/tilemap/z/32m/32n/32/32/index.json(m,nは整数)
7. ArcGIS Online(Map Viewr Classic)での読み込み
最後にこちらの記事で記載したとおりに、ArcGIS OnlineのMap Viewer Classicで読み込んでいきます。
読み込むURLはベクトルタイルサーバ情報の以下です。
https://k96mz.github.io/20250117tilemap/VectorTileServer/
以下のようにして読み込みます。今回は、ベースマップとして読み込んでいます。
読み込むと以下のように地図が表示されました。
ズームレベル0~2については作成したタイルが読み込まれていました。tilemapについては、以下のURLのファイルが読み込まれています。
Request URL:
https://k96mz.github.io/20250117tilemap/VectorTileServer/tilemap/1/0/0/32/32?f=json
については、
Status Code: 301 Moved Permanently
と表示されました。
Request URL:
https://k96mz.github.io/20250117tilemap/VectorTileServer/tilemap/1/0/0/32/32/?f=json
については、
Status Code:200 OK
と表示されました。
参考記事も同様のファイルが存在したので、たぶん問題ないのだと思います。
上の図はズームレベル2の状態ですが、graticules30である経緯度線が消えています。これは、スタイルファイルであるroot.jsonに記載された通りの想定された挙動です。
ズームレベル3についても、作成したタイルが読み込まれました。
河川であるriverlについては、tile-joinをする過程で他の地物と統合されたベクトルタイルファイルとなっていますが、データとしてはズームレベル2までしか作成していません。実際にズームレベル3で表示したところ、下図のように河川データは表示されませんでした。
つまりは、tile-joinを行う際に、地物データにズームレベルのばらつきがあると、ズームレベルが小さい地物はそのズームレベル以降ではオーバーズーミングできないことが分かりました。オーバーズーミングをさせたい場合は、全ての地物を同じズームレベルに揃えてデータを作成する必要があります。逆に言えば、オーバーズーミングする必要がない地物だと、異なるズームレベルを持った地物でもtile-joinしても良いことになります。
index.jsonにおいて、"maxLOD": 2,としていますが、これはMap Viewer Classicだと関係ないのかもしれません。
ズームレベル4の時には、tilemapはズームレベル4のファイルが読み込まれますが、ベクトルタイルはズームレベル3のものが再度読み込まれました。例えば、以下のベクトルタイルファイルはズームレベル3で一度読み込まれ、ズームレベル4で再度読み込まれます。
https://k96mz.github.io/20250117tilemap/VectorTileServer/tile/3/6/2.pbf
そのため、キャッシュを使用できると良さそうです。
ズームレベル5はズームレベル4と同じ挙動です。
ズームレベル6は地物の表示がなくなり、backgroundだけになります。これは、スタイルファイルであるroot.jsonに記載された通りの想定された挙動です。
上図の例では、ズームレベル6にあるtilemapファイル4つのうち、読み込まれたファイルは以下です。
https://k96mz.github.io/20250117tilemap/VectorTileServer/tilemap/6/0/32/32/32/?f=json
ズームレベル6以降はtilemapファイルは存在しない(作成していない)のでエラーが返ります。同様に、ベクトルタイルファイルについてもエラーが返ります。下図はズームレベル8の例です。
ズームレベル8以降は、ファイル自体が返ってきません。これは、index.jsonでmaxzoomを8としているからな気がします。つまり、index.jsonの設定により、サーバでズームレベル8までしかベクトルタイルやtilemapを返さない設定になっているということです。しかし、ArcGIS Onlineの仕様なのか、ずっと拡大をし続けることは出来ました。もちろん、何も表示されません。
※最後に、表示させたレイヤをArcGIS Onlineに保存しておきます。
8. ArcGIS Online(Map Viewer)での読み込み
次にMap Viewer Classicではなく、Map Viewerでの読み込みを実行します。
しかし、Add Layer from URLから読み込みを実行しても、以下のとおりずっと処理中になり読み込めません。
そこで、Add layerをクリックし、先程保存したレイヤ(20250117tilemap)を追加します。
Map Viewer Classicとの違いは、ズームレベル2のベクトルタイルまでしか読み込まないことです。原因としては、index.jsonの "maxLOD": 2,によるものと思われます。試しにこれを3にして、再度Map Viewer Classicの読み込みと保存をし、Map Viewerで表示してみます。そうるすると、ズームレベル3のベクトルタイルまで読むことが出来ました。
Map Viewer ClassicとMap Viewerの表示仕様の違い
Map Viewer Classicでは、index.jsonの "maxLOD"の影響は不明であるが、Map Viewerでは"maxLOD"で規定されたズームレベルまでしかクライアントに読み込まれない。
ズームレベル関係まとめ
A. ベクトルタイル作成時のMax Zoom:それぞれのレイヤが持つ素材の最大ズームレベル
B. スタイルファイルroot.jsonのそれぞれのレイヤのmaxzoom:オーバーズーミング時の最大ズームレベル(画面で表示される際の最大ズームレベル)
C. ベクトルタイルサーバ情報index.jsonのmaxzoom:サーバが提供するタイルの最大ズームレベル。このズームレベル以降はレスポンスを返しません。
D. ベクトルタイルサーバ情報index.jsonのmaxLOD:クライアント側で表示する最大ズームレベル
※Cが一番大きな値を取る。Bのレイヤの一番大きなmaxzoom値を、Dの値にすると整合が取れる
読み込みURLを変更してみる
こちらのEsriドキュメントに記載の通り、以下のようなURLにしないといけないのかもしれません。
https://<fully qualified web adaptor machine name>/<web adaptor name>/rest/services/<service name>/<service type>.
そのため、以下のURLで読み込まれるか実験してみました。また、フォルダなども新しく作成しました。
https://k96mz.github.io/20250117tilemap/rest/services/service/VectorTileServer
無事に読み込み出来ました!!!
Map Viewerで保存を選択することが出来ませんでした。
しかし、ContentのNew itemから保存することが出来ました。
まとめ
今回はArcGIS Onlineでベクトルタイルのオーバーズーミングを試しました。Map Viewer ClassicとMap Viewerの表示仕様の違いが分かったのが大きな成果です。
Reference