ここからの説明は、実際にGPSセンサ付のデバイスでのみ動かせる。 まず、HTTPS配付可能なディレクトリにて、HTML 文書ファイルと JavaScript プログラムを作成し、それを GPS センサつきモバイルデバイスで確認するという手順が必要である。
https://www.w3.org/TR/geolocation-API/
GPSはアメリカによる測位衛星システムの固有名詞であり、 近年では衛星による位置を取得する一般名詞としてGNSS (Global Navigation Satellite System) を使うのが推奨されているが 本講ではGPSという語を用いる。
HTML5 Geolocation APIでは次の3つのインターフェースが用意されている。
getCurrentPosition(successCallback[, errorCallback[, option]])
センサからの位置情報を1度だけ取得試行し、成功したら
successCallback
を、失敗したら
errorCallback
を呼ぶ。
成功時の関数には Potision
オブジェクトが、
失敗時の関数には PotisionError
オブジェクトが渡される。
watchPosition(successCallback[, errorCallback[, option]])
位置情報取得を繰り返す。引数は getCurrentPosition()
と同様。
返却値としてIDが返るので、この値を保存しておき、GPS
追跡を止めたいときに次の clearWatch()
に渡す。
clearWatch(watchId)
指定したIdの追跡を止める。止めない限り追跡は続き、 成功・失敗によって指定した関数が呼ばれるため、 止める処理を盛り込む必要がある。
情報取得を試行する2つの関数は、いずれも第1、第2引数にそれぞれ 取得成功時に呼ぶ関数、失敗時に呼ぶ関数を指定する。このように 将来何かのタイミングで呼び返してほしい関数のことをコールバック関数 という。
第3引数に指定するのは挙動を制御するオプションで、 以下のプロパティが設定できる。
enableHighAccuracy |
高精度の測定をするかどうか。false はしない。false 以外であればする。デフォルトは false。 |
timeout |
位置情報が取得できるまでの最大待ち時間(ミリ秒)。 |
maximumAge |
以前に取得してキャッシュしてある位置情報の有効期限(ミリ秒)。 0(デフォルト)に指定するとキャッシュを利用せずかならず測定を試みる。 |
たとえば、1回のみの情報取得を試みるコードは以下のようになる。
// ここまでに変数 mymap にLeaflet地図オブジェクトが入っているとする。 var gpsmarker = L.marker(mymap.getCenter()).addTo(mymap); // マーカを作り、取得に関する情報をポップアップ表示する用途に用いる。 gpsmarker.bindPopup("取得中...").openPopup(); function tryGetGPS() { // 取得を開始する処理を行なう関数の定義 navigator.geolocation.getCurrentPosition( onSuccess, onError,{ // 下で定義する2つの関数をコールバック指定 maximumAge: 0, timeout: 2000, enableHighAccuracy: true }); } function onSuccess(pos) { // 成功時のコールバック。関数名は何でもよい。 // pos.coords に位置情報が入る。LeafletのLatLngに変換する。 var latlng = L.latLng([pos.coords.latitude, pos.coords.longitude]); mymap.panTo(latlng); // 地図の中心を取得した位置に gpsmarker.setPopupContent( // ポップアップ表示を "ここは "+latlng+"です." // 更新後の緯度経度に変え、 ).openPopup().setLatLng(latlng); // ポップアップし、ポイントも変更する } var nTrial = 10; // 最大試行回数を決めておく function onError(err) { // 失敗時のコールバック restN = "あと"+(--nTrial)+"回試行します。"; gpsmarker.setPopupContent("取得失敗:"+restN).openPopup(); if (nTrial > 0) { // 残り回数があれば tryGetGPS(); // 再度取得を試行する } } tryGetGPS();
成功時のコールバックには Position
オブジェクトが渡る。
Position
は2つのプロパティを持つ。
coords | 位置に関する情報 | |
timestamp | 取得時刻 |
coords
プロパティはさらに以下のプロパティを持つ。
latitude | 緯度(10進) | |
longitude | 経度(10進) | |
altitude | WGS84高度(メートル)(取れなければnull) | |
accuracy | 緯度経度の測定誤差(精度) | |
altitudeAccuracy | 高度の測定誤差(精度) | |
heading | 移動方向(北から反時計回り360度まで) | |
speed | 水平移動速度(m/s) |
モバイルデバイスを用いての実験はこのURLから:
https://www.yatex.org/lect/gps/gps-get.html
https://www.yatex.org/lect/gps/gps-watch.html
機種によって異なるが、次のようなことが気になる場合がある。
また、watchPosition()
の場合は捕捉に成功するまで続くが逆に
という問題があり、デバイスによっては電力消費が激しくなることもある。
<!DOCTYPE html> <html lang="ja"> <head> <title>GPS宝探し</title> <link rel="stylesheet" type="text/css" href="../src/leaflet.css"> <script type="text/javascript" src="../src/leaflet.js"></script> <script type="text/javascript" src="gps-chase.js"></script> <style type="text/css"> <!-- div#gpsmap {width: 90vw; height: 75vw; margin: auto;} --> </style> </head> <body> <h1>たからさがし<span id="title"></span></h1> <p> <button id="start" type="button">START</button> <button id="stop" type="button">STOP</button> <a href="../src/gps-chase.js">src</a> </p> <div id="gpsmap"></div> </body> </html>
document.addEventListener("DOMContentLoaded", () => { var mymap = L.map("gpsmap").setView([38.891, 139.824], 16); L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> \ contributors' }).addTo(mymap); var gpsmarker = L.marker(mymap.getCenter()).addTo(mymap); gpsmarker.bindPopup("STARTおしてね").openPopup(); var nTrial = 100 var watchId = null; // 最初はnullにしておく function stopGPS() { // watchが動いていたら止めてnullにする console.log("watchId="+watchId); if (watchId != null) { // nullかどうかで比較しないとだめ(初期値0) navigator.geolocation.clearWatch(watchId); document.getElementById("title").textContent = "stop"; gpsmarker.setPopupContent("停めました"); } watchId = null; } function tryWatchGPS() { stopGPS(); // 二重で動かないように注意する watchId = navigator.geolocation.watchPosition( onSuccess, onError,{ maximumAge: 0, timeout: 3000, enableHighAccuracy: true}); document.getElementById("title").textContent = "START!!"; } function onSuccess(pos) { // GPS信号が取れたらここに来る var latlng = L.latLng([pos.coords.latitude, pos.coords.longitude]); mymap.panTo(latlng);// 地図の中心をそこにする console.log(latlng); // ★★★★★ ここから gpsmarker.setLatLng(latlng).setPopupContent( "ここは lat="+latlng.lat+", lng="+latlng.lng+" です." ).openPopup(); // ★★★★★ ここまでの latlng.lat と latlng.lng を // if文などで判定して、特定の場所に近づいたら「GOAL!」と // 表示するように変えてみよ。 } function onError(err) { restN = "あと"+(--nTrial)+"回試行します。"; gpsmarker.setPopupContent("捕捉失敗:"+restN).openPopup(); if (nTrial <= 0) { navigator.geolocation.clearWatch(watchId); } } // STARTボタンに開始を仕込む document.getElementById("start").addEventListener("click", tryWatchGPS); // STOPボタンに停止を仕込む document.getElementById("stop").addEventListener("click", stopGPS); }, false);
★★★★★★