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

monolog

スタック・オーバーフロー・エンジニアのなかにしゆうが思うことを書いていきます。

Geolocation APIを用いた高精度な位置情報取得

geolocationでの位置情報取得 - teguのTech Blogで紹介されていたものと考え方は同じです。まあ要は、

  1. navigator.geolocation.getCurrentPosition を使うと精度が低くても successCallback が呼ばれる
  2. navigator.geolocation.watchPosition を使えばええやん
  3. 一定以上の精度にならないときは先に進めず止まってしまう
  4. タイムアウトするようにしよう

というお話です。タイムアウトの信頼性を向上させ、エラー処理もそこそこやってる気がする関数を作ってしまったので紹介します。

// AccuratePosition
// 時間の許す限り正確な位置情報を取得する
// http://pear.jp/

function getAccuratePosition(successCallback, errorCallback, option){
    // 位置情報に対応していなければ終了
    if(!navigator.geolocation){
        var error     = new Object();
        error.code    = 9;
        error.message = 'Geolocation APIが利用できません。';
        errorCallback(error);
        return;
    }

    // 変数の初期化
    var watch_id = undefined;
    var timer_id = undefined;
    var position = undefined;
    var limit    = option && option.limit   ? option.limit   : 100;
    var timeout  = option && option.timeout ? option.timeout : 0;

    // タイムアウトをセット
    if(timeout > 0){
        timer_id = setTimeout(
            function(){
                // 位置情報の取得を中止する
                if(watch_id){
                    navigator.geolocation.clearWatch(watch_id);
                    watch_id = undefined;
                }

                // 位置情報が取得できていればsuccessCallbackに送る
                if(position){
                    successCallback(position);
                }
                else{
                    var error     = new Object();
                    error.code    = 9;
                    error.message = '位置情報の取得でタイムアウトしました。';
                    errorCallback(error);
                    return;
                }
            }, 
            timeout
        );
    }

    // 取得を実行
    watch_id = navigator.geolocation.watchPosition(
        function(p){
            // 取得のたびに更新する
            position = p;

            // 求める精度に達すればsuccessCallbackに送る
            if(position.coords.accuracy < limit){
                // タイムアウト監視を止める
                if(timer_id){
                    clearTimeout(timer_id);
                    timer_id = undefined;
                }
                navigator.geolocation.clearWatch(watch_id);
                successCallback(position);
            }
        }, 
        function(e){
            errorCallback(e);
        }, 
        {enableHighAccuracy:true, maximumAge:0}
    );
}

使えるオプションは、

  • limit: 許される誤差(m)。省略時は100。
  • timeout: 待てる時間(ms)。省略時は無限。

に限ります。動作としては「精度がlimitより良くなるまで取得し続けるけれど、timeout以上かかるようならやめてそれなりの精度の位置情報を取得する」です。 navigator.geolocation.getCurrentPosition とやってるところを getAccuratePosition に変えるだけで大丈夫そうです。たとえば、

getAccuratePosition(
    function(position){
        alert('成功');
    },
    function(error){
        alert('失敗:' + error.message + '(' + error.code + ')');
    },
    {limit:200, timeout:4000}
);

のように呼ぶイメージでしょうか。このスクリプトの長所は、

  • navigator.geolocation.getCurrentPosition と同じノリで使える
  • navigator.geolocation があるかどうかまで内部でチェックする
  • すべてローカル変数なので他のスクリプトと衝突しにくい

とかでしょうか。ぼくも初心者なのでツッコミ歓迎です。

参考文献