ここからの説明は、実際にGPSセンサ付のデバイスでのみ動かせる。 まず、HTTPS配付可能なディレクトリにて、HTML 文書ファイルと JavaScript プログラムを作成し、それを GPS センサつきモバイルデバイスで確認するという手順が必要である。
https://www.w3.org/TR/geolocation-API/
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);
★★★★★★