読者です 読者をやめる 読者になる 読者になる

minofoto and miscellaneous notes

個人的な備忘録ですが、たまに広く読んでもらいたい記事を書くこともあります。記事は随時修正したり追記したりすることがあります。

OpenLayers を使って iPhone 用の飲食店マップを作ってみた

OSM

はじめに

OpenStreetMap Advent Calendar に参加します。MapBox for iOS SDKマピオンの API が紹介されていますが、私はそういうものを知らなかったので、素人なりに OpenLayers を使って iPhone で表示できる飲食店マップを作ってみた試みをご紹介します。(できた地図だけを見たい方は下の方にスクロールして、画像をクリックしてください。)

何をしたかったか

会議などを開催するときに、参加者向けに近隣のランチマップ/飲み屋マップを作りたいことってありますよね。そういうときに、

  1. 地図のエリアを選択する
  2. エリア内に POI (食堂など)を入力
  3. スマートフォン (iOS/Android) 用の地図を埋め込んだサイト + 印刷用の地図(PDFなど) を同時に作成

なんて3ステップで地図が簡単に作れるしくみがあるといいなぁ、などと夢想しながらも、いきなりそんな気の利いたものは作れないので、まず隗より始めよ、で手作業で飲み屋マップを作ってみました。

やったこと

楽をするために、まずは人の真似をしようということで、参考にさせてもらったのが 激辛商店街マップ|京都☆激辛商店街 向日市。 それから さくらのレンタルサーバ。これらは OpenLayers を使っているらしいので、OpenLayers のサイトにあるたくさんの例も参考にしながら作りました。javascript のみで動作するので、比較的簡単なようです。

残念なことに、OpenLayers は部分的にしか iOS をサポートしていません。実際、激辛マップを iPhone (iOS7 の Safari) で見ると、肝心の POI をタップしても、店の情報を見ることができません。これは

    var pois = new OpenLayers.Layer.Text("My Points", {
	location:"text/sample.txt"
      });
    map.addLayer(pois);

の部分がうまく動作しないためのようです。いろいろ試して

  var pois = new OpenLayers.Layer.Vector("POIs", {
        strategies: [new OpenLayers.Strategy.BBOX({resFactor: 1.1})],
        protocol: new OpenLayers.Protocol.HTTP({
          url: "text/sample2.txt",
          format: new OpenLayers.Format.Text()
        })
      });
    map.addLayer(pois);

ならばうまくいくことがわかりました。

次に iPhone で表示するために

<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <!-- スマートフォン用 -->
  <meta name="viewport"
	content="width=320, height=480, initial-scale=1.0, minimum-scale=1.0, maximum-scale=2.0, user-scalable=yes" />

という設定と

    function check_smartphone() {
      var flg = (navigator.appVersion).indexOf("Mobile");
      if (flg>0){
        initial_zoom = 15;
        my_screen_width=320;
        <!-- location.href="index.html";  <!-- PC 用に書き換えるところ -->
      } else {
        initial_zoom = 16;
        my_screen_width = 700;
        location.href="index_PC.html";  <!-- PC 用に書き換えるところ -->
      }
      re_center();
    }

というコードを仕込んで、ブラウザの名前に mobile が入っている場合は mobile 用のページのまま、そうでない場合は画面サイズの大きい PC 用のページに飛ばすようにしました。また、地図が画面いっぱいに表示されると、地図のスクロールはできてもページ全体のスクロールができなくなる問題に対処するために、

    &nbsp; <div id="canvas" style="width:310px; height:400px"></div>    <!-- PC 用に書き換えるところ -->

として、地図の左端に余白を残すようにしました。画面の左端をスライドすることで上下にスクロールができます。

もうひとつ工夫したのが

    function re_center() {
      //map.zoomToMaxExtent();
      //map.zoomTo(initial_zoom);
      var centLonLat = new OpenLayers.LonLat(139.68336129378946, 35.707380793896974)
                       .transform(
                          new OpenLayers.Projection("EPSG:4326"), 
                          new OpenLayers.Projection("EPSG:900913")
                       );
      map.setCenter(centLonLat, initial_zoom);
    }

    <form>
      <input type="button" value="東中野駅付近に戻す" onclick="re_center()" /> 
    </form>

で、地図を初期位置に戻すボタンを付けてみたことです。地図を埋め込んだサイトで、私はよく地図をスクロールしすぎて迷子になってしまいますので(笑)。(更に地図スクロール範囲の制限もかけていますが。)

ひとまず出来たもの

こうして作ってみたのが下の画像のような 東中野〜中野ひとり飲みマップ です。とあるローカルコミュニティ向けの内輪の飲み屋紹介マップですが、中身は気にしないでください(笑)。
基本的には index.html, index_PC.html と text/sample2.txt のみで動作します。もとの example が Creative Commons License なので、このソースコードも同様に利用していただいて構いません。

どのくらい大変だったか、など

真似できる例を探すのに数日、コードを書くのに隙間時間で 1-2 日ぐらいだったかな。むしろベースマップを充実させるのに時間がかかっています。Bing トレース以外にも、表示する店の位置を再度確かめに行ったりしています。こういう利用が増えると、多くの人が OSM に POI を追加するモチベーションになるのではないでしょうか。

もしも OSM の POI が充実している場所では、POI を検索して開店時間などの条件に合う店だけピックアップしてマークできたりすると使いでがあるでしょうね。

まだ足りないこと

画面解像度の調整

現在は 320x480 pixel にしていますが、iPhone の機種を見分けて、解像度を上げられるといいなぁ。

Android 対応

Android 端末は持っていないので、どうなるのか、まだ試していません。誰か教えてください。

現在位置を表示する機能

スマートフォンGPS を元に現在位置が表示できると、土地勘のない会議参加者用のランチマップとしてはかなり使い勝手が良くなるはずですね。

POI 入力サポート機能

http://higashinakano.ikidane.com/admin.html に POI 入力サポート用のコードを置いていますが、まだまだ未完成です。