◆ getCurrentPosition で 1 回取得
◆ watchPosition で変化のたびにコールバック関数呼び出し
◆ https とユーザの許可が必要
◆ devtools の sensor タブから 取得できる緯度経度を変更できる

geolocation という位置情報を取得する機能があります
https://developer.mozilla.org/ja/docs/Web/API/Geolocation_API

自分で使うことはなかったので今更ながら使ってみました
記事にしようと思ったメインのところより機能紹介が長くなったので分けました

基本の使い方

使い方はシンプルでこういう感じです

navigator.geolocation.getCurrentPosition(
console.log,
console.log
)
// GeolocationPosition {}
// coords: GeolocationCoordinates
// accuracy: 150
// altitude: null
// altitudeAccuracy: null
// heading: null
// latitude: 35.689487
// longitude: 139.691706
// speed: null
// __proto__: GeolocationCoordinates
// timestamp: 1622265658717
// __proto__: GeolocationPosition

navigator.geolocation でアクセスできるオブジェクトを使います

navigator.geolocation
// Geolocation {}
// __proto__: Geolocation
// clearWatch: ƒ clearWatch()
// getCurrentPosition: ƒ getCurrentPosition()
// watchPosition: ƒ watchPosition()
// constructor: ƒ Geolocation()
// Symbol(Symbol.toStringTag): "Geolocation"
// __proto__: Object

位置情報を取得するだけの機能なので関数は少なめです

getCurrentPosition

getCurrentPosition では今の位置情報を取得します
取得は非同期なのですが Promise ではなくコールバック関数を成功用とエラー用に 2 つ渡すというちょっと古めな作りです
不満もありますが Chrome5 や IE9 からあるような昔からの機能なのでこれは仕方ないでしょう

取得に成功すると 緯度経度などが入った coords プロパティと取得時刻が入った timestamp プロパティのあるオブジェクトを引数にコールバック関数が呼び出されます
coords の中身はこんな感じです

{
accuracy: 150,
altitude: null,
altitudeAccuracy: null,
heading: null,
latitude: 35.689487,
longitude: 139.691706,
speed: null
}

latitude と longitude が緯度経度で その正確さを表す accuracy を取得できます
accuracy の単位はメートルで 150 なら 取得できた緯度経度の座標から 150m 以内の場所と考えると良いみたいです
GPS 装置によっては方位・高度・速度も取得できるようです
取得できない場合は上の例のように null です

watchPosition

watchPosition を使うと呼び出し時に 1 回位置情報を取得するだけでなく 位置情報に変化があるたびにコールバック関数を呼び出してくれます
引数やコールバック関数に渡される引数は getCurrentPosition と同じです
watch を解除するには clearWatch に watchPosition を呼び出したときの返り値を渡します
setTimeout/clearTimeout みたいな感じです

ただ ちょっと特殊な動きで変化したときには 2 回コールバック関数が呼び出されます
変化前と変化後の 2 回です
「変化前」の値は 前回の変化時の「変化後」として受け取ったものと同じものです
2 回同じものを受け取ることになるので ログを保存するようなことをするのなら重複除外が必要です
変化前の分は timestamp が前回の取得時になっているので timestamp を使って除外できます

navigator.geolocation.watchPosition(
console.log,
console.log
)
// 1
// GeolocationPosition {coords: GeolocationCoordinates, timestamp: 1622265658717}
// ↑ watch 開始時に取得できる現在の値
// GeolocationPosition {coords: GeolocationCoordinates, timestamp: 1622265658717}
// ↑ 1 回目の変化時に取得できる変化前の値
// GeolocationPosition {coords: GeolocationCoordinates, timestamp: 1622266016026}
// ↑ 1 回目の変化時に取得できる変化後の値
// GeolocationPosition {coords: GeolocationCoordinates, timestamp: 1622266016026}
// ↑ 2 回目の変化時に取得できる変化前の値
// GeolocationPosition {coords: GeolocationCoordinates, timestamp: 1622266021207}
// ↑ 2 回目の変化時に取得できる変化後の値

実行結果を見ても 同じ timestamp が 2 連続していますね

パーミッション

この API は https が必須ですが http でも関数は存在して呼び出せます
呼び出した結果としてエラーを受け取ります

navigator.geolocation.getCurrentPosition(
console.log,
console.log
)
// GeolocationPositionError {}
// code: 1
// message: "Only secure origins are allowed (see: https://goo.gl/Y0ZkNV)."
// __proto__: GeolocationPositionError

また パーミッションが必要でユーザが拒否するとこういうエラーを受け取ります

navigator.geolocation.getCurrentPosition(
console.log,
console.log
)
// GeolocationPositionError {}
// code: 1
// message: "User denied Geolocation"
// __proto__: GeolocationPositionError

code が 1 ですが 1 は PERMISSION_DENIED を表すようです
エラーコードを数値で表現するのも古い感じがしますね (参考)

devtools

取得する位置情報は devtools で簡単に操作できます
sensor タブの Location から変更できます

devtools-senssor-location

事前に登録済みの場所を選択したり 直接緯度経度の数値を変更できます
この状態で getCurrentPosition などで位置情報を取得するとここで設定したものになります
設定できるのは緯度経度だけで accuracy など設定できないものも多いです

位置情報を偽装するのにも使えますが 緯度経度以外の位置情報も変更するには関数を置き換える必要がありそうです