零度のウェブマッピング

PostGIS から Ruby を介して SVG に直結するタイプのウェブマッピングのコンセプト実証コードです。

コンセプト

HTML5 の時代には、クライアントサイド(ブラウザ)のグラフィック能力が格段に向上しています。また、SVG 的にグラフィック要素を宣言していくタイプのグラフィックでは、グラフィックに対してイベントハンドラを自在に定義できるため、デスクトップアプリではむしろ実現できなかった、柔軟かつ豊かなユーザインタラクションが可能となってきます。
一方で、これまで作られてきた "Ajax 的" マップツールキットは、必ずしも HTML5 時代の新機能を活用しておらず、むしろ HTML5 時代の新機能を API の下に隠蔽する傾向があります。
そこで、サーバ側プログラミングと密接に連携することを前提に、SOAP/ASP 的な発想の地図画像サービス(すなわち、Web 1.0 的なサービス)を使用せず、また、地図サービス汎用に開発された "Ajax 的" API (すなわち、Web 2.0 的な API)を使用しない、しかし、HTML5 時代の新機能をネイティブで使用するウェブマッピングを提案したいと思います。このコンセプトに従ったウェブマッピングの仮称を「零度のウェブマッピング」とします。
上記の書き方で Web 1.0 的と言った発想は、"Map over the Web"、Web 2.0 的と言った発想は "Map on the Web" かもしれませんが、零度のウェブマッピングにおいては、"Map is a Web" と言えるかもしれません。

コンセプト実証コードの内容

コンセプトが大げさな割には、コンセプト実証コードは大したことをしていません。先ほどのエントリで取り込んだ OpenStreetMap の道路データを、PostGIS の ST_AsSVG を用いて SVG Path に変換し、RaphaelAn Intro to Raphaël - Raphaël)によってブラウザに表示させているだけです。このプログラムは、Sinatra (Sinatra) を用いた Web サーバとして動作します。

実際のコード

require 'rubygems'
require 'pr_geohash'
require 'sequel'
require 'sinatra/base'

class App < Sinatra::Base
  DB = Sequel::connect('postgres://fitter:happier@localhost/more_productive')
  W = 800
  set :static, true
  set :public, 'public'

  get '/' do
    redirect '/xn77n'
  end

  get '/:geohash' do
    content_type 'text/html'
    geohash = params[:geohash]
    extent = GeoHash.decode(geohash)
    (lat0, lng0, lat1, lng1) = extent.flatten
    h = W / Math::cos(lat0 / 360.0 * 2 * Math::PI)
    h = h / 2 if geohash.size % 2 == 0
    a = W / (lng1 - lng0)
    b = 0
    d = 0
    e = h / (lat1 - lat0)
    x_off = - (W * lng0) / (lng1 - lng0)
    y_off = - (h * lat1) / (lat1 - lat0)
    bbox = "ST_GeomFromText('POLYGON ((#{lng0} #{lat0}, #{lng1} #{lat0}, #{lng1} #{lat1}, #{lng0} #{lat1}, #{lng0} #{lat0}))', 4326)"
    @dataset = DB["SELECT ST_AsSVG(ST_Affine(ST_Intersection(the_geom, #{bbox}), #{a}, #{b}, #{d}, #{e}, #{x_off}, #{y_off}), 0, 0), type, name FROM japan_highway WHERE ST_Intersects(the_geom, #{bbox});"]
    instr = []
    @dataset.each {|r|
      color = case r[:type]
              when 'motorway'
                'red'
              when 'footway'
                'green'
              when 'secondary'
                'gray'
              else
                'navy'
              end
      instr << "        r.path('#{r[:st_assvg]}').attr('stroke', '#{color}');\n"
    }
    haml <<-EOS
!!!XML
%html
  %head 
    %title= params[:geohash]
    %script{:src => 'raphael.js'}
  %body
    :javascript
      window.onload = function() {
        var r = Raphael(0, 0, #{W}, #{h});
#{instr}
      }
    EOS
  end  
end

App.run! :port => 2010

コンセプト実証が目的のため、投影もごく簡略に、またスタイル設定もごく単純に行っています。

スクリーンショット


Map data (c) OpenStreetMap (and) contributors, CC-BY-SA

特徴

  • データは PostGIS データベースから HTTP のプレゼンテーションに直結です(キャッシュを除く中間層をできるだけ排除)。
  • HTML ファイルのほとんどは JavaScript で書かれています(Raphael のおかげで、SVG を使いつつも XML を回避、おまけに Internet Explorer にも対応)。
  • 座標変換系の処理は、サーバ側が担当しています。ブラウザはユーザインタフェースにリソースを割かれるはずですので、ジオ系の座標変換は、サーバ側が担当することを基本と考えています(データの同一性は、データIDで確保することになる)。

これから

零度のウェブマッピングは、このようなコンセプト実証コードの先から真価を発揮するはずです。例えば、上下左右の矢印キーに、隣の geohash に飛ばす機能を付与したり、道路をクリックするとそのタグを編集できたり、他のサービス(特にチェックイン系サービス)とつなげたり、簡単にまた自在に行えるのではないでしょうか。