WebGISの構築5−Tileserverによる配信

今回は、下図赤枠部分に示すmbtilesからクライアントへ地図タイルを配信する仕組みを構築します。

今回構築する仕組みと本記事の範囲

地図配信とは

”地図配信”とは、クライアント(ブラウザやQGISなどのアプリケーション)からの地図データ配信要求に対して、地図データ(地図タイル)を返却する仕組みです。今回は、GoogleMapにて開発されWebGISの地図配信のデファクトスタンダードである”XYZタイル方式”にて地図配信を行います。
要求と返却は、HTTPプロトコルにて行われます。
この方式は、以下のようなHTTPリクエスト(地理院地図の例)を発行し、応答として地図画像(256✖️256のpngやjpeg形式)を取得します。
https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png
リクエストパラメータのz、x、yは、それぞれz(ズームレベル)、x(横軸)、y(縦軸)のことです。

下図はズームレベルの0から2までの地図を示していますが、1つの地図のサイズは同じなので、ズームレベルが上がることに地図が詳細化していきます。ズームレベルは、理論上は無限に設定(1タイル数センチなど)できますが、地理院のサイトでは2から18までとなっています。参考までにレベル18の縦横の長さは約122メートルです。

国土地理院のWebサイト”地理院タイル について”より引用
https://maps.gsi.go.jp/development/siyou.html

また、緯度経度によって決まるズームレベルごとのx、yの値は、以下のサイトで確認できます。

https://maps.gsi.go.jp/development/tileCoordCheck.html

上記サイトで羽田空港付近を表示すると、右下のタイルのズームレベル=15、x=29107、y=12909であることが確認できます。

羽田空港付近のレベル15の地図

実際の地図配信要求を確認しましょう。ブラウザから以下のURLを発行します。

https://cyberjapandata.gsi.go.jp/xyz/std/15/29107/12919.png

すると、以下のように256✖️256の画像ファイル(png)が取得できます。この画像を”地図タイル”と呼びます。

地理院地図から配信された地図(画像)

この画像を”地図タイル”と呼びます。
この地図タイルは画像形式の地図ですが、今回大阪市DMから変換する地図タイルは、”ベクトル形式”になります。
ベクトル形式の地図タイルの内容は、GeoJSONの内容と同じで、座標情報(Geometryタグ)や属性情報(Propertyタグ)から構成されます。

地図配信サーバーとは

地図配信サーバーとは、その名の通り”地図タイルを配信するためのサーバーアプリケーション”です。
先ほどの地図タイル取得リクエストからもわかるように、特に”地図配信サーバー”を用意しなくても、Apacheやnginxなどの通常のWebサーバーを使って地図タイルを配信することができます。具体的には、Webサーバーのコンテンツとして、z、xのディレクトリを作成し”y.png”という名前の地図タイルを配置すれば配信は可能です。
ただ、この方式では管理するファイル数が非常に多くなってしまいますし、地図に関するメタ情報(tile.json)もファイルを手作りして配置しなければなりません。

地図タイル配信用のサーバーアプリケーション(地図配信サーバー)を導入することで、こういった問題を解決することができます。地図配信サーバーは以下のような機能を持ちます。

  • mbtilesのような複数の地図タイルを集約したファイルからの地図タイル配信
  • 地図メタデータ(tile.json)の配信
  • 一部のHTTPヘッダー情報の制御(CORS関連)

地図配信サーバーは、ArcGISのような商用のものに加えオープンソースのものもあります。
以下のURL(英語)にていくつかリストアップされています。

https://github.com/mapbox/mbtiles-spec/wiki/Implementations

例えば、以下はPythonで作成された画像タイルのみに対応した地図配信サーバーです。

https://github.com/perrygeo/python-mbtiles

python-mbtilesのソースコードは、3ファイルから構成され、実ステップ数195行というとても短いものです。
処理内容は、クライアントからの地図タイル取得要求に対し、mbtilesファイル(SQLite形式)上のテーブル”tiles”に対してSQLを発行し、取得したタイルデータを返却するというものです。以下に地図タイルを取得するSQLを発行する部分のソースを示します。

