STEP 1: Shapefile を GeoJSON ファイルに変換する
GDAL/OGR は手元の OS X では Java6 依存性があるように表示されてしまうので、ここは迷うことなく GeoRuby を使って Ruby で処理する。ストリームを意識しやすいので良い。次の togeojson.rb を使って
$ ruby togeojson.rb | gzip -9 > some.geojson.gz
等とする。tippecanoe はストリームが切れていても終末の処理を適当にしてくれるので、ファイルの完成を待たずに次のステップに進んでも良い。
スクリプトは次のとおり。属性の文字コードを変換すべきかどうかは、Shapefile と GeoRuby の細かな特性に依存すると思うので、手元のデータ・手元の環境に合わせて調整するのがよい。
require 'rubygems'
require 'find'
require 'json'
require 'georuby'
require 'geo_ruby/shp'
#require 'geo_ruby/geojson'
def process(shp_path)
$stderr.print "processing #{shp_path}.\n"
geojson_path = shp_path.sub(/shp$/, 'geojson')
s = []
GeoRuby::Shp4r::ShpFile.open(shp_path) {|shp|
shp.each {|r|
r.data.attributes.each{|k,v|
if v.class == String
# 属性の文字コードを Shift_JIS から UTF-8 に変換する
r.data.attributes[k] = v.encode('UTF-8', 'CP932')
end
}
if $first
$first = false
else
print ",\n"
end
r.geometry.with_m = false
r.geometry.with_z = false
print JSON.dump({
"type" => "Feature",
"geometry" => r.geometry,
"properties" => r.data.attributes
})
}
}
end
$first = true
print <<-EOS
{"type": "FeatureCollection", "features": [
EOS
count = 0
Find.find('.') {|path|
next unless /shp$/.match path
next unless /RdCL/.match path # "RdCL" がファイル名に入っている場合のみ処理
next if /(NNFPt|NRPt|CSPt|PFPt|DEM)/.match path # 属性・分量の問題で後回し
count += 1
process(path)
#break if count == 100
}
print <<-EOS
]}
EOS
Tippecanoe で GeoJSON をベクトルタイルに変換する
https://github.com/mapbox/tippecanoe
にある tippecanoe をインストールする。
$ brew install tippecanoe
手元にあるのは中縮尺・大縮尺のデータなので、とりあえず閲覧するために z=15〜18 でベクトルタイルを作成したりしている。(これは手元にあるデータによって変わってくる。)
$ gzcat some.geojson.gz | tippecanoe -z 18 -Z 15 -t . some.mbtiles
ここで、 -t . とするのは作業ディレクトリをカレントディレクトリにするため。たいていの Shapefile ベースのデータでは問題なく処理してくれるのが tessera のありがたいところだけれども、処理の特に後段のところで、ややテンポラリを多く使う場合がある。私は残り容量の少ない MacBook Air (11-inch, mid 2011) で処理をしているので、データが置かれているカレントディレクトリ(安い USB HDD)にテンポラリを置くことにしている。それでも、劇的に速度が低下するという感じはない。
tessera でベクトルタイルを閲覧してみる
ここから先は node.js による処理になる。一部、node のバージョンに依存するライブラリもあるので、nodebrew で node / npm を導入したほうが良いかもしれない。
ソフトウェア導入についてこれから説明するが、記憶によるところなので、依存性処理によって不要になるコマンドが入っているかもしれない。それぞれのモジュールについての覚書を兼ねている。
$ npm install mbtiles tilelive tilelive-mapnik
↑このあたりは必要だと思うが、後段の tessera 導入で自動的にインストールされるかもしれない。
$ npm install tessera
サーバとして動いてくれる tessera を導入する。
$ npm install tilelive-vector tilelive-xray
今回、ベクトルタイルのデータを閲覧するので、上記のモジュールが必要になる。特に、tilelive-xray が重要。スタイルをつけていないデータを上手く表示してくれるための機能らしく、tilelive-xray を導入していないと、tessera がエラーメッセージを出して終了してしまう。
また、導入すべき node モジュールが足りないと、tessera でエラーが出る。次のようにしてモジュールを一覧することにより、推理して頂くのがよい。
$ npm find tilelive
実際にサーバを動かすには、次のようにする
$ tessera mbtiles://./some.mbtiles
これで、localhost にサーバが立ち上がるのでブラウザで Leaflet ベースのウェブ地図として最低限閲覧することができる。
ただし、この方法で tessera から送信されるのは、tessera が(たぶんオンデマンドでレンダリングした)PNGタイルである。まさに、Mapbox Studio 的なアプローチで、ぎりぎりサーバサイドレンダリングを実施している。クライアントサイドレンダリングを試してみる方法は、後ほど記載することにしたい。