fix: deterministic multi-GPX trackpoint ordering and catch-path completion
Pre-allocate fileResults[idx] slots so GPX files always concatenate in URL order regardless of fetch arrival order (Bug 1). Both .then and .catch now call computeDistance() after decrementing pending so a failed last fetch no longer leaves the distance element permanently blank (Bug 2). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
This commit is contained in:
@@ -144,33 +144,46 @@ function haversine(lat1, lng1, lat2, lng2) {
|
|||||||
var distEl = document.getElementById('stat-distance');
|
var distEl = document.getElementById('stat-distance');
|
||||||
|
|
||||||
if (GPX_URLS.length > 0) {
|
if (GPX_URLS.length > 0) {
|
||||||
// Mode A: sum haversine between all GPX trackpoints
|
// Mode A: sum haversine between all GPX trackpoints (deterministic order)
|
||||||
var pending = GPX_URLS.length;
|
var pending = GPX_URLS.length;
|
||||||
var masterPts = [];
|
var fileResults = new Array(GPX_URLS.length);
|
||||||
GPX_URLS.forEach(function(url) {
|
GPX_URLS.forEach(function(url, idx) {
|
||||||
fetch(url)
|
fetch(url)
|
||||||
.then(function(r) { return r.text(); })
|
.then(function(r) { return r.text(); })
|
||||||
.then(function(text) {
|
.then(function(text) {
|
||||||
var xml = new DOMParser().parseFromString(text, 'text/xml');
|
var xml = new DOMParser().parseFromString(text, 'text/xml');
|
||||||
var trkpts = xml.querySelectorAll('trkpt');
|
var trkpts = xml.querySelectorAll('trkpt');
|
||||||
|
var pts = [];
|
||||||
trkpts.forEach(function(pt) {
|
trkpts.forEach(function(pt) {
|
||||||
masterPts.push({
|
pts.push({
|
||||||
lat: parseFloat(pt.getAttribute('lat')),
|
lat: parseFloat(pt.getAttribute('lat')),
|
||||||
lon: parseFloat(pt.getAttribute('lon'))
|
lon: parseFloat(pt.getAttribute('lon'))
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
fileResults[idx] = pts;
|
||||||
pending--;
|
pending--;
|
||||||
if (pending === 0) {
|
if (pending === 0) { computeDistance(); }
|
||||||
var total = 0;
|
|
||||||
for (var i = 1; i < masterPts.length; i++) {
|
|
||||||
total += haversine(masterPts[i-1].lat, masterPts[i-1].lon,
|
|
||||||
masterPts[i].lat, masterPts[i].lon);
|
|
||||||
}
|
|
||||||
distEl.textContent = masterPts.length < 2 ? '—' : Math.round(total).toLocaleString();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(function(err) { console.warn('GPX load failed:', url, err); pending--; });
|
.catch(function(err) {
|
||||||
|
console.warn('GPX load failed:', url, err);
|
||||||
|
fileResults[idx] = [];
|
||||||
|
pending--;
|
||||||
|
if (pending === 0) { computeDistance(); }
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function computeDistance() {
|
||||||
|
var masterPts = [];
|
||||||
|
fileResults.forEach(function(pts) {
|
||||||
|
if (pts) { pts.forEach(function(p) { masterPts.push(p); }); }
|
||||||
|
});
|
||||||
|
var total = 0;
|
||||||
|
for (var i = 1; i < masterPts.length; i++) {
|
||||||
|
total += haversine(masterPts[i-1].lat, masterPts[i-1].lon,
|
||||||
|
masterPts[i].lat, masterPts[i].lon);
|
||||||
|
}
|
||||||
|
distEl.textContent = masterPts.length < 2 ? '—' : Math.round(total).toLocaleString();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Mode B: sum haversine between consecutive entry lat/lng points
|
// Mode B: sum haversine between consecutive entry lat/lng points
|
||||||
var total = 0;
|
var total = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user