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: '© <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.