Add more statistics
This commit is contained in:
+48
@@ -473,6 +473,52 @@
|
||||
document.getElementById("stat-poos").textContent = count("poo");
|
||||
}
|
||||
|
||||
// Gaps (ms) between consecutive events of `type` logged within the last
|
||||
// `days` days, sorted ascending. These intervals are what tell you how
|
||||
// often the puppy needs to go out.
|
||||
function gapsBetween(events, type, days = 7) {
|
||||
const cutoff = startOfDay(new Date());
|
||||
cutoff.setDate(cutoff.getDate() - (days - 1));
|
||||
const from = cutoff.getTime();
|
||||
const times = events
|
||||
.filter(e => e.type === type && e.at >= from)
|
||||
.map(e => e.at)
|
||||
.sort((a, b) => a - b);
|
||||
const gaps = [];
|
||||
for (let i = 1; i < times.length; i++) gaps.push(times[i] - times[i - 1]);
|
||||
return gaps.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
// Median is used for the "typical" gap because it ignores the single long
|
||||
// overnight gap each day, so it reflects real daytime frequency.
|
||||
function median(sorted) {
|
||||
if (sorted.length === 0) return null;
|
||||
const mid = Math.floor(sorted.length / 2);
|
||||
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
||||
}
|
||||
|
||||
function renderTiming(events) {
|
||||
const peeGaps = gapsBetween(events, "pee");
|
||||
const pooGaps = gapsBetween(events, "poo");
|
||||
const show = (id, ms) => {
|
||||
document.getElementById(id).textContent = ms == null ? "—" : formatDuration(ms);
|
||||
};
|
||||
show("gap-pee", median(peeGaps));
|
||||
show("gap-pee-min", peeGaps[0] ?? null);
|
||||
show("gap-poo", median(pooGaps));
|
||||
show("gap-poo-min", pooGaps[0] ?? null);
|
||||
|
||||
const hint = document.getElementById("timing-hint");
|
||||
const typicalPee = median(peeGaps);
|
||||
if (typicalPee != null) {
|
||||
hint.textContent =
|
||||
`Based on ${peeGaps.length} pee gap${peeGaps.length === 1 ? "" : "s"}. ` +
|
||||
`Aim to take the puppy out a little before the typical ${formatDuration(typicalPee)} mark.`;
|
||||
} else {
|
||||
hint.textContent = "Log a few more pees and poos to see typical timings.";
|
||||
}
|
||||
}
|
||||
|
||||
function renderLasts(events) {
|
||||
const setLast = (id, type) => {
|
||||
const ev = lastEventOfType(events, type);
|
||||
@@ -832,6 +878,7 @@
|
||||
renderBigClock(events);
|
||||
renderStats(events);
|
||||
renderLasts(events);
|
||||
renderTiming(events);
|
||||
renderSleepWindows(events);
|
||||
renderWakeWindows(events);
|
||||
renderWeekly(events);
|
||||
@@ -1169,6 +1216,7 @@
|
||||
renderBigClock(evs);
|
||||
renderStats(evs);
|
||||
renderLasts(evs);
|
||||
renderTiming(evs);
|
||||
renderSleepWindows(evs);
|
||||
renderWakeWindows(evs);
|
||||
renderWeekly(evs);
|
||||
|
||||
Reference in New Issue
Block a user