GPSアプリ作成上の注意点について
こんにちは、サンプルアプリ開発者の山田健一です。
GPSアプリはMonacaと相性がよいものの1つです。
なぜならケーブル要らずのデバッグができるからです。
「GPSアプリをデバッガーで起動して、外を歩きながら取得したGPSデータを、PCに表示させたログ で確認する」という使い方が可能です。
GPS機能を利用するにはいくつかの注意点があります。
場所によっては位置を測定できないことがある
位置が測定できたとしても誤差が大きいことがある
以上の点に注意してください。
具体的には、
geolocation.getCurrentPosition メソッドは使用せず、geolocation.watchPosition メソッドを使用するようにしてください。
watchPosition メソッドを使用すると位置情報が変わるたびに指定した callback 関数が呼ばれます。
具体的なコード例は次のようになります。
watchId = navigator.geolocation.watchPosition(onSuccessGps, onErrorGps,
{ maximumAge: 3000, timeout: 30000, enableHighAccuracy: true });
位置情報を得た場合、第1パラメーターに指定した onSuccessGps 関数に制御が移ります。
同様に、位置情報取得に失敗した場合は第2パラメーターに指定した onErrorGps 関数に制御が渡ります。
第3パラメーターについて説明します。
maximumAge はキャッシュされた位置情報の永続時間をミリ秒単位で指定します。例では3,000ミリ秒(=3秒)としています。
timeout は位置情報を返すまでの最大待機時間をミリ秒単位で指定します。例では30,000ミリ秒(=30秒)としています。30秒の間に位置情報を取得できない場合、第2パラメーターに指定した onErrorGps 関数に制御が渡ります。
enableHighAccuracy に true を指定することで厳密な計測になります。端末がGPS機能をサポートしている場合、GPS機能を使用します。端末がGPS機能をサポートしていなくても弊害はありませんので、通常は true を指定します。
成功時のコールバック関数 はパラメーターを1つ持っています。このパラメーターに位置情報が入っています。
function onSuccessGps(p)
と指定した場合、緯度、経度、誤差は次のように求められます。
緯度:p.coords.latitude
経度:p.coords.longitude
誤差:p.coords.accuracy
緯度、経度の単位は度です。これは通常私たちが用いている単位です。
誤差の単位は m(メートル)です。
geolocation.watchPosition メソッドは geolocation.clearWatch メソッドが呼ばれるまで位置情報の監視を続けます。
位置情報監視を停めるには次のコードが必要です。
navigator.geolocation.clearWatch(watchId);
watchId という変数で位置情報監視のイベントを識別しています。
この位置情報は、じっとしていても測定誤差が変われば、callback関数が呼ばれます。測定誤差が変わる場合は多くの場合、位置情報も変化しています。
実際にどれほどの誤差が発生するのかを予め把握しておくことは、GPSアプリの設計方針立案の重要事項となります。
すなわち、
どの程度の誤差まで許容するのか
timeoutはどの程度の設定が適切か
などを決定する必要があります。
筆者が作成したGPSを利用した歩行管理アプリ
https://play.google.com/store/apps/details?id=info.yamada_ken1.letswalk
では、timeoutは30,000ミリ秒(=30秒)としています。
また、許容誤差を25mとしています。この許容誤差はアプリ内部で、測定結果をふるい落とす基準として使っています。25mに設定したのは Galaxy Sで測定した誤差が、24mまでの測定データでおよその歩行記録が把握できると判断したためです。他の端末のことを考えて、25mとしました。歩行スピードを時速6kmで計算すると100m進むのに1分ですので、25mの誤差は15秒分に相当します。
この測定誤差を容易に体験できるように、誤差が変化する様子をグラフに表すアプリを作成してみました。
コードの主要部分は次のようになります。
//GPS精度確認
function checkGps() {
//開始時刻
timStart = new Date();
//状況初期化
_changeButton(1);
//タイマー起動(45秒後にGPS停止)
timerID = setTimeout( function () { stopGps(); }, 45000);
// グラフデータ用配列クリア
d1 = [];
//GPS起動
watchId = navigator.geolocation.watchPosition(onSuccessGps, onErrorGps,
{ maximumAge: 3000, timeout: 30000, enableHighAccuracy: true });
}
//GPS成功
function onSuccessGps(p) {
var timNow = new Date();
//経過時間を秒換算
var time = (timNow.getTime() - timStart.getTime()) / 1000;
//誤差取得
var acc = p.coords.accuracy;
//測定データをコンソールに表示
console.log("緯度:" + p.coords.latitude +
",経度:" + p.coords.longitude +
",誤差:" + acc);
//グラフデータ追加
d1.push([time, acc]);
var optData = [];
var optData1 = {
label: "誤差",
data: d1,
lines: { show: true },
points: { show: true }
};
optData.push(optData1);
//グラフ描画
$.plot($("#chart"), optData,
{
xaxis: optXaxis,
yaxis: optYaxis,
grid: optGrid
}
);
}
//GPSエラー
function onErrorGps(error) {
//記録終了
navigator.geolocation.clearWatch(watchId);
//タイマー終了
clearTimeout(timerID);
//状況変更
_changeButton(3);
}
//タイムアウト処理(確認終了)
function stopGps() {
//記録終了
navigator.geolocation.clearWatch(watchId);
//状況変更
_changeButton(2);
//グラフデータあるか?
if (d1.length == 0) {
$('#chart').html("GPSデータ取得 0 件");
}
}
前段で解説したように、geolocation.watchPosition メソッドは位置情報が変わるたびに結果を返してきますので、ある程度測定したら停止する必要があります。
そのために
[code]timerID = setTimeout( function () { stopGps(); }, 45000);[/code]
というコードで45秒後にイベントを発火させるようにしています。
タイマーイベントでは
[code]navigator.geolocation.clearWatch(watchId);[/code]
というコードで、位置情報監視を停めています。
また、位置情報取得エラーが発生した場合、以後の測定はあてになりませんので、同様に位置情報監視を停めています。
このサンプルをデモした結果は次のようになります。
このときPCのデバッグログには次のように表示されています。
このように示された緯度、経度の場所を地図で示してくれるサイトを紹介します。
デバッグログに示された緯度、経度を地図上で確認し、自分が測定した位置とどの程度異なっているかを確認してください。
ライブラリーとして、iUI,jQuery,flotを使用していますが、上記のソースには含んでいませんので、別途ダウンロードをお願いします。
ソースコード、apkファイルは次のリンクからダウンロードできます。