vectiles mix-in: GeoJSON タイルによるパブリックデータのミックスイン
この記事は FOSS4G Advent Calendar 2013 : ATND の2013年12月13日(金)の記事です。
コモディティ化しつつあるベクトルタイルについて、考察と実験の結果を共有します。
ベクトルタイルということ。
Geo+Web界隈で、これまで技術力の高いウェブ地図サービスで個別に実装されてきたベクトルタイルがコモディティ化しそうになってきたのは今年も半ばに入ってからであった。 Vector Tiles Preview: Designing the World with TileMill2 | Mapbox 等が、その流れを宣言するものであった。その後、TileMill2 においては、その内部で地図デザインをストレスなく利用するための手段として、ProtocolBuffer ベースのベクトルタイルが使われるという状態になっている。ウェブブラウザにおけるベクトルタイルの利用は、MapBox さんのエコシステムでは多少優先度が低いのかもしれない。
ベクトルタイルにGeoJSONを使うということ。
他方、openstreetmap.us で migurski さんが主導する方面では、より straightforward な実装である、GeoJSON によるベクトルタイルが明示的に試されてきている。
Mapnik Vector Tiles
GeoJSONベクトルタイルは、おそらくMapBoxさんが当面の実利用においては断念したものであり、コンシューマ向けサービスですぐに「フルベクトル」で利用されうるものではない。むしろ、TopoJSONのみに限らず、今後いくらかの改善がなされた上で、まずはベクトルであることが有利な情報から、利用されていくのではないか。
しかし、当面の技術試験のためには、ライブラリが揃っていてブラウザで気軽に実験できるGeoJSONタイルを試すことには意義がある。
低い合意としてのGeoJSON。
GeoJSONは、「理想のフォーマット」として生まれたものではない。むしろ、既存の標準化に対する技術面・手続き面のアンチテーゼとして生まれたようなところがある。
そのことは、sgilles さんが foss4gna-2013 で GeoJSON is Spectacularly Wrong として明示的に語ってくださったところである。
GeoJSONを使うということ自体が、何か高いものを回避する、何かを諦めて現実的なレベルで話を進めるという工学パターンを体現している。フォーマット面に力をあえて入れず、本質的に重要な先に進むというアプローチをとる場合に、GeoJSONを使うことが多い。
GeoJSONについては、tmcwさんが強力にドライブされている geojson.io: Edit GeoJSON やその裏にある? toGeoJSON - macwright.org も見るべきである。これらも、実は2013年に行われた。ずいぶん昔のことであるようにも感じる。
バイナリアンなベクトルタイル及びSVGを後回しにすること。
ベクトルタイルにおいては、MapBoxさんがTileMill2という状況に対して示した回答であるProtocolBufferベースのタイルや、歴史を誇りWeb標準の流れの中心にあるSVGによるタイルもある。しかし、これらの採用について考えることを留保し、GeoJSONを当面用いておいて応用について考えることをしたい。
座標の表現の効率化を考えることを後回しにすること。
また、バイナリアンではないベクトルタイルの配信において致命的に重要になるのは、座標データをどのようにシリアライズするかである。正解は、整数化した上で差分エンコードすることであるということはほぼ決まりきっている。特にタイルにおいては、画像座標(画面座標)に整数化して差分エンコードすることが、タイルの用途からして、間違いない正解であろう。ここに、SVGのPath Expressionの知見が生きる場所がある。しかし、このことについて考えるのは、ベクトルタイルの応用についてめどがたってからにしよう。
大縮尺でのベクトルタイルに可能性を見出すこと。
ベクトルタイルの応用サンプルでよく見られる失敗パターンは、画面中に大量のベクトルデータを表示してしまって、ブラウザがにっちもさっちもいかなくなるというパターンである。小縮尺では、むしろラスタタイルによる美しい地図表現のほうが卓越するのであって、ベクトルタイルがスイートであるのは大縮尺であるということを意識しよう。
但し、小縮尺でのインタラクティブな地図表現にはベクトルが非常に有効である。しかし、こちらはジオビジュアライゼーション的な世界であると一旦整理し、ウェブ地図からの延長でのベクトルタイルの利用は、まずは大縮尺だと認識してみよう。
地理院地図とvectiles-poiをミックスインする実験。
上記のような整理に立って、 Mapnik Vector Tiles の POI データを、地理院地図にミックスインする実験をしてみた。
ミックスインという言葉に込められた思いについては、#webgistec を参照。
実装
実装はここにある→ vectiles mix-in
【※12/13 06:00現在、ちょっとエラーが入ったものが上がっていて、これが見えると地図が見えません。修正版を上げていますが、github.io に反映されていないようです。すみません。しばらく時間を置いてからごらんください。】
地理院タイルの上に、OSMのPOIデータが一レイヤのベクトルタイルとしてmix-inされるというデモサイトである。
- 地理院タイルは、地理院地図|ヘルプ にある標準地図(在来版)
- OSMのPOIデータは、migurskiさんの Mapnik Vector Tiles
- POIデータのアイコンは、 Maki | A clean point of interest icon set from MapBox | MapBox
- ウェブ地図APIは、Leaflet - a JavaScript library for mobile-friendly maps
- glenrobertson/leaflet-tilelayer-geojson · GitHub を使用
- mlevans/leaflet-hash · GitHub を使用
ソースコードの解説をしたいところだが、あとで書くメソッドに委ねることにしよう。
大縮尺での効果を強調するため、小縮尺ではベクトルタイルをロードしないようにしている。migurski さんのベクトルタイルでは、小縮尺では数を絞ったPOIを提供されており、そのあたりの工夫をあえて見せないような実装を私がしているところがある。
IE8で動かないこと。CORSの重要性。
いきなり制限事項になるが、IE11では動くが、IE8では動かない。
普通の方法ではIE8はCORS(cross-origin resource sharing)をケアしてくれないので、migurskiさん側でCORS設定していただいているにも関わらず、IE8はクロスドメイン制約で転ぶ。
Can I use Cross-Origin Resource Sharing
ただ、既にIE6は終わりが見えており、IE8ではsupported somewhatということなので、もうCORSで悩むことは過去の話になってくるものと考えてしまおう。
MSDN Blogsに回避手段が載っている(XDomainRequest - Restrictions, Limitations and Workarounds - IEInternals - Site Home - MSDN Blogs )が、いまはここにリソースを注入しないことにする。
CORSについては時間が解決してくれることをもう確度をもって期待できるので、半年後の世界を考えるのであれば、CORSは解決した問題と見なすことにしよう。
ベクトルタイルのつくりかた
今回の実験では migurski さんの敷いたレールに乗れたので回避できたが、本来、様々なデータが重なりあう世界を求めるとすれば、ベクトルタイルの作り方をコモディティ化する必要がある。これについては私もまだ見えていない。多分、これも migurski さん率いところの TileStache が一つの候補となることだろう。
この節のタイトルは、 地図 - ちずのつくりかた / map school - Qiita [キータ] にちなんでいる。tmcw さんの原文を nyampire さんが翻訳したものである。これも是非読むべきものである。
タイルのメリット。
このデモで見えた(ベクトル)タイルのメリットは次の通りであろう。
- タイルがスケール依存であることがプラスに利いている。縮尺が大きくなればそれだけ多くの種類のPOIを表示するようになっている。
- タイルがスケールすることがよく示されている。タイルによらなければ、これだけ多くのPOIを「1レイヤ」として提示することはできないだろう。
プライベートデータのミックスインに向けて。Dropboxとか。
今回エントリの線にしたがって、パブリックデータのベクトルタイルによるミックスインの可能性が示されたあとは、タイルのWebとの親和性を活用して、普通のクラウド・ストレージをつかって、プライベートデータのミックスインがパブリックサービス上で、クラウド・ストレージ・アグノスティックに実現可能であるという線を示すべきだろう。
リアルタイム・ベクトルタイル
リアルタイム・ベクトルタイルについては、おそらくタイルURIに ?#{Time.now.to_i} でもつけてキャッシュを無効化した上で、JavaScript側でリフレッシュすることで実現できるのではないか。これも試してみる必要がある。
このエントリーでカバーしきれなかったネタ
- FOSS4G Advent Calendar で13日の金曜日担当であったからJSONネタにしたこと。
- migurskiさんはすごい人っぽいということ。
- このエントリみたいに、行き先ドリブンで説明を端折り気味に一息に説明してしまうことを 名付けて、桶狭間戦法。