From 0dd4a67e7b6f678b4136931d686670153e1e11c6 Mon Sep 17 00:00:00 2001 From: 4aiman Date: Mon, 25 May 2026 09:25:50 +0300 Subject: [PATCH] Sort by timestamp not seq, filter teleportation glitches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track 22 May showed 31km instead of 12.6km because 4 points had wrong seq order — native service and WebView GPS interleaved. Sorting by seq placed them wrong, creating 2km+ teleport jumps. Fixes: - All sort calls now use timestamp only (seq was unreliable) - computeStats skips segments > 180 km/h (GPS teleportation) - After recalculate: 22 May track should show ~12.6 km --- frontend/js/gps.js | 13 +++++++------ frontend/js/main.js | 7 +------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/frontend/js/gps.js b/frontend/js/gps.js index 58b2138..9c67778 100644 --- a/frontend/js/gps.js +++ b/frontend/js/gps.js @@ -40,11 +40,8 @@ GPS.distance = function(lat1, lon1, lat2, lon2) { GPS.computeStats = function(points, weightKg, opts) { if (points.length < 2) return { distance: 0, elevGain: 0, elevLoss: 0, avgSpeed: 0, maxSpeed: 0, kcal: 0, duration: 0, avgCadence: null }; - // Sort by seq (if present) or timestamp to fix out-of-order points from native service - const sorted = points.slice().sort((a, b) => { - if (a.seq != null && b.seq != null) return a.seq - b.seq; - return new Date(a.ts) - new Date(b.ts); - }); + // Always sort by timestamp — seq can be wrong if points arrived out of order during recording + const sorted = points.slice().sort((a, b) => new Date(a.ts) - new Date(b.ts)); let distance = 0, elevGain = 0, elevLoss = 0; const speeds = []; // m/s per segment @@ -84,9 +81,13 @@ GPS.computeStats = function(points, weightKg, opts) { for (let i = 1; i < sorted.length; i++) { const p = sorted[i], prev = sorted[i - 1]; const d = GPS.distance(prev.lat, prev.lon, p.lat, p.lon); - distance += d; const dt = (new Date(p.ts) - new Date(prev.ts)) / 1000; + // Skip teleportation glitches (> 180 km/h = GPS jump) + if (dt > 0 && d / dt > 50) continue; + + distance += d; + const v = dt > 0 ? d / dt : 0; // m/s speeds.push(v); diff --git a/frontend/js/main.js b/frontend/js/main.js index 531719b..6cd93dc 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -1870,7 +1870,6 @@ function renderRecordingInline(container) { // Restore trail if already recording — sort by seq/ts to avoid jumps if (GPS.recording.points.length > 0) { const sorted = GPS.recording.points.slice().sort((a, b) => { - if (a.seq != null && b.seq != null) return a.seq - b.seq; return new Date(a.ts) - new Date(b.ts); }); const coords = sorted.map(p => [p.lat, p.lon]); @@ -1883,7 +1882,6 @@ function renderRecordingInline(container) { // Rebuilds polyline from all sorted points instead of adding one-by-one. GPS.recording.onBatchUpdate = () => { const sorted = GPS.recording.points.slice().sort((a, b) => { - if (a.seq != null && b.seq != null) return a.seq - b.seq; return new Date(a.ts) - new Date(b.ts); }); const coords = sorted.map(p => [p.lat, p.lon]); @@ -1923,10 +1921,7 @@ function setupLiveUpdates(container) { GPS.recording.onBatchUpdate = () => { if (!gpsTrailLine || !gpsMap) return; - const sorted = GPS.recording.points.slice().sort((a, b) => { - if (a.seq != null && b.seq != null) return a.seq - b.seq; - return new Date(a.ts) - new Date(b.ts); - }); + const sorted = GPS.recording.points.slice().sort((a, b) => new Date(a.ts) - new Date(b.ts)); const coords = sorted.map(p => [p.lat, p.lon]); gpsTrailLine.setLatLngs(coords); if (coords.length) gpsMap.panTo(coords[coords.length - 1]);