2011年3月8日火曜日

HTML 5、ジオロケーション API、Web サービスを組み合わせ、モバイル・マッシュアップを作成する

前提条件

よく使われる頭字語

  • API: Application Programming Interface
  • CSS: Cascading StyleSheet
  • GPS: Global Positioning System
  • HTML: HyperText Markup Language
  • JSONP: JSON with Padding
  • SDK: Software Developer Kit
  • UI: User Interface
  • W3C: World Wide Web Consortium

この記事では、最新の Web 技術を使用する Web アプリケーションを作成します。ここで紹介するコードの大部分は単なる HTML と JavaScript、そして CSS であり、すべての Web 開発者にとってコアとなる技術です。この記事を読み進めていく上で必要なもののうち、最も重要なものは、テストのベースとなるブラウザーです。この記事では、Mozilla Firefox 3.5 またはそれ以上を使用することを強く推奨します。このブラウザーはデスクトップ・ブラウザーとしてジオロケーションをサポートしているからです。もちろん、モバイル・ブラウザーでもテストする必要があり、そのために iPhone と Android の最新 SDK が必要です。この記事では iPhone SDK 3.1.3 と Android SDK 2.1 を使いました。これらへのリンクは「参考文献」セクションを参照してください。

基本編: 位置を取得する

ジオロケーション自体、少し目新しいものです。ジオロケーションを利用すると、ユーザーのいる場所を特定することができますが、単に場所を認識してユーザーに知らせるだけではあまり有用ではありません。果たして自分のいる場所の緯度と経度を正確に知りたいと思う人がいるでしょうか。そこで、位置情報を利用する他のデータやサービスとジオロケーション機能を組み合わせ、人の興味を引くようなものを生成する必要があります。そうしたサービスはほとんどすべて、入力の一部としてユーザーのいる場所の緯度と経度を要求します。多くの場合、必要なものはそれだけです。そこで、緯度と経度を取得する方法を調べてみましょう。リスト 1は、そのための標準的な JavaScript API です。


リスト 1. ユーザーを発見する: getCurrentPosition
navigator.geolocation.getCurrentPosition(successCallback,  errorCallback, options); 

これはジオロケーションに必須の API です。大部分のアプリケーションでは、必要なものはこれだけです。ジオロケーション・オブジェクトは標準的なナビゲーター・オブジェクトの一部です。ジオロケーション・オブジェクトにはいくつかのメソッドがありますが、最もよく使われるのは getCurrentPosition です。ユーザーのいる場所にアクセスする操作は、時間がかかる処理 (宇宙の衛星にアクセスする必要があるかもしれません) であるのと同時に、ユーザーの同意が必要です。そのため、この操作は非同期で行います。この操作のパラメーターはコールバック関数であり、1 つは成功用、1 つは失敗用です。

成功関数には Position 型の 1 つのパラメーターが渡されます。このオブジェクトには 2 つのプロパティーがあり、1 つはタイムスタンプのプロパティー、もう 1 つは Coordinates 型の coords というプロパティーです。Coordinates オブジェクトには以下のようなプロパティーがあります。

  • latitude
  • longitude
  • altitude
  • accuracy
  • altitudeAccuracy
  • heading
  • speed

latitude (緯度)、longitude (経度)、accuracy (精度) を除き、これらのプロパティーのすべてがすべての機器で利用できるわけではありません。ジオロケーション API がサポートされており、位置を解決できる機器であれば、その機器では latitude、longitude、accuracy を利用できると思って間違いありません。

エラー用のコールバック関数には PositionError 型の 1 つのパラメーターが渡されます。PositionError のインスタンスには code と message という 2 つのプロパティーがあります。message は機器特有であり、デバッグに便利です。message のコードには下記の 3 つのうちの 1 つの値を持つ必要があります。

  • PERMISSION_DENIED (1)
  • POSITION_UNAVAILABLE (2)
  • TIMEOUT (3)

アプリケーションはこのコードを利用して、理解しやすいエラー・メッセージをユーザーに表示する必要があります。

注意点として、W3C 仕様では 3 番目のパラメーターとしてオプションを指定することもできるようになっています。そうしたオプションには、ユーザーの位置の判断に要する時間が一定値を超えた場合にタイムアウトにするための値などが含まれています。しかしこの機能は iPhone などの機器ではまだサポートされていないため、使わないようにすることをお勧めします。これでジオロケーション API の詳細を理解できたので、その使い方を簡単な例で調べてみましょう。

Twitter と統合する

最近では、マッシュアップの Hello World でも何らかの形で Twitter を使います。最初の例として、Twitter の検索 API を使います。この API を利用すると、ある位置から指定半径内で投稿されたツイートを検索することができます。リスト 2 は近くで投稿されたツイートを検索する例を示しています。


