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

#概要
今更ですが、ReactでWeb版GPSロガーを作ってみます。
移動した位置を線で結んでゆく、所謂、あれです。
React以外では、React Native含めいろいろ作ってきましたが、
Reactのstate更新による再描画を利用すると割と動作が軽いことがわかったのでやってみます。
一般的にGPSロガーと言えばいろいろな機能を加えて使用するものと思われますが、
今回の①では、ボタンを押したときに現在位置をプロットする仕様とします。
機能としては、GPSロガーの動作のみ実現することにします。
②では位置情報が更新されるとそのまま線を引いてゆく仕様にしようと思います。

#事前準備
・GCPにおいて、Maps Javascript APIの有効化
・APIキーの取得
簡単に出来るのでお願いいたします。

・@react-google-maps/apiのインストール
mapパッケージはいくつか存在し、しかも、直近ダウンロードが多く良さげ？！と思ったりするものもあり迷いますがずっと使っている上記を使用しました。


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

動きとしては、

・地図を表示
・現在位置をマーカーでセンター表示にする
・画面のプロットボタンを押すと現在地と前回ボタンを押した地点を線で結ぶ
・だらだらこれの繰り返し


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

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

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

const App = ( ) => {
    const [position, setPosition] =　useState({lat:null,lng:null});
    const [pathCoordinates, setPathCoordinates] = useState([]);

//今回、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',
    }
    const containerStyle = {
        width: '100%',
        height: '75vh'
    }
    const buttonStyle = {
        width: '100%',
        height: '10vh',
        fontSize: '20px',
        fontWeight: 'bold'
    }

//配列のstateの場合、値を追加するにはスプレッド構文を用います。
    const PathCd = () => {
        setPathCoordinates([...pathCoordinates, {lat:position.lat,lng:position.lng}])
    }

//ボタンをクリックするとPathCd()が呼ばれ現在地の緯度経度がsetPathCoordinatesにより追加されます。
//このとき再描画され線が引かれます。
    return (
        <>
        <div>
            <label style={labelStyle}>GPSロガー①</label>
                <LoadScript googleMapsApiKey={process.env.REACT_APP_GOOGLE_MAP_API_KEY}>
                    <GoogleMap
                        mapContainerStyle={containerStyle}
                        center={{lat: position.lat, lng: position.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: position.lat, lng: position.lng}} />
                    </GoogleMap>
                </LoadScript>
        </div>
        <button style={buttonStyle} onClick={() => PathCd()}>
            現在位置をプロット
        </button>
        </>
    );
};
export default App
```

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

JR東京駅からスタートします。
ここから大手町プレイスに向かってみます。
気が向いたタイミングでボタンを押します。
![mobile_gps_logger_01_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411849/515e8e81-786c-9e95-8695-4fceb0bc5111.jpeg)
大手町プレイスまで来ました。
こんな感じにボタンを押したときの位置情報の軌跡が線で
表現されています。
![mobile_gps_logger_01_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411849/e412b8a4-5d3d-6067-3beb-914b2bbf2473.jpeg)





#まとめ
コードでお分かりのように、
`Polyline`の`path`に、現在位置の緯度経度を単純に追加してゆくだけなので
移動してボタンを押せばおすほど行が増えます。
それをさらに`return`で描画してゆき、やがてデバイスのリソースが一杯になり再描画における副作用が修復の度合いを超えると画面が固まったりしてしまうので
DBに書き出しなどをやったり古いレコードをマージしたり工夫するのが普通です。
ただ、5分もボタンを押してると飽きるので問題なしです。
しかも、このボタンバージョンでは数日やってても
ダイジョブでした。
`②では、ボタン無しで追加`してゆくようにしようと思います。