ActivityCharts: 10s rolling mean on cadence and power line charts (display only)
This commit is contained in:
@@ -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 }),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user