ActivityCharts: 10s rolling mean on cadence and power line charts (display only)

This commit is contained in:
Davide Scaini
2026-05-12 23:32:33 +02:00
parent 1298586a74
commit a5db6142b3
+25 -3
View File
@@ -147,6 +147,20 @@
}; };
} }
// ── Rolling mean (display only — raw data used for stats/histogram) ────
function rollingMean(vals: (number | null)[], halfWin: number): (number | null)[] {
return vals.map((_, i) => {
const lo = Math.max(0, i - halfWin);
const hi = Math.min(vals.length - 1, i + halfWin);
let sum = 0, count = 0;
for (let j = lo; j <= hi; j++) {
const v = vals[j];
if (v != null) { sum += v; count++; }
}
return count > 0 ? sum / count : null;
});
}
// ── Reference lines (avg, P20, P80) — speed, cadence, power, hr ──────── // ── Reference lines (avg, P20, P80) — speed, cadence, power, hr ────────
function refStats(tab: Tab, vals: number[]) { function refStats(tab: Tab, vals: number[]) {
if (tab !== 'speed' && tab !== 'cadence' && tab !== 'power' && tab !== 'hr') return null; if (tab !== 'speed' && tab !== 'cadence' && tab !== 'power' && tab !== 'hr') return null;
@@ -214,12 +228,20 @@
// control points and visual artifacts — use linear instead. // control points and visual artifacts — use linear instead.
const curve = xMode === 'distance' ? 'linear' : 'monotone-x'; const curve = xMode === 'distance' ? 'linear' : 'monotone-x';
// Smooth cadence and power for visual rendering only (±5 s centred window = 11 s).
// Raw data is still used for the histogram, reference-line stats, and tooltip.
const needsSmooth = activeTab === 'cadence' || activeTab === 'power';
const smoothed = needsSmooth
? rollingMean(data.map(d => (d as any)[yKey] as number | null), 5)
: null;
const lineData = smoothed ? data.map((d, i) => ({ ...d, [yKey]: smoothed[i] })) : data;
if (activeTab === 'cadence') { if (activeTab === 'cadence') {
marks.push(Plot.lineY(data, { x, y: yKey, stroke: color, strokeWidth: 1.5, curve })); marks.push(Plot.lineY(lineData, { x, y: yKey, stroke: color, strokeWidth: 1.5, curve }));
} else { } else {
marks.push( marks.push(
Plot.areaY(data, { x, y: yKey, fill: color, fillOpacity: 0.15, curve }), Plot.areaY(lineData, { x, y: yKey, fill: color, fillOpacity: 0.15, curve }),
Plot.lineY(data, { x, y: yKey, stroke: color, strokeWidth: 1.5, curve }), Plot.lineY(lineData, { x, y: yKey, stroke: color, strokeWidth: 1.5, curve }),
); );
} }