GeolocationAPI（WatchPosition）について

## Geolocation APIのwatchPosition()メソッドで現在位置を監視する
### 概要
Geolocation APIのWatchPositionを使って現在位置を監視する方法のまとめです。
### 目次
- watchPosition()
- 現在地を取得する、取得した現在地を監視する
- successCallbackについて
- errorCallbackについて
- clearWatchについて
- optionsについて
  - enableHighAccuracy
  - timeout
  - maximumAge
- サンプルコード
- サンプルコード動作確認
- 最後に
### 対象読者
- watchPositionとは何なのか興味のある方
- watchPositionを使用して位置情報の監視を行いたい方
- GetCurrentPositionとの違いを知りたい方
### watchPosition()
watchPositionとは、端末の位置情報を監視するためのメソッドです。
位置情報を取得するためには、ユーザーの許可が必要です。

https://developer.mozilla.org/ja/docs/Web/API/Geolocation/watchPosition
### 現在地を取得する、取得した現在地を監視する
watchPosition() メソッドを使用すると、初めに端末の現在地を取得します。その後端末の現在地をリアルタイムで取得できます。
```
const successCallback = (pos) => {
      const { latitude, longitude } = pos.coords
      console.log("経度：", longitude)
      console.log("緯度：", latitude)
    }
    const errorCallback = (error) => {
      console.error("エラー発生:", error.code)
      console.log(error)
      navigator.geolocation.clearWatch(watchId)
      console.log("位置情報の追跡を停止しました")
    }
    const options = {
      enableHighAccuracy: true,
      timeout: 5000,
      maximumAge: 'infinity',
    }
    const watchId = navigator.geolocation.watchPosition(successCallback, errorCallback, options)
    
    setTimeout(() => {
      navigator.geolocation.clearWatch(watchId)
      console.log("位置情報の追跡を停止しました")
    }, 30000)
```
watchPosition() を使ってユーザーの現在地情報をコンソールに表示しています。取得に失敗した場合はエラーメッセージを表示しています。
### :white_check_mark:successCallbackについて
watchPositionの第一引数で、位置情報が更新されたときに呼ばれる関数です。緯度経度などの情報を取得し、扱うことができます。
### :warning:errorCallbackについて
watchPositionの第二引数で、位置情報の取得が失敗したときに呼ばれる関数です。位置情報の取得失敗時の動作を記述できます。
### :see_no_evil:clearWatchについて
watchPositionによる位置情報の監視を停止することができます。
### :gear:optionsについて
watchPositionの第三引数で、位置情報の取得に関する設定を記述できます。この記事ではenableHighAccuracy、timeout、maximumAgeを使用しています。
#### enableHighAccuracy
より高精度な位置情報を要求するかどうかを設定します。true にすると高精度な情報を取得しようとしますが、バッテリー消費が多くなります。false にすると精度は下がりますが、バッテリー消費を抑えられます。

trueの場合
![enableHighAccuracyTrue.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/5c9d565d-21b8-44ec-b146-b02bd16770d7.jpeg)
falseの場合
![enableHighAccuracyFalse.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/b89dba15-5af5-4787-b7bd-604f009c092f.jpeg)
#### timeout
位置情報の取得を待つ最大時間を設定します。この時間内に位置情報が取得できない場合、setTimeoutが呼ばれ、clearWatchが起動します。指定しない場合は無限に待つ設定になります。サンプルコードでは5秒でタイムアウトする設定にしています。

動作確認方法

Edgeで開発者ツールを開きます。(F12またはCtrl+Shift+I)

Consoleタブ下の「⋮」をクリックから「More tools」を選択し「Sensor」を開きます。

「場所」のセレクトボックスを開き「場所を利用できません」を選択します。

「コンソール」に切り替え、リロードしてから5秒待ちます。

以下のようにエラーが表示されます。（エラーコード2→位置情報の取得に失敗、エラーコード3→タイムアウト）

