Project today's end-of-day sleep total on the Sleep trend chart

A dashed tail continues today's line from now to midnight by adding the
increments the N-day average curve makes over the same stretch, so the
projection follows the usual daily rhythm instead of extrapolating the
current rate (which overshoots right after a long night). The legend
shows the projected total; with no history there's no average and no
projection.
This commit is contained in:
Alexander Heldt
2026-07-15 10:36:22 +00:00
parent cebe923d68
commit ab0e51108c
4 changed files with 45 additions and 4 deletions
+29 -2
View File
@@ -1318,7 +1318,27 @@
}
}
return { today, yesterday, avg, avgDays };
// Where today is likely to end up: continue today's line by adding what
// the average day typically adds between now and midnight. That respects
// the time-of-day rhythm (night sleep, nap clusters), unlike a linear
// rate extrapolation, which overshoots wildly just after a long night.
// No history → no average → no projection.
let projected = null;
if (avg) {
const nowPt = today[today.length - 1];
const avgAt = (x) => {
const lo = Math.floor(x);
const hi = Math.min(24, lo + 1);
return avg[lo].y + (avg[hi].y - avg[lo].y) * (x - lo);
};
projected = [{ x: nowPt.x, y: nowPt.y }];
for (let h = Math.ceil(nowPt.x); h <= 24; h++) {
if (h <= nowPt.x) continue; // now landing exactly on an hour boundary
projected.push({ x: h, y: nowPt.y + avgAt(h) - avgAt(nowPt.x) });
}
}
return { today, yesterday, avg, avgDays, projected };
}
function drawSleepTrendChart(curves) {
@@ -1330,9 +1350,10 @@
const innerH = H - MT - MB;
const series = [
// Reference lines first so today draws on top of them.
// Reference lines first so today (and its projected tail) draw on top.
{ pts: curves.avg, cls: "trend-avg", label: `${curves.avgDays}-day average` },
{ pts: curves.yesterday, cls: "trend-yesterday", label: "Yesterday" },
{ pts: curves.projected, cls: "trend-projected", label: "Projected end of day" },
{ pts: curves.today, cls: "trend-today", label: "Today" },
].filter(s => s.pts && s.pts.length > 1);
@@ -1377,9 +1398,15 @@
const yLegend = document.getElementById("legend-trend-yesterday");
const aLegend = document.getElementById("legend-trend-avg");
const aText = document.getElementById("legend-trend-avg-text");
const pLegend = document.getElementById("legend-trend-projected");
const pText = document.getElementById("legend-trend-projected-text");
if (yLegend) yLegend.hidden = !curves.yesterday;
if (aLegend) aLegend.hidden = !curves.avg;
if (aText) aText.textContent = `${curves.avgDays}-day avg`;
if (pLegend) pLegend.hidden = !curves.projected;
if (pText && curves.projected) {
pText.textContent = `Projected ~${curves.projected[curves.projected.length - 1].y.toFixed(1)}h`;
}
}
// ---------- weight ----------