pytghon-mbtilesのソースコード抜粋

特にキャッシュ機構などはなく、URLで要求された1タイルごとにSQL(SELECT文)を発行しているようです。性能面はともかくシンプルな実装です。

TileServer-GLとは

ここからが本題のTileServer-GL(以降、単にTileServer)のお話です。
TileServerは、Mapbox社が開発したオープンソースのタイル配信サーバーで以下の特徴があります。

  • mbtiles形式のラスター地図/ベクター地図が配信できる
  • スタイル指定の配信に対応している(複数のmbtilesを配信可)
  • 地図描画ライブラリ(mapbox-gl)を配信できる
  • 一部のHTTPヘッダーを制御できる(Access-Control-Allow-Origin)
  • node-js上で稼働し、Dockerイメージも存在

上記は、連載の中で説明していきますので、とりあえず、ラスター/ベクター共に配信でき、Dockerイメージも提供されている地図配信サーバーと理解いただければよいと思います。
公式ドキュメント(英語)は以下となります。

https://tileserver.readthedocs.io

TileServerの導入

それでは、TileServerを導入しましょう。環境などを以下に示します。

  • OSはCentOS8(CentOS Linux release 8.1.1911)
  • TileServerはDockerイメージを使用
  • Dockerのバージョンは”18.03.1-ce”

なお、Dockerの導入方法については以下の記事を参考にしてください。

Dockerイメージの取得と起動

TileServerの導入方法は、以下のURL(github)に書かれています。

https://github.com/maptiler/tileserver-gl

TileServerの導入方法(githubより引用)

”docker run”してしまえば、docker-hubからイメージをダウンロードしてコンテナ化、実行までしてくれます。
dockerコマンドの起動イメージは、以下のようになります。

$ docker run -d -it –name tileserver -v /home/takamoto/tiledata/osakadm/:/data -p 30002:80 klokantech/tileserver-gl

run:docker-hubからイメージをダウンロード(pull)しコンテナにコンパイルして起動する指定です。
-d:デーモン(常駐)モードで起動します。
-it:Dockerコンテナとホスト側の標準入出力を接続し、シェルでコマンド投入できる(docker exec)ようにします。
-v:データ配置ディレクトリをマッピングします。Dockerコンテナ側の”/data”は固定で、ホスト側はmbtilesを配置したディレクトリを指定します。
-p:ポートの指定です。Dockerコンテナ側は80固定ですので、ホスト側は任意のポートを指定します。
klokantech/tileserver-gl:イメージ名とタグ名です。

起動後、ブラウザからサイトのポート30002(http://hoge-host:30002)にアクセスすると、ブラウザに以下のような画面が表示されます。

TileServerの初期画面

この状態で、”Inspect”(点検)ボタンを押下すると以下のような地図が表示されます。

大阪市DMからmbtilesに変換し配信・表示された地図

上記は、デフォルトで作成されたJavaScript(MapboxGLJS、もうすぐ嫌というほど説明します)にて表示されています。復習を含みますが、地図表示までの流れは以下のようになります。

  • 大阪市DMから抽出・変換したGeoJSONを
  • tippecanoeにてベクトルのmbtilesに変換し
  • TileServerから配信された”地図タイル”(ベクトル、pbf形式)を
  • MapboxGLJSにて表示した状態

なお、地図上では以下の操作が可能です。

  • マウスホイールによる拡大・縮小
  • マウス右ボタンドラッグによる3D視点移動と回転
  • マウスオーバーによる属性表示
マウスオーバーによる属性表示
3D表示状態

デモサイトは以下となります。(プロキシ経由でSSL化済み)

IE(インターネットエクスプローラ)では表示できませんので、Chromeなど他のブラウザをご利用ください。

まとめ

今回はここまでとします。
次回は、nginxを使ったプロキシ化とSSL化について説明します。