Draw GPS Track on OpenStreetMap

I made a thing for my other blog to show the GPS track of my flights.

I thought I'd write down how I did it.

Recording GPS Tracks

I use an app for iOS called "myTracks". In the free version you can start a recording and then stop the recording.

You will be able to view the track in the app itself, but you can also export it and e-mail yourself a file in the "gpx" format. Gpx stands for "GPS Exchange Format" and it's XML based.

Dowloading GPX files

I fetch the GPX file from a URL using the standard "Fetch API"

        fetch(trackPath)
            .then(function (response) {
                return response.text();
            }).then(function (gpxData) {
                // Parse gpxData here ...
            });

Parsing GPX files

I use a JavaScript library "gpxParser" that I found on GitHub.

The parsing works like so:

let gpx = new gpxParser();
gpx.parse(gpxData);

Embedding a Map

I need a map to draw the gps track on. For this I use leaflet to embed an OpenStreetMap map.

With the following script:

<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"
            integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
            crossorigin=""></script>

This CSS

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"
          integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
          crossorigin="" />

This HTML

<div id="map"></div>

And this piece of JavaScript to initialize the map:

let mymap = L.map('map');

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    maxZoom: 50
}).addTo(mymap);

Drawing the Track

After parsing the GPX data and embedding a map, it's possible to draw the track:

function drawTrack(track) {
    let coordinates = track.points.map(p => [p.lat.toFixed(5), p.lon.toFixed(5)]);

    var polyline = L.polyline(coordinates, { weight: 6, color: 'darkred' }).addTo(mymap);

    // zoom the map to the polyline
    mymap.fitBounds(polyline.getBounds());
}

In the first line track.points.map(p => [p.lat.toFixed(5), p.lon.toFixed(5)]) I "map" each point in the track to a new object that the Leaflet library understands: a two element array (latitude and lontitude).

To be clear, the "track" input is what the gpx library has parsed. From earlier:

let gpx = new gpxParser();
gpx.parse(gpxData);
drawTrack(gpx.tracks[0]);

Example

Here's an example of what the embedded map looks like. Note it also contains two charts for altitude and groundspeed. These use the HighCharts component - but I'll talk about that in some other post.

I also packages this into an app by itself, so it can be embedded by using a URL (in the example: https://tracks.aaronlenoir.com/?track=tracks/flights/flight-010-20190917.gpx

You can see the URL of the gpx file is passed to the track variable.