ReactでWeb版GPSロガーを作ってみる②

#概要
「ReactでWeb版GPSロガーを作ってみる①」では、
ボタンを押したときに現在位置をプロットする仕様でした。
今回の②では位置情報が更新されるとそのまま線が引かれる仕様にしようと思います。


#事前準備
①のときと同様に、
・GCPにおいて、Maps Javascript APIの有効化
・APIキーの取得
をお願いいたします。

・@react-google-maps/apiのインストール
・@react-cmpt/use-throttleのインストール

#コーディング
環境
node v10.24.0
react 17.0.2
@react-google-maps/api@2.7.0
@react-cmpt/use-throttle@0.3.2
chrome

動きとしては、

・地図を表示
・現在位置をマーカーでセンター表示にする
・移動により位置情報が変化すると現在地と移動する前の地点を線で結ぶ
（ただし、秒単位で間引いて線を結ぶ仕様とする。）
・そしてこれの繰り返しで移動した軌跡を描画してゆく


編集は、
`$ npx create-react-app project_name`
で作成される`App.js`のみをとりあえず編集します。
また、
プロジェクトカレントパスに、「`.env`」隠しファイルを作成し、
以下一行追加しておいてください。

`REACT_APP_GOOGLE_MAP_API_KEY="(事前準備で取得したAPIキー)"`

```react:App.js
import React, { useState, useEffect } from 'react';
import { GoogleMap,
            LoadScript,
            Marker,
            Polyline, } from '@react-google-maps/api';
import { useThrottle } from "@react-cmpt/use-throttle";
import './App.css';

const App = ( ) => {
    const [posCurrent, setPosition] = useState({lat:null,lng:null});
    //posCurrentの更新を３秒間は間引くことを示す。（３秒未満のイベントはスルーする）
    const [posThrottle] = useThrottle(posCurrent, 3000);
    const [pathCoordinates, setpathCoordinates] = useState([]);
    
    //GoogleMapのPolylineコンポーネントのpathに指定するpathCoordinatesのエントリーに
    //nullが存在するとPolylineが機能しないので削除しておく。
    {(() => {
        if (JSON.stringify(pathCoordinates[0]) === '{"lat":null,"lng":null}' ) {
            const pathTmp = [...pathCoordinates]
            pathTmp.splice(0,1)
            setpathCoordinates(pathTmp)
        }
    })()}
    
    //配列のstateの場合、値を追加するにはスプレッド構文を用います。
    const PathCd = () => (
            setpathCoordinates([...pathCoordinates, {lat:posCurrent.lat,lng:posCurrent.lng}])
    )

	//posThrottleが更新されると、PathCd()が呼び出される。
	//この時、前回PathCd()が呼び出された際、stateの更新による再描画とposCurrentの更新による
	//再描画との再描画の連鎖などを回避するため、PathCd()側の描画に関係する待ちイベント処理等を抑制させる。
    useEffect(() => {
        PathCd()
    }, [posThrottle])


	//今回、getCurrentPositionで現在位置を取得します。
	//位置情報が更新されると再描画されるのを確認出来ます。
	//（位置が変わりマーカーが再びセンターにくる。）
    {(() => { navigator.geolocation.getCurrentPosition(position => {
        const { latitude, longitude } = position.coords;
        setPosition({lat:latitude,lng:longitude});
        },
        (err) => console.log(err),
        {
            enableHighAccuracy: true,
            maximumAge: 0
        }
    )})()}

    const labelStyle = {
        margin: '3px',
        display: 'block'
    }
    const containerStyle = {
        width: '100%',
        height:'80vh'
    }

    return (
        <>
        <div>
            <label style={labelStyle}>GPSロガー②</label>
                <LoadScript googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAP_API_KEY}>
                    <GoogleMap
                        mapContainerStyle={containerStyle}
                        center={{lat:posCurrent.lat,lng:posCurrent.lng}}
                        zoom={15}
                        options={{ gestureHandling: 'greedy'}}
                        >
                        <Polyline
                            path={pathCoordinates}
                            key={1}
                            editable={false}
                            geodesic={false}
                            options={{
                                strokeColor: '#0000FF',
                                strokeOpacity: 1.0,
                                strokeWeight: 5
                            }}
                        />
                        <Marker position={{lat:posCurrent.lat, lng:posCurrent.lng}} />
                    </GoogleMap>
                </LoadScript>
        </div>
        </>
    )
}
export default App
```

#モバイルからのWebアクセス
Google Maps APIを利用する際のアクセスプロトコルは、`https`になります。
`自己CAの場合は`、`Chrome`や`Safari`でアクセスしてみてください。
（ブラウザで聞かれたら許可してください。）
`SSL証明書購入の場合は`、`どのブラウザでも`行けると思います。
・モバイルの`GPS`は`オン`です。（①②も）


大手町プレイスからスタートしてみます。
三越日本橋本店の手前あたりです。
日ごろから鍛えているので長距離ジョギングも平気です。
嘘です。
ここ数年きついので自転車でタラタラ走っています。
![mobile_gps_logger_02_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411849/9cd17b79-ce3b-eea3-3647-ca6ff41d5cc7.jpeg)
到着です。
東京スカイツリーまで来ました。
Wifiオフの状態でしたが位置が非常に正確です。
enableHighAccuracyが効いていると思われます。
これならもっと間引いてもいけそうです。
![mobile_gps_logger_02_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411849/f4d83ad1-adf6-f7c7-db1f-d50cc8338557.jpeg)
実際こんな道中でした。
![mobile_gps_logger_02_3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411849/7e23f840-6b8f-dd58-917f-e7efd0a06715.jpeg)




#まとめ
今回も①同様、
位置情報が変わると`Polyline`の`path`に、現在の位置情報を追加してゆき、
それをさらに`return`で再描画を繰り返してゆきます。
そのままpathの行が増えるとやがてデバイスのリソースなどが一杯になり、
多くの情報を描画することや他の要因により画面が固まったりしてしまいます。
DBに書き出しなどを行ったり古いレコードをマージしたりする工夫が必要です。
実際、対策を施した多機能追加バージョンも作成しているので折をみて公開したいと思います。
取得保存したpath情報でいろいろなことに使えそうです。

年末年始、暇で時間ができたので最近凝っているReactを
テストすることにしてみました。
また、
RailsあたりでもGPSアプリケーション公開しようと思います。
データベースお得意のRailsなので色々出来そうです。
さらに、Node不要のRails7に驚異を感じますが、
いろいろ出来るようにしておこうと思います。


（おまけ）
なお、このままでも一時間以上連続動作しています。
毎日のジョギング(いや、サイクリング(汗))にも十分使えています。