/* gpx.js - display GPX tracks on a leaflet maps
* see leaflet-gpx https://github.com/mpetazzoni/leaflet-gpx for the underlying leaflet plugin
*/
// keep track of how many tracks we've added
var trackCount = 0
var trackArray = []
var map = L.map('map')
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © <a href="http://www.osm.org">OpenStreetMap</a>'
}).addTo(map)
function download(url) {
const a = document.createElement('a')
a.href = url
a.download = url.split('/').pop()
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
function sortedAppend(t) {
// splice might fail "not a function" otherwise
if(trackArray.length == 0) {
trackArray.push(t)
return
}
// find idx to splice
var idx = 0
for(const track of trackArray) {
if(t.date > track.date) {
break
}
idx++
}
trackArray.splice(idx, 0, t)
trackCount++
}
function createTrackList(arr) {
var tracklist = document.getElementById('tracklist')
arr.forEach((track, idx, array) => {
const date = track.date
const text = track.name
const bounds = track.bounds
var t = document.createElement('li')
t.className = 'track'
t.innerHTML = `<a><date>${date.toISOString().split('T')[0]}</date><span>${text}</span></a>`
t.onclick = function() { map.fitBounds(bounds) }
tracklist.appendChild(t)
})
}
function addGPX(map, gpx, lineColor) {
new L.GPX(gpx, {
async: true,
marker_options: {
startIconUrl: 'images/pin-icon-start.png',
endIconUrl: 'images/pin-icon-end.png',
shadowUrl: 'images/pin-shadow.png'
},
polyline_options: {
smoothFactor: 3,
color: lineColor,
opacity: 1,
weight: 3,
lineCap: 'round'
}
}).on('loaded', function(e) {
// add track to list
const track = {
date: e.target.get_start_time(),
name: e.target.get_name(),
bounds: e.target.getBounds()
}
sortedAppend(track)
// fit map to track bounds on loading
map.fitBounds(e.target.getBounds())
}).on('mouseover', function(e) {
var paths = gpx.split("/")
var filename = paths[paths.length - 1]
var kms = e.target.get_distance() / 1000
var movingTime = e.target.get_duration_string_iso(e.target.get_moving_time(), true)
var movingSpeed = e.target.get_moving_speed()
var totalAvgTime = e.target.get_duration_string_iso(e.target.get_total_time(), true)
var totalAvgSpeed = e.target.get_total_speed()
var tooltip = `
<div class="maptooltip">
<h3>${e.target.get_name()}</h3>
<div class="maptooltip-left">
<b>Distance: ${kms.toFixed(2)} km</b><br>
Total time: ${totalAvgTime} h<br>
Moving time: ${movingTime} h<br>
</div>
<div class="maptooltip-right">
<b>Elevation gain: ${e.target.get_elevation_gain().toFixed()} m d+</b><br>
Avg speed: ${totalAvgSpeed.toFixed(2)} km/h<br>
Avg moving speed: ${movingSpeed.toFixed(2)} km/h <br>
</div>
<div style="clear:both"></div>
<h4>Click to download: ${filename}</h4>
</div>`
this.bindTooltip(tooltip, {sticky: true})
this.openPopup(e.latlng)
}).on('click', function(e) {
download(gpx)
}).addTo(map)
}
const ta = [
this.addGPX(map, '../tracks/turin_09122022.gpx', 'red'),
this.addGPX(map, '../tracks/biella_27122022.gpx', 'blue'),
this.addGPX(map, '../tracks/la_fausto_coppi_2026_lungo.gpx', 'purple')
]
// this.createTrackList(trackArray)
// // wait for all tracks to be loaded, then create tracklist
function sleep(ms) {
return new Promise(resolve => { setTimeout(resolve, ms); });
}
async function waitForLoading() {
while (trackArray.length < ta.length) {
await(sleep(100));
}
this.createTrackList(trackArray)
}
waitForLoading()
// todo this should run after addGPX complete