changed overview graphs binning
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user