リスト 2. 近くで投稿されたツイートを検索する
<!DOCTYPE html> <html> <head> <meta name = "viewport" content = "width = device-width"/> <title>Local Twitter Search</title> <script type="text/javascript">     function startSearch(){         var gps = navigator.geolocation;         if (gps){             gps.getCurrentPosition(searchTwitter,                     function(error){                 alert("Got an error, code: " + error.code + " message: "  + error.message);              });         } else {             searchTwitter();         }     }     function searchTwitter(position){         var query = "http://search.twitter.com/search.json?callback=showResults&q=";         query += $("kwBox").value;         if (position){             var lat = position.coords.latitude;             var long = position.coords.longitude;             query += "&geocode=" + escape(lat + "," + long + ",50mi");         }         var script = document.createElement("script");         script.src = query;         document.getElementsByTagName("head")[0].appendChild(script);     } </script> </head> <body>     <div id="main">         <label for="kwBox">Search Twitter:</label>         <input type="text" id="kwBox"/>         <input type="button" value="Go!" onclick="startSearch()"/>     </div>     <div id="results">     </div> </body> </html> 

ユーザーはテキスト・ボックスに検索用語を入力します。ボタンをクリックすると startSearch 関数が呼び出されます。ここでジオロケーション API を使用します。まず、ジオロケーション API を利用できるかどうかをチェックします。利用できる場合には、getCurrentPosition API を呼び出します。成功用のコールバック関数には searchTwitter 関数を使います。エラー用のコールバック関数には、単純なクロージャーを渡し、このクロージャーによって単純にエラー情報を表示します。

searchTwitter 関数は、ブラウザーが位置を特定できると呼び出されます。ここで、searchTwitter 関数に渡された位置情報を使って geocode パラメーターを Twitter の検索クエリーに追加します。リスト 2 の例では、特定された位置から 50 マイル以内の場所で投稿されたツイートを検索します。Twitter を呼び出すためには動的なスクリプト・タグを使います。これはよく JSONP と呼ばれる手法であり、Twitter の検索 API では JSONP がサポートされています。JSONP を使うと Twitter の検索機能をブラウザーから直接呼び出すことができ、まったくサーバーが必要ありません。これを示しているのがクエリーの callback パラメーターです。このパラメーターが showResults に設定されていることに注意してください。showResults は呼び出される関数の名前です。showResults は UI の作成に使われているだけなのでリスト 2 には現れていませんが、この記事のソース・コードの一部として含まれています (「ダウンロード」を参照)。図 1 リスト 2 のコードを iPhone で実行した場合のスクリーン・キャプチャーです。


図 1. iPhone から Twitter を検索する
現在いる地点から 50マイル以内の場所で投稿されたツイートを iPhone で検索した結果のスクリーン・キャプチャー 

位置を認識する他の多くのアプリケーションと同様、このアプリケーションでは 1 度だけ位置を取得すれば十分です。しかし他のアプリケーションではユーザーの移動に合わせてユーザーを追跡する必要があります。そうしたアプリケーションには、もっと高度な他のジオロケーション API を使う必要があります。

上級編: 追跡

アプリケーションでは、ユーザーの現在位置を必要とするだけではなく、ユーザーが移動するたびに現在位置を更新しなければならない場合もあります。そのために watchPosition という API があります。watchPosition  getCurrentPosition と非常に似ており、同じ引数を取ります。1 つ大きな違いとして、watchPosition は ID を返します。この ID を、最終的なジオロケーション API である clearWatch と組み合わせて使うことができます。clearWatch 関数は watchPosition から取得した ID を引数に取ります。つまりwatchPosition を呼び出すと、ブラウザーは渡された成功用のコールバック関数に対して更新情報を送信し続け、それをclearWatch が呼び出されるまで続けます。ユーザーの位置を継続的に取得していると、モバイル機器のバッテリーが極めて早く消耗してしまうので、この API は十分注意して使用する必要があります。今度は例を見てみましょう。

Google マップと統合する

この例では Google Maps API を利用します。これらの Google Maps API はモバイル機器用に最適化されており、特に iPhone と Android プラットフォームを意識して最適化されています。そのため Google Maps API はモバイル Web 開発者にとって非常に魅力的であり、位置を認識するアプリケーションを作成する場合には、なおさらのことです。下記のサンプル・アプリケーションでは、単純にユーザーの位置を地図上に表示し、ユーザーの位置が変更されるたびに地図を更新します。リスト 3 はこの地図のためのコードを示しています。


リスト 3. ジオロケーションを使った地図アプリケーション
<html>  <head>  <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>  <title>I'm tracking you!</title>  <script type="text/javascript" src="http://maps.google.com/maps/api/js?      sensor=true"></script>  <script type="text/javascript">     var trackerId = 0;     var geocoder;     var theUser = {};     var map = {};     function initialize() {         geocoder = new google.maps.Geocoder();         if (navigator.geolocation){             var gps = navigator.geolocation;             gps.getCurrentPosition(function(pos){                 var latLng = new google.maps.LatLng(pos.coords. latitude,pos.coords.longitude);                 var opts = {zoom:12, center:latLng, mapTypeId:  google.maps.MapTypeId.ROADMAP};                 map = new google.maps.Map($("map_canvas"), opts);                 theUser = new google.maps.Marker({                     position: latLng,                     map: map,                     title: "You!"                 });                 showLocation(pos);             });             trackerId = gps.watchPosition(function(pos){                 var latLng = new google.maps.LatLng(pos.coords.latitude,pos. coords.longitude);                 map.setCenter(latLng);                 theUser.setPosition(latLng);                 showLocation(pos);             });         }   } </script>  </head>  <body style="margin:0px; padding:0px;" onload="initialize()">      <div id="superbar">               <span class="msg">Current location:                <span id="location"></span>           </span>           <input type="button" value="Stop tracking me!"  onclick="stopTracking()"/>       </div>   <div id="map_canvas" style="width:100%; height:90%; float:left;  border: 1px solid black;">   </div>  </body>  </html>  

