changed overview graphs binning

This commit is contained in:
Brian Bjarke Jensen
2025-11-11 13:45:54 +01:00
parent 143c3a0323
commit bb27d4437f
3 changed files with 281 additions and 76 deletions
+106 -27
View File
@@ -365,7 +365,7 @@
</div>
<div class="chart-container">
<h2>Diaper Changes Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})</h2>
<h2>Diaper Changes (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})</h2>
<div class="chart-wrapper">
<canvas id="diaperChart"></canvas>
</div>
@@ -627,36 +627,115 @@
);
}
// Create days based on currentDaysRange (including today)
for (let i = currentDaysRange - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
date.setHours(0, 0, 0, 0);
// If 24 hours selected, show 3-hour aggregates
if (currentDaysRange === 1) {
// Create 8 three-hour buckets
for (let i = 7; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 3);
const dateStr = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
labels.push(dateStr);
const startLabel = periodStart.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
const endLabel = periodEnd.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
labels.push(`${startLabel}-${endLabel}`);
// Count poop and pee diapers for this day
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
// Count poop and pee diapers for this 3-hour period
const periodChanges = filteredChanges.filter((dc) => {
const changeDate = new Date(dc.change_time);
return changeDate >= periodStart && changeDate < periodEnd;
});
const dayChanges = filteredChanges.filter((dc) => {
const changeDate = new Date(dc.change_time);
return changeDate >= date && changeDate < nextDay;
});
const poopCount = periodChanges.filter(
(dc) => dc.poop_amount !== null,
).length;
const peeCount = periodChanges.filter(
(dc) => dc.pee_amount !== null,
).length;
const poopCount = dayChanges.filter(
(dc) => dc.poop_amount !== null,
).length;
const peeCount = dayChanges.filter(
(dc) => dc.pee_amount !== null,
).length;
poopData.push(poopCount);
peeData.push(peeCount);
}
} else if (currentDaysRange === 3) {
// Show 8-hour aggregates for 3 days (9 buckets total)
for (let i = 8; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 8);
poopData.push(poopCount);
peeData.push(peeCount);
// Format label based on the 8-hour period
const dayStr = periodStart.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
const startHour = periodStart.getHours();
let periodLabel;
if (startHour >= 0 && startHour < 8) {
periodLabel = `${dayStr} Night`;
} else if (startHour >= 8 && startHour < 16) {
periodLabel = `${dayStr} Morning`;
} else {
periodLabel = `${dayStr} Evening`;
}
labels.push(periodLabel);
// Count poop and pee diapers for this 8-hour period
const periodChanges = filteredChanges.filter((dc) => {
const changeDate = new Date(dc.change_time);
return changeDate >= periodStart && changeDate < periodEnd;
});
const poopCount = periodChanges.filter(
(dc) => dc.poop_amount !== null,
).length;
const peeCount = periodChanges.filter(
(dc) => dc.pee_amount !== null,
).length;
poopData.push(poopCount);
peeData.push(peeCount);
}
} else {
// Create days based on currentDaysRange (including today)
for (let i = currentDaysRange - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
date.setHours(0, 0, 0, 0);
const dateStr = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
labels.push(dateStr);
// Count poop and pee diapers for this day
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
const dayChanges = filteredChanges.filter((dc) => {
const changeDate = new Date(dc.change_time);
return changeDate >= date && changeDate < nextDay;
});
const poopCount = dayChanges.filter(
(dc) => dc.poop_amount !== null,
).length;
const peeCount = dayChanges.filter(
(dc) => dc.pee_amount !== null,
).length;
poopData.push(poopCount);
peeData.push(peeCount);
}
}
return { labels, poopData, peeData };
@@ -724,7 +803,7 @@
beginAtZero: true,
title: {
display: true,
text: "Number of Diapers",
text: "Number of Changes",
font: {
size: 13,
weight: "600",
+82 -19
View File
@@ -402,7 +402,7 @@
</div>
<div class="chart-container">
<h2>Feedings Per Day (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})</h2>
<h2>Feedings (Last ${currentDaysRange} Day${currentDaysRange !== 1 ? "s" : ""})</h2>
<div class="chart-wrapper">
<canvas id="feedingsChart"></canvas>
</div>
@@ -661,28 +661,91 @@
);
}
// Create days based on currentDaysRange (including today)
for (let i = currentDaysRange - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
date.setHours(0, 0, 0, 0);
// If 24 hours selected, show 3-hour aggregates
if (currentDaysRange === 1) {
// Create 8 three-hour buckets
for (let i = 7; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 3);
const dateStr = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
labels.push(dateStr);
const startLabel = periodStart.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
const endLabel = periodEnd.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
labels.push(`${startLabel}-${endLabel}`);
// Count feedings for this day
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
// Count feedings for this 3-hour period
const count = filteredFeedings.filter((f) => {
const feedingDate = new Date(f.start_time);
return feedingDate >= periodStart && feedingDate < periodEnd;
}).length;
const count = filteredFeedings.filter((f) => {
const feedingDate = new Date(f.start_time);
return feedingDate >= date && feedingDate < nextDay;
}).length;
data.push(count);
}
} else if (currentDaysRange === 3) {
// Show 8-hour aggregates for 3 days (9 buckets total)
for (let i = 8; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 8);
data.push(count);
// Format label based on the 8-hour period
const dayStr = periodStart.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
const startHour = periodStart.getHours();
let periodLabel;
if (startHour >= 0 && startHour < 8) {
periodLabel = `${dayStr} Night`;
} else if (startHour >= 8 && startHour < 16) {
periodLabel = `${dayStr} Morning`;
} else {
periodLabel = `${dayStr} Evening`;
}
labels.push(periodLabel);
// Count feedings for this 8-hour period
const count = filteredFeedings.filter((f) => {
const feedingDate = new Date(f.start_time);
return feedingDate >= periodStart && feedingDate < periodEnd;
}).length;
data.push(count);
}
} else {
// Create days based on currentDaysRange (including today)
for (let i = currentDaysRange - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
date.setHours(0, 0, 0, 0);
const dateStr = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
labels.push(dateStr);
// Count feedings for this day
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
const count = filteredFeedings.filter((f) => {
const feedingDate = new Date(f.start_time);
return feedingDate >= date && feedingDate < nextDay;
}).length;
data.push(count);
}
}
return { labels, data };
+93 -30
View File
@@ -536,42 +536,105 @@
return `${hours}h ${mins}m`;
}
function prepareBarChartData(sleeps, timeRange) {
const days = {};
const today = new Date();
today.setHours(0, 0, 0, 0);
function prepareBarChartData(sleepSessions) {
const now = new Date();
const labels = [];
const data = [];
// Initialize all days in range
for (let i = timeRange - 1; i >= 0; i--) {
const date = new Date(today);
date.setDate(date.getDate() - i);
const dateStr = date.toISOString().split("T")[0];
days[dateStr] = 0;
// Filter by selected child if applicable
let filteredSessions = sleepSessions;
if (selectedChildId !== null) {
filteredSessions = sleepSessions.filter(
(session) => session.child_id === selectedChildId,
);
}
// Count sleeps per day
sleeps.forEach((sleep) => {
const date = new Date(sleep.start_time);
date.setHours(0, 0, 0, 0);
const dateStr = date.toISOString().split("T")[0];
if (days.hasOwnProperty(dateStr)) {
days[dateStr]++;
// If 24 hours selected, show 3-hour aggregates
if (currentDaysRange === 1) {
// Create 8 three-hour buckets
for (let i = 7; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 3);
const startLabel = periodStart.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
const endLabel = periodEnd.toLocaleTimeString("en-US", {
hour: "numeric",
hour12: true,
});
labels.push(`${startLabel}-${endLabel}`);
// Count sleep sessions for this 3-hour period
const count = filteredSessions.filter((session) => {
const startDate = new Date(session.start_time);
return startDate >= periodStart && startDate < periodEnd;
}).length;
data.push(count);
}
});
} else if (currentDaysRange === 3) {
// Show 8-hour aggregates for 3 days (9 buckets total)
for (let i = 8; i >= 0; i--) {
const periodStart = new Date(now);
periodStart.setHours(periodStart.getHours() - (i * 8), 0, 0, 0);
const periodEnd = new Date(periodStart);
periodEnd.setHours(periodEnd.getHours() + 8);
const labels = Object.keys(days).map((date) => {
const d = new Date(date);
return d.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
});
// Format label based on the 8-hour period
const dayStr = periodStart.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
const startHour = periodStart.getHours();
let periodLabel;
if (startHour >= 0 && startHour < 8) {
periodLabel = `${dayStr} Night`;
} else if (startHour >= 8 && startHour < 16) {
periodLabel = `${dayStr} Morning`;
} else {
periodLabel = `${dayStr} Evening`;
}
labels.push(periodLabel);
return {
labels,
data: Object.values(days),
};
}
// Count sleep sessions for this 8-hour period
const count = filteredSessions.filter((session) => {
const startDate = new Date(session.start_time);
return startDate >= periodStart && startDate < periodEnd;
}).length;
data.push(count);
}
} else {
// Create days based on currentDaysRange (including today)
for (let i = currentDaysRange - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
date.setHours(0, 0, 0, 0);
const dateStr = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
labels.push(dateStr);
// Count sleep sessions for this day
const nextDay = new Date(date);
nextDay.setDate(nextDay.getDate() + 1);
const count = filteredSessions.filter((session) => {
const startDate = new Date(session.start_time);
return startDate >= date && startDate < nextDay;
}).length;
data.push(count);
}
}
function prepareDurationDistributionData(sleeps) {
const ranges = {