GPXデータをNode-REDでMAP表示する

#はじめに
最近YAMAPというスマホアプリを利用して登山やウォーキングの移動記録に利用させて頂いてます！https://yamap.com/
![新規 PNG イメージ (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87274/42892117-6820-009c-4844-73f4ec6cf03a.png)

このサービスは利用者同士でアップロードした写真や移動記録を共有することができます（要登録）。移動記録はGPXデータとしてファイルをエクスポートすることが出来ます。感謝です！

今回は、エクスポートしたGPXファイルをNode-REDアプリで読み込んで移動軌跡を地図上に表示したいと思います。

#GPXファイルのダウンロード
YAMAPの活動日記のGPXデータはエクスポートボタンをクリックするとダウンロードすることが出来ます。（下記スクショ参照）
![新規 PNG イメージ (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87274/12f4eace-894e-a24d-7c28-f2d7febd059c.png)

GPXファイル（GPS eXchange Format）は、GPSやGNSS装置、ソフトウェア間で位置情報を交換するためのデータフォーマットですが、今回使うデータは緯度経度データ（lat,lon）だけ取り出して使います。

#YAMAPのGPXファイル例
```javascript
<?xml version='1.0' encoding='UTF-8'?><gpx creator="YAMAP - https://yamap.com" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><metadata><bounds maxlat="35.7122402452265" maxlon="139.7760804278215" minlat="35.67051605324789" minlon="139.71303124925095"/></metadata><trk><name>国立競技場〜上野ウォーキング</name><number>1</number><trkseg><trkpt lat="35.67967315673425" lon="139.714627666529"><ele>48.37340545654297</ele><time>2024-12-06T05:03:10Z</time></trkpt><trkpt lat="35.679737278293516" lon="139.71442054970163"><ele>24.98186492919922</ele><time>2024-12-06T05:03:16Z</time></trkpt><trkpt lat="35.67975232380971" lon="139.71464476561147"><ele>28.07640838623047</ele><time>2024-12-06T05:03:44Z</time></trkpt><trkpt lat="35.67967018115863" lon="139.71484341671663"><ele>26.21483612060547</ele><time>2024-12-06T05:04:03Z</time></trkpt>
```
#Node-REDのフロー
Node-REDのフローの説明を大雑把に説明すると
・GPXファイルを読み込みます
・GPXファイルから緯度経度を順番に取り出します
・順次MAPにマーカー表示します
![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87274/3e351fe6-17b6-77c3-1f9a-580a57b45c11.png)
#Node-REDコード
今回のアプリのフローは以下となります
```javascript
[
    {
        "id": "e0a8c7397e9086c6",
        "type": "ui_worldmap",
        "z": "2765d3e413fe3e7c",
        "group": "f6d075ed94163f1b",
        "order": 3,
        "width": 6,
        "height": "8",
        "name": "GPXビュワー",
        "lat": "",
        "lon": "",
        "zoom": "16",
        "layer": "OSMC",
        "cluster": "",
        "maxage": "",
        "usermenu": "hide",
        "layers": "hide",
        "panit": "true",
        "panlock": "false",
        "zoomlock": "false",
        "hiderightclick": "true",
        "coords": "none",
        "showgrid": "false",
        "showruler": "false",
        "allowFileDrop": "false",
        "path": "/worldmap",
        "overlist": "DR,CO,RA,DN,BU,RW,HM",
        "maplist": "OSMG,OSMC,EsriC,EsriS,EsriT,EsriDG,UKOS",
        "mapname": "",
        "mapurl": "",
        "mapopt": "",
        "mapwms": false,
        "x": 600,
        "y": 160,
        "wires": []
    },
    {
        "id": "791b480a2b9a60b1",
        "type": "change",
        "z": "2765d3e413fe3e7c",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "payload.gpx.trk.trkseg.trkpt",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 460,
        "y": 100,
        "wires": [
            [
                "3858880b3aa43f1f"
            ]
        ]
    },
    {
        "id": "3858880b3aa43f1f",
        "type": "split",
        "z": "2765d3e413fe3e7c",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 610,
        "y": 100,
        "wires": [
            [
                "e06e0d6f57f1675f"
            ]
        ]
    },
    {
        "id": "e06e0d6f57f1675f",
        "type": "function",
        "z": "2765d3e413fe3e7c",
        "name": "name",
        "func": "msg.payload = {\n    \"name\":\"me\",\n    \"lat\":msg.payload.lat,\n    \"lon\":msg.payload.lon,\n    \"photoUrl\":\"https://m.media-amazon.com/images/I/71hzOqZrB0L._AC_SS130_.jpg\"\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 270,
        "y": 160,
        "wires": [
            [
                "607c98dd6daa0f76"
            ]
        ]
    },
    {
        "id": "607c98dd6daa0f76",
        "type": "delay",
        "z": "2765d3e413fe3e7c",
        "name": "",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "10",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 420,
        "y": 160,
        "wires": [
            [
                "e0a8c7397e9086c6"
            ]
        ]
    },
    {
        "id": "4588bc6fd27ad41a",
        "type": "fastxml",
        "z": "2765d3e413fe3e7c",
        "name": "",
        "property": "payload",
        "outproperty": "payload",
        "attr": "",
        "chr": "_",
        "x": 300,
        "y": 100,
        "wires": [
            [
                "791b480a2b9a60b1"
            ]
        ]
    },
    {
        "id": "aaa0c9bff85e5133",
        "type": "ui_upload",
        "z": "2765d3e413fe3e7c",
        "group": "f6d075ed94163f1b",
        "title": "upload GPX file",
        "accept": ".gpx",
        "name": "GPXアップロード",
        "order": 1,
        "width": 6,
        "height": 4,
        "chunk": 256,
        "transfer": "text",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "4588bc6fd27ad41a"
            ]
        ]
    },
    {
        "id": "f6d075ed94163f1b",
        "type": "ui_group",
        "name": "GPXビュワー",
        "tab": "0b8a7a0b409383f5",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "0b8a7a0b409383f5",
        "type": "ui_tab",
        "name": "GPX ビュワー",
        "icon": "dashboard",
        "disabled": false,
        "hidden": false
    }
]
```
上記フローには下記のノードが必要ですのでインストールしてください
https://flows.nodered.org/node/node-red-contrib-web-worldmap
https://flows.nodered.org/node/node-red-contrib-ui-upload

#完成
だいぶ見栄えは粗削りですが・・・（敢えて余計なことは省いてます）
予めYAMAPからDLしたGPXファイルを選択して再生ボタンを押せば地図上に赤いマーカーがスタート地点から終点まで移動します。これ見てるだけで癒されるのは私だけどしょうか？(笑)
![新規 PNG イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87274/0f903b3d-0dfb-8047-8bc6-3678addaf626.png)

#まとめ
YAMAPの活動日記からGPXファイルをエクスポートし、Node-REDアプリで地図上に移動する様子を表示しました。YAMAP以外の他のGPXファイルでも行けると思います（未確認ですが）、例えばサンタさんの移動データを入手して、夜中にのんびり軌跡を眺めるなんて、うーんロマンチックですね！
ではではメリークリスマーーーーーース！