この文書の本体がロードされると initialize 関数が呼び出されます。この関数はブラウザーでジオロケーションがサポートされているかどうかをチェックします。サポートされている場合には、initialize 関数は先ほどのリスト 2 の例と同じようにgetCurrentPosition を呼び出します。位置を取得すると、initialize 関数は Google Maps API を使って地図を作成します。緯度と経度をどのように使って google.maps.LatLng のインスタンスを作成しているかに注意してください。このオブジェクトを使って地図の中心を合わせます。次に、ユーザーの現在位置を示すマーカーを地図上に作成します。このマーカーにも、ジオロケーション API から取得した緯度と経度を使います。

地図を作成し、その地図上にマーカーを表示したら、ユーザーの追跡を始めます。そのためには watchPosition から返される ID を取り込みます。新しい位置情報を受信するたびに、その新しい位置に地図の中心を合わせ、そこにマーカーを移動します。リスト 4は注目に値する他の 2 つの関数を示しています。


リスト 4. ジオコーディング関数と追跡終了関数
function showLocation(pos){     var latLng = new google.maps.LatLng(pos.coords.latitude,pos.coords.longitude);     if (geocoder) {         geocoder.geocode({'latLng': latLng}, function(results, status) {           if (status == google.maps.GeocoderStatus.OK) {             if (results[1]) {                 $("location").innerHTML = results[1].formatted_address;             }            }          });       }         } function stopTracking(){     if (trackerId){         navigator.geolocation.clearWatch(trackerId);     } } 

リスト 3 では、最初に地図を描画した時とユーザーの位置情報の更新を受信した時に showLocation 関数が呼び出されます。リスト 4 には showLocation 関数を示してあります。showLocation 関数は (リスト 3  initialize 関数で最初に作成される)google.maps.Geocoder のインスタンスを使用します。この API を使用するとジオコーディングを実行することができます。つまり住所を引数として取り、その住所を地図座標 (緯度と経度) に変換することができます。また逆ジオコーディング (地図座標を引数として取り、実際の住所を返す) を行うこともできます。この場合では、ジオロケーション API によって生成された座標を Google Maps API の引数に使用して、その座標を逆ジオコーディングします。すると、その結果が画面に表示されます。

リスト 4 の最後の関数が stopTracking 関数です。この関数は、リスト 3 の HTML で作成されたボタンをユーザーがクリックすると呼び出されます。ここでは watchPosition 関数を最初に呼び出した時に取得した trackerId を使います。この trackerId を単純にclearWatch 関数に渡すと、ブラウザーまたは機器はユーザーの位置情報の取得を停止し、JavaScript の呼び出しも停止します。図 2 は、この追跡アプリケーションを使用している状態でのスクリーン・キャプチャーです。


図 2. 追跡アプリケーション
サンプルの追跡アプリケーションで作成された地図と位置マーカーを表示した画面のスクリーン・キャプチャー 

もちろん、この追跡アプリケーションを実際にテストするためには、位置を変更する必要があります。そのためのツールとして Google App Engine が便利です。Google App Engine を使うと、誰もが利用できる公開された場所に Web アプリケーションを簡単にアップロードすることができるからです。そうすれば、皆さんのモバイル機器からネットワークに接続できる場所であればどこででも、そのアプリケーションを直接テストすることができます。そのテストをする際には、公共交通機関に乗り、あるいは誰かが運転する車に乗せてもらい、皆さんが移動するのに合わせて Web アプリケーションが応答する様子を確認できるはずです。

まとめ

この記事では、モバイル Web アプリケーションでジオロケーション API を使う方法を説明しました。GPS というと非常に魅力的ではあっても複雑に思えます。しかし、この記事で説明したように、ジオロケーションの W3C 標準には非常に単純な API が用意されています。この API を使用すれば、ユーザーの位置を簡単に取得することができ、またその位置を時間と共に追跡することができます。それができると、位置をサポートするさまざまな Web アプリケーションに位置座標を渡すことができ、または位置を認識する独自のサービスを皆さん自身が作成することもできます。HTML 5 とモバイル Web アプリケーションに関するこの連載の第 2 回目では、ローカル・ストレージを利用してモバイル Web アプリケーションのパフォーマンスを改善する方法について説明します。



参考文献

学ぶために

0 件のコメント:

コメントを投稿