changed overview graphs binning
This commit is contained in:
@@ -365,7 +365,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-container">
|
<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">
|
<div class="chart-wrapper">
|
||||||
<canvas id="diaperChart"></canvas>
|
<canvas id="diaperChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
@@ -627,36 +627,115 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create days based on currentDaysRange (including today)
|
// If 24 hours selected, show 3-hour aggregates
|
||||||
for (let i = currentDaysRange - 1; i >= 0; i--) {
|
if (currentDaysRange === 1) {
|
||||||
const date = new Date(now);
|
// Create 8 three-hour buckets
|
||||||
date.setDate(date.getDate() - i);
|
for (let i = 7; i >= 0; i--) {
|
||||||
date.setHours(0, 0, 0, 0);
|
const periodStart = new Date(now);
|
||||||
|
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
|
||||||
|
|
||||||
const dateStr = date.toLocaleDateString("en-US", {
|
const periodEnd = new Date(periodStart);
|
||||||
month: "short",
|
periodEnd.setHours(periodEnd.getHours() + 3);
|
||||||
day: "numeric",
|
|
||||||
});
|
|
||||||
labels.push(dateStr);
|
|
||||||
|
|
||||||
// Count poop and pee diapers for this day
|
const startLabel = periodStart.toLocaleTimeString("en-US", {
|
||||||
const nextDay = new Date(date);
|
hour: "numeric",
|
||||||
nextDay.setDate(nextDay.getDate() + 1);
|
hour12: true,
|
||||||
|
});
|
||||||
|
const endLabel = periodEnd.toLocaleTimeString("en-US", {
|
||||||
|
hour: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
});
|
||||||
|
labels.push(`${startLabel}-${endLabel}`);
|
||||||
|
|
||||||
const dayChanges = filteredChanges.filter((dc) => {
|
// Count poop and pee diapers for this 3-hour period
|
||||||
const changeDate = new Date(dc.change_time);
|
const periodChanges = filteredChanges.filter((dc) => {
|
||||||
return changeDate >= date && changeDate < nextDay;
|
const changeDate = new Date(dc.change_time);
|
||||||
});
|
return changeDate >= periodStart && changeDate < periodEnd;
|
||||||
|
});
|
||||||
|
|
||||||
const poopCount = dayChanges.filter(
|
const poopCount = periodChanges.filter(
|
||||||
(dc) => dc.poop_amount !== null,
|
(dc) => dc.poop_amount !== null,
|
||||||
).length;
|
).length;
|
||||||
const peeCount = dayChanges.filter(
|
const peeCount = periodChanges.filter(
|
||||||
(dc) => dc.pee_amount !== null,
|
(dc) => dc.pee_amount !== null,
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
poopData.push(poopCount);
|
poopData.push(poopCount);
|
||||||
peeData.push(peeCount);
|
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);
|
||||||
|
|
||||||
|
// 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 };
|
return { labels, poopData, peeData };
|
||||||
@@ -724,7 +803,7 @@
|
|||||||
beginAtZero: true,
|
beginAtZero: true,
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: "Number of Diapers",
|
text: "Number of Changes",
|
||||||
font: {
|
font: {
|
||||||
size: 13,
|
size: 13,
|
||||||
weight: "600",
|
weight: "600",
|
||||||
|
|||||||
@@ -402,7 +402,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-container">
|
<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">
|
<div class="chart-wrapper">
|
||||||
<canvas id="feedingsChart"></canvas>
|
<canvas id="feedingsChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
@@ -661,28 +661,91 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create days based on currentDaysRange (including today)
|
// If 24 hours selected, show 3-hour aggregates
|
||||||
for (let i = currentDaysRange - 1; i >= 0; i--) {
|
if (currentDaysRange === 1) {
|
||||||
const date = new Date(now);
|
// Create 8 three-hour buckets
|
||||||
date.setDate(date.getDate() - i);
|
for (let i = 7; i >= 0; i--) {
|
||||||
date.setHours(0, 0, 0, 0);
|
const periodStart = new Date(now);
|
||||||
|
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
|
||||||
|
|
||||||
const dateStr = date.toLocaleDateString("en-US", {
|
const periodEnd = new Date(periodStart);
|
||||||
month: "short",
|
periodEnd.setHours(periodEnd.getHours() + 3);
|
||||||
day: "numeric",
|
|
||||||
});
|
|
||||||
labels.push(dateStr);
|
|
||||||
|
|
||||||
// Count feedings for this day
|
const startLabel = periodStart.toLocaleTimeString("en-US", {
|
||||||
const nextDay = new Date(date);
|
hour: "numeric",
|
||||||
nextDay.setDate(nextDay.getDate() + 1);
|
hour12: true,
|
||||||
|
});
|
||||||
|
const endLabel = periodEnd.toLocaleTimeString("en-US", {
|
||||||
|
hour: "numeric",
|
||||||
|
hour12: true,
|
||||||
|
});
|
||||||
|
labels.push(`${startLabel}-${endLabel}`);
|
||||||
|
|
||||||
const count = filteredFeedings.filter((f) => {
|
// Count feedings for this 3-hour period
|
||||||
const feedingDate = new Date(f.start_time);
|
const count = filteredFeedings.filter((f) => {
|
||||||
return feedingDate >= date && feedingDate < nextDay;
|
const feedingDate = new Date(f.start_time);
|
||||||
}).length;
|
return feedingDate >= periodStart && feedingDate < periodEnd;
|
||||||
|
}).length;
|
||||||
|
|
||||||
data.push(count);
|
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);
|
||||||
|
|
||||||
|
// 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 };
|
return { labels, data };
|
||||||
|
|||||||
@@ -536,42 +536,105 @@
|
|||||||
return `${hours}h ${mins}m`;
|
return `${hours}h ${mins}m`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareBarChartData(sleeps, timeRange) {
|
function prepareBarChartData(sleepSessions) {
|
||||||
const days = {};
|
const now = new Date();
|
||||||
const today = new Date();
|
const labels = [];
|
||||||
today.setHours(0, 0, 0, 0);
|
const data = [];
|
||||||
|
|
||||||
// Initialize all days in range
|
// Filter by selected child if applicable
|
||||||
for (let i = timeRange - 1; i >= 0; i--) {
|
let filteredSessions = sleepSessions;
|
||||||
const date = new Date(today);
|
if (selectedChildId !== null) {
|
||||||
date.setDate(date.getDate() - i);
|
filteredSessions = sleepSessions.filter(
|
||||||
const dateStr = date.toISOString().split("T")[0];
|
(session) => session.child_id === selectedChildId,
|
||||||
days[dateStr] = 0;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count sleeps per day
|
// If 24 hours selected, show 3-hour aggregates
|
||||||
sleeps.forEach((sleep) => {
|
if (currentDaysRange === 1) {
|
||||||
const date = new Date(sleep.start_time);
|
// Create 8 three-hour buckets
|
||||||
date.setHours(0, 0, 0, 0);
|
for (let i = 7; i >= 0; i--) {
|
||||||
const dateStr = date.toISOString().split("T")[0];
|
const periodStart = new Date(now);
|
||||||
if (days.hasOwnProperty(dateStr)) {
|
periodStart.setHours(periodStart.getHours() - (i * 3), 0, 0, 0);
|
||||||
days[dateStr]++;
|
|
||||||
|
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 labels = Object.keys(days).map((date) => {
|
const periodEnd = new Date(periodStart);
|
||||||
const d = new Date(date);
|
periodEnd.setHours(periodEnd.getHours() + 8);
|
||||||
return d.toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
// Format label based on the 8-hour period
|
||||||
labels,
|
const dayStr = periodStart.toLocaleDateString("en-US", {
|
||||||
data: Object.values(days),
|
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 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) {
|
function prepareDurationDistributionData(sleeps) {
|
||||||
const ranges = {
|
const ranges = {
|
||||||
|
|||||||
Reference in New Issue
Block a user