🍜 Ride with GPSからダウンロードした .gpx を読み込めるようにJSで変換する ①
作成日: 2021/09/25
1

読み飛ばして良いまえがき
自分で操作する場合には、多少手順が複雑でも諦めて繰り返すのですが…… 人に説明しようとすると話は別。何度も質問されたり、忙しい時に限って依頼が来るので、だとしたら誰がやっても失敗しないぐらい簡素にしたいと思いませんか?
妻に「Ride with GPSからダンロードしてきた .gpx が、Oregonで読み込めないんだけれど……。」と言われた時に開くのが、今回の解説ページです。



読み飛ばしてはいけないまえがき
サンプルのCodePenのものはすでに動くので、単に.gpxの変換だけしたい方は、そのまま使っていただいて構いません。趣旨としては、簡単なデータの操作程度であればすぐに書けるので、良いツールが見つからないならば自分で書いてみよう!というDIY精神でコードを書くと結構楽しいですよというお話です。

僕はmacOSのChromeと、手持ちのGarmin Oregon 450でしか動作確認をしていません。こんなザル検証は、お仕事では許されないわけですが、日曜エンジニアリングの範囲であれば全然問題無いわけです。

ただ、おそらく仕様上はOregonシリーズの450以降や、eTrexシリーズの最近のものであれば、今回変換した .gpx が読み込めるはずです。
(自転車で長距離や登山をしない人からするとなんのこっちゃという機種ですね。すみません。)



完成品の使い方

このシリーズで解説するコードはこちらです。
先にも書いたように環境が揃っていれば動くはずですので、コードには興味なくてすぐに変換したいんだよ方は、そのまま使用していただいて構いません。
https://codepen.io/kaitou1192/pen/gORyBGX

大まかな手順としては……

  1. Ride with GPS から .gpx ファイルをダウンロードしてくる
  2. 先程のCodePenの実行画面の「ファイル選択」で、該当の .gpx を選択
  3. ポイント数、ファイル名、トラック名を設定したのち「出力する」を選択
  4. 表示されたリンク「ダウンロード」よりファイルをダウンロードしてGPSに入れる

です。


注意点 その1
「1. Ride with GPS から .gpx ファイルをダウンロードしてくる」ですが、「GPXトラック(.gpx)」の項で

  • 500ポイントに減らす → チェックなし
  • 経路マーカーとしてPOIを含める → チェックなし
  • 経路マーカーとしてキューを含める → チェックなし

という状態にしてください。

画面でいうとこんな感じ。
スクリーンショット 2021-09-25 10.14.31.png

注意点 その2
今のところ日曜エンジニアリングの範囲でしかやっていないので、変なファイルを読み込ませたらどうなるんだ!とかはまるで考慮していません。そのあたりは自己責任でお願いします。
(とはいえ、コードが丸見えなので、僕が用意したコードが変なことはしていないというのはわかると思います。)



やっと本日の本題

今回は、まずブラウザで開いているページからローカルのXMLファイルのデータを読み込み、そこに書いている内容を取り出すというところまでやってみます。

本日の最終地点のCodePen → https://codepen.io/kaitou1192/pen/zYzmPGb

まずベースになる.gpxファイルをRide with GPSからダウンロードしてきます。
僕がダウンロードしてきたのは、このコースです。
https://ridewithgps.com/routes/31941961?privacy_code=phhXR8Izbex5WGSf

ダウンロードしたファイルをテキストエディタで開いてみると、この.gpxというのはXMLだということがわかります。
これはJavaScriptでDOMの操作ができる…… つまりHTMLやJSの知識、しかもプログラミング学習サービスetc.で扱っている範囲でどうにかできそうだということがわかると思います。 😎
スクリーンショット 2021-09-25 10.16.19.png

この落としてきた.gpxファイルをまずは読み込みたいので input type="file" を作ります。

<div class="file">
  <label>RWGのGPX: <input type="file" accept=".gpx"></label>
</div>

この accept=".gpx" の箇所で、読み込むファイルは .gpx という拡張子のものですよ。と指定しています。
(ただ、この拡張子が…… という時点で超ザルであることは間違いないので、商用の何かを作る際には、拡張子を偽装した何かがぶっこまれるかもしれないということは頭の片隅に置いておいてください。そういう場合、受け取ったファイルが何者なのか?というチェックをする処理は必須になります。今日は自分のための日曜エンジニアリングなので、このあたりは不問です。)


次に「ファイルを選択」で、ファイルが選択されたときに発動するトリガーを用意します。
こんな感じに addEventListener change を指定してあげればOK。

const inputFile = document.querySelector('input[type=file]');

inputFile.addEventListener('change', (event) => {
});

このファイルは、こんな感じに書くとアクセスできます。
(おまじないではなく、ちゃんと理解したい方はこちらをご確認いただければ。)

  const fileObject = event.target.files[0];

受け取ったファイルの中身を扱うためには FileReader を経由し .readAsText() と組み合わせて使います。

  const rwgGpx = new FileReader();

  rwgGpx.addEventListener('load', (event) => {
    const loadedGpx = event.target.result;
    console.log(loadedGpx);//このconsole.logは中身のチェックをしているだけなので本番では不要です。
  });
  
  rwgGpx.readAsText(fileObject);

こんがらがりそうなので、整理します。
input でユーザーに選択されたファイルが event.target.files[0] → fileObject。
rwgGpx は FileReaderオブジェクトで、それに readAsText 経由で fileObject を読み込ませます。
その読み込ませた結果…… つまり event.target.result → loadedGpx が、ユーザーに選択されたファイルの中身、今回でいうと .gpx の中身の文字列(String)の状態ということになります。

この時点では、単なる文字列なので、これを直接あーだこーだしようとすると、いかつい正規表現etc.であれやこれやしなければならないのですが、折角のXMLなので次回はDOMとして扱えるようにしたいと思います。



せっかくなので本編からはずれたワンポイント解説

今回の fileObject とかを受け取った際に console.log とかで、中身を確認したくなると思うのですが、CodePen側のConsoleで見ても、こんな感じでちょっと不便です。
スクリーンショット 2021-09-25 14.48.01.png
Chromeの開発者ツール経由の場合は、ちゃんとこんな風に表示されるのでおすすめです。
(先入観でCodePenの画面を開発者ツールで開くと面倒なことになりそうな気がするのですが、実際にはあまりそういうこともなく、普通に扱うことができます。)
スクリーンショット 2021-09-25 14.48.20.png



Ride with GPSからダウンロードした .gpx を読み込めるようにJSで変換する



Twitterもやっているので、よかったらフォローしてください。🙏🏻
https://twitter.com/Kaitou1192

本業はコードを書かせてもらえないフロントエンドエンジニアです。 こんなサービス作っています。 https://lp.re-shine.jp