JavaScriptによる位置情報の取得を簡単に解説(geolocation)



JavaScriptによる位置情報の取得を簡単に解説(geolocation)

Webブラウザのgeolocationオブジェクトを使うと、JavaScriptで現在位置(緯度/経度/高度と移動中なら速度/方向)を取得することができます。特にスマートフォン向けサイトでは、利用者の現在地を元に情報提供を行いたい場合もあるかと思いますので、位置情報を取得する流れを確認しておきましょう。

目次
  1. 位置情報を取得するgetCurrentPosition()
  2. 位置情報を取得し続けるwatchPosition()
  3. 住所の利用

geolocationは、Webブラウザ上のアプリケーション(JavaScript)で位置情報を利用するための仕組みです。navigatorが持つオブジェクトの形で実装され、現在ではパソコン用も含めほとんどのWebブラウザで利用できるようになっています。

位置情報を取得するgetCurrentPosition()

geolocationで位置情報を取得するには、getCurrentPosition()を呼び出して取得する方法と自動的に取得(位置情報を監視)し続ける方法があります。まずは、getCurrentPosition()で現在位置を取得してみましょう。

位置情報の取得には時間がかかることがあるので、getCurrentPosition()は「結果の通知を受ける関数」を渡す形で利用します。位置情報を受け取って処理する関数を作成し、その関数(関数オブジェクト)をgetCurrentPosition()の引数に渡すわけです。

getCurrentPosition()を呼び出すと、すぐに制御が返されます(次の文が実行される)。そして、位置情報の取得に成功すると、引数に渡した関数にPositionオブジェクトが渡されます。

Positionオブジェクトには、取得した位置情報と取得時間が格納されているので、その情報を使って処理を行うわけです。

実際にどのような情報が取得できるか、試してみましょう。以下のhtmlファイルを作成し、実行してみてください。

このhtmlでは、クリックされるとイベント関数test()を実行するボタンを配置し、そのtest()内でgetCurrentPosition()を呼び出すようにしてみました。

実際に位置情報の処理を行うのは、test2()です。このtest2()を、getCurrentPosition()の引数に渡しています。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function test() {
    navigator.geolocation.getCurrentPosition(test2);
}

function test2(position) {

    var geo_text = "緯度:" + position.coords.latitude + "\n";
    geo_text += "経度:" + position.coords.longitude + "\n";
    geo_text += "高度:" + position.coords.altitude + "\n";
    geo_text += "位置精度:" + position.coords.accuracy + "\n";
    geo_text += "高度精度:" + position.coords.altitudeAccuracy  + "\n";
    geo_text += "移動方向:" + position.coords.heading + "\n";
    geo_text += "速度:" + position.coords.speed + "\n";

    var date = new Date(position.timestamp);

    geo_text += "取得時刻:" + date.toLocaleString() + "\n";

    alert(geo_text);

}
</script>
</head>
<body>

<button onclick="test()">test</button>

</body>
</html>

Webブラウザにhtmlファイルを読み込んだら、testボタンをクリックしてみましょう。

位置情報の利用を許可するか尋ねるダイアログが表示されたら、許可してください。続いてgetCurrentPosition()の呼び出しが行われ、しばらくすると位置情報がダイアログで表示されたと思います。

image

test2()の引数に返されるPositionには、位置情報を格納したcoordsが格納されています。coordsからは、緯度・経度・高度といった現在の位置を表す座標の値と精度、また移動中であればその速度と方向を取得できるので、ダイアログに表示する文字列に列挙する形で一覧にしてみました。

また、文字列の最後には取得時刻(timestanp)も追加してあります。タイムスタンプは、ミリ秒単位の値ですが、この値からDateオブジェクトを作成することで日時を得ることができます。

coords.accuracyからは緯度/経度の精度を、position.coords.altitudeAccuracyからは高さの精度をメートル単位で取得できます。

GPSなど位置情報デバイスが搭載されていない端末でもネット接続を始め様々な情報から位置を推定してくれるので、デスクトップ端末でもある程度正確な位置情報を取得できる場合も多いようです。ただ、手元のデスクトップパソコンで実行してみると、accuracyの値が1000以上とかなり大きくなっていました。

位置情報を取得するデバイスを搭載しない端末のWebブラウザでは、accuracyの値が大きくなる(誤差が大きくなる)ことも想定しておく必要がありそうです。

実際に位置情報を利用する場面ではスマートフォンの存在が大きいと思いますので、できればWebサーバーに配置して、スマートフォンで移動しながら試してみましょう。私が持っているスマートフォンでは、accuracyの値も10程度とそう悪くはない感じでした。

getCurrentPosition()には、エラー時に呼び出される関数とタイムアウト(位置情報を取得するまで待機する最大時間)や有効期限(前回の位置情報取得からの経過時間が有効期限以下の場合、前回取得した位置情報を利用することができる)、高精度の取得を行うか否か、といったオプションを追加指定することができます。