タイムアウト前
![timeoutBefore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/0426dfc9-5059-4465-9e48-3f01b399e008.png)
タイムアウト後
![timeoutAfter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/acee55bc-ce57-483c-8721-b10bbf531947.png)
#### maximumAge
キャッシュされた位置情報の最大許容時間を設定します。指定した時間内であれば位置情報が更新されていなくても、キャッシュされた位置情報を返すことができます。デフォルトは0で最新の位置情報を取得しようとします。これを設定すると位置情報を取得する頻度を減らすことができパフォーマンス向上に役立ちます。

このオプションの動作を確認するためにまず以下のようにボタン押下でgetCurrentPositionが起動するコードを書きます。
```
<body>

<button id="btn">起動</button><br>
<p>緯度：<span id="latitude"></span><span>度</span></p>
<p>経度：<span id="longitude"></span><span>度</span></p>

<script>
const options2 = {
  enableHighAccuracy: true,
  timeout: 1000000,
  maximumAge: 'infinity',
};

function success(position) {
  var latitude = position.coords.latitude;
  var longitude = position.coords.longitude;
  document.getElementById("latitude").innerHTML = latitude;
  document.getElementById("longitude").innerHTML = longitude;
}

function error(error) {
  console.warn(`ERROR(${error.code}): ${error.message}`);
}

document.getElementById("btn").onclick = function(){
    navigator.geolocation.getCurrentPosition(success, error, options2);
};
</script>

</body>
```
ボタンを押下して現在の位置情報を取得します。
![firstGetCurrentPosition.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/d89737fe-3f89-45b8-a7b2-495cc6a9b9e0.jpeg)
まったく同じ位置でもう一度ボタンを押下すると押下した時の位置情報ではなく先ほど取得した位置情報が使用され、画面上での変化はない想定でした。
![secondGetCurrentPosition.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4044018/93d25db3-703d-46cc-afbd-9a89ebfda0cd.jpeg)
端末自体のキャッシュが更新されているため位置情報が更新されているのではないかと思います。もしこのオプションが動作していることの確認が取れたら教えていただきたいです。
### :beginner:サンプルコード
```
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>watchPosition</title>  
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin=""/>
  <style>
    #map { height: 850px; }
  </style>
</head>
<body>
  <div id="map"></div>
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script>
  <script>
  const map = L.map('map').setView([35.6895, 139.6917], 13)
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    
    let marker = L.marker([35.6895, 139.6917]).addTo(map)

    const successCallback = (pos) => {
      const { latitude, longitude } = pos.coords

      marker.setLatLng([latitude, longitude])

      console.log("経度：", longitude)
      console.log("緯度：", latitude)
    }
    
    const errorCallback = (error) => {
      console.error("エラー発生:", error.code)
      console.log(error)
      navigator.geolocation.clearWatch(watchId)
      console.log("位置情報の追跡を停止しました")
    }
    
    const options = {
      enableHighAccuracy: true,
      timeout: 5000,
      maximumAge: 0,
    }
    
    const watchId = navigator.geolocation.watchPosition(successCallback, errorCallback, options)
    
    setTimeout(() => {
      navigator.geolocation.clearWatch(watchId)
      console.log("位置情報の追跡を停止しました")
    }, 30000)
  </script>
</body>
</html>
```
### :eye:サンプルコード動作確認
- Edgeで開発者ツールを開きます。(F12またはCtrl+Shift+I)
- Consoleタブ下の「⋮」をクリックから「More tools」を選択し「Sensor」を開きます。
- 「場所」のセレクトボックスを開き「その他」を選択します。
- 緯度経度を変更しマップピンが切り替わることを確認します。

※この動作確認方法は自分の位置情報を無理やり変更するため位置情報が更新されるまでの間に一時的にエラーコード2（位置情報の取得に失敗）が返されます。位置情報がまだ取得できていない状態でwatchPositionが位置情報を取得しようとすることで発生するので正常な挙動です。
### :writing_hand:最後に
地図を扱うアプリだと現在地の監視はとても便利だと思うのでこの記事を投稿しました。
maximumAgeについては調べてみても「キャッシュの有効期限です。」程度の説明しかなかったのでなかなか動作が確認できず最終的に今回のような形になりました。

watchPositionを通して開発者ツールから自分の現在地を簡単に変更できることに驚きました、この記事を通してこんな動作確認方法もあることを一人でも多くの方に知ってもらえたら幸いです。