エラー時に呼び出される関数にはエラー情報のオブジェクトが引数で渡され、messageプロパティにデバッグ用の文字列が入っています(codeプロパティからエラー原因の数値コードを取得することもできます)。

位置情報は、常に取得できるとは限りません。端末に位置情報を取得する機能が実装されていても、Webブラウザの確認画面でユーザーが位置情報の利用を拒否することもできます。実アプリの実装では、「位置情報を取得できない場合」への対応も忘れないようにしましょう。

第三引数には、位置情報取得のオプションをオブジェクトの形で渡します。オブジェクトには高精度の取得を行うかどうかを示すフラグenableHighAccuracy、タイムアウトをミリ秒単位で設定するtimeout、有効期限をミリ秒単位で設定するmaximumAgeの各プロパティを設定します。

test()のgetCurrentPosition()を以下のように変更したhtmlファイルを作成し、先ほどと比べてみましょう。

navigator.geolocation.getCurrentPosition(test2, function(e) { alert(e.message);}, {"enableHighAccuracy": true, "timeout": 20000, "maximumAge": 2000});

環境によっては、先ほどより精度が上がっているかもしれません。timeoutを短くすると、エラーになる(この例ではダイアログで指定時間内に位置情報を取得できずタイムアウトしたことの表示が行われる)可能性が高くなります。

maximumAgeの指定は、取得する位置情報がmaximumAgeで指定した時刻(呼び出し時間-maximumAge)以降のものであることを求める(位置情報キャッシュの有効期間)、といった意味になるようです。getCurrentPosition()で取得する位置情報の時刻が、getCurrentPosition()を呼び出す前のものになっていることもありますが、そうした現象をmaximumAgeの設定で容認/抑止できるわけですね。

位置情報を取得し続けるwatchPosition()

続いて、継続的に位置情報を監視し取得し続けるwatchPosition()を試してみましょう。

watchPosition()は、getCurrentPosition()と同じ引数で呼び出しますが、呼び出した後は位置情報の更新があった時など継続的に位置情報が更新され、引数に渡した関数に通知されます。

以下のHTMLファイルを作成し、試してみてください。

何度も位置情報を取得することになるので、取得した位置情報はページ内に表示する形にしてみました。また、取得回数の表示を入れてみたので、どの程度の頻度で呼び出されるかも見てみましょう。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
var num = 0;
var watch_id;

function test() {
    watch_id = navigator.geolocation.watchPosition(test2, function(e) { alert(e.message); }, {"enableHighAccuracy": true, "timeout": 20000, "maximumAge": 2000});
}

function clear() {
    navigator.geolocation.clearWatch(watch_id);
}

function test2(position) {

    var geo_text = "緯度:" + position.coords.latitude + "\n";
    geo_text += "経度:" + position.coords.longitude + "\n";
    geo_text += "高度:" + position.coords.altitude + "\n";
    geo_text += "位置精度:" + position.coords.accuracy + "\n";
    geo_text += "高度精度:" + position.coords.altitudeAccuracy  + "\n";
    geo_text += "移動方向:" + position.coords.heading + "\n";
    geo_text += "速度:" + position.coords.speed + "\n";

    var date = new Date(position.timestamp);

    geo_text += "取得時刻:" + date.toLocaleString() + "\n";
    geo_text += "取得回数:" + (++num) + "\n";

    document.getElementById('position_view').innerHTML = geo_text;

}
</script>
</head>
<body>

<button onclick="test()">test</button>
<button onclick="clear()">clear</button>

<pre id="position_view"></pre>

</body>
</html>

私のデスクトップPC(Firefox)で試すと、位置情報に変更がなくても5秒毎に位置情報の取得(関数呼び出し)が行われました。maximumAge(上の例では20秒)が最低間隔になる、というわけでもなさそうです。

image

スマートフォンで試すと、移動しなくても位置精度が小刻みに変わるせいか高頻度で位置情報の取得が行われました。「位置情報を取得したら更新処理を行う」といった実装にする場合は、実際にどの程度位置が変わったか、また前回からの経過時間などを見て更新を行うか判断した方がよさそうですね。

watchPosition()は、位置情報の取得を終了させるためのIDを返します。位置情報を連続的に取得する必要がなくなった時は、このIDをclearWatch()に渡して位置情報の取得を終えます。

しばらく位置情報が更新される状況を確認したら、「clear」ボタンでclearWatch()を呼び出し位置情報の取得を終了させてください。

住所の利用

geolocationで取得する位置情報は、緯度/経度という言わば「座標の値」ですので、具体的な所在地(住所)を得るには、緯度/経度から住所を求める仕組みが必要になります。

緯度、経度、住所、APIなどのキーワードで探すといくつかJavaScript(Webサービス)で利用できる住所取得サービスが見つかると思いますので、住所が必要になったら利用条件を確認して利用するとよいでしょう。

宍戸輝光
この記事を書いた人
宍戸輝光
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp