Skip to content

Commit

Permalink
Enhance charts and add tooltips
Browse files Browse the repository at this point in the history
  • Loading branch information
Brendan Birdsong committed Sep 27, 2023
1 parent 8b29dd5 commit 6c168ea
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 111 deletions.
203 changes: 96 additions & 107 deletions app/components/ChartModal.js
Original file line number Diff line number Diff line change
@@ -1,122 +1,111 @@
"use client";

import { CartesianGrid, Line, LineChart, ResponsiveContainer, XAxis, YAxis } from 'recharts';
import { calculateAverageIntake, calculateDayAverageLoss, sortEntries } from '../constants';
import { Button, Stack, TextField } from '@mui/material';
import { useState } from 'react';
import {
calculateAverageIntake,
calculateDayAverageLoss,
sortEntries,
} from "../constants";
import { Button, Stack, TextField, Typography } from "@mui/material";
import { useState } from "react";
import Graph from "./Graph";
import { getCharts } from "../charts";

export default function ChartModal({ user }) {
const [show, setShow] = useState(false);
const [daysToGraph, setDaysToGraph] = useState(30);
const [daysToAverage, setDaysToAverage] = useState(7);

const [show, setShow] = useState(false);
const [days, setDays] = useState(30);

const data = [];
var entries = [];
var lastEntry = {};
const data = [];
var entries = [];

if (days) {
const lastDayEntries = user.entries.slice(0, days);
entries = sortEntries(lastDayEntries, true);
for (var i = 1; i < entries.length; i++) {
const curEntry = entries[i - 1];
const nextEntry = entries[i];

const curWeekWeight = calculateDayAverageLoss(user, curEntry, 7);
const nextWeekWeight = calculateDayAverageLoss(user, nextEntry, 7);

const curWeekCalories = calculateAverageIntake(user, curEntry, 7);
const nextWeekCalories = calculateAverageIntake(user, nextEntry, 7);

const prevDataWeightVariance = data.length > 0 ? data[i - 2].weightVariance : 0;
const prevDataCaloricVariance = data.length > 0 ? data[i - 2].caloricVariance : 0;
const prevWeightChange = data.length > 0 ? data[i - 2].weightChange : 0;
const prevCaloricChange = data.length > 0 ? data[i - 2].caloricChange : 0;

data.push({
date: curEntry.date,
weightChange: ((nextWeekWeight - curWeekWeight)) + prevWeightChange,
caloricChange: ((nextWeekCalories - curWeekCalories)) + prevCaloricChange,
weightVariance: ((nextWeekWeight - curWeekWeight)),
caloricVariance: ((nextWeekCalories - curWeekCalories)),
});
}
if (daysToGraph && daysToAverage) {
const lastDayEntries = user.entries.slice(0, daysToGraph);
entries = sortEntries(lastDayEntries, true);
for (var i = 1; i < entries.length; i++) {
const curEntry = entries[i - 1];
const nextEntry = entries[i];

lastEntry = entries[0];
}

if (user.entries.length <= 1) {
return;
}
const curWeight = parseFloat(
calculateDayAverageLoss(user, curEntry, daysToAverage)
);
const nextWeight = parseFloat(
calculateDayAverageLoss(user, nextEntry, daysToAverage)
);

return (
<>
<Button sx={{marginTop: 2, marginLeft: 2}} color="primary" variant="contained" size="small" onClick={() => setShow(!show)}>{show ? 'Hide' : 'Show'} Charts</Button>
{show &&
<>
<Stack margin={2} spacing={2}>
<TextField onChange={(e) => setDays(parseInt(e.target.value))} name="steps" type="number" label="Days" value={days} />
</Stack>
<h5 style={{marginTop: 10, color: 'black'}}>Weight Average</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={entries}>
<XAxis dataKey="date" />
<YAxis domain={[lastEntry.weight - 10, lastEntry.weight + 10]} />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Weight" type="monotone" dataKey="weight" stroke="blue" />
</LineChart>
</ResponsiveContainer>
const curCalories = parseFloat(
calculateAverageIntake(user, curEntry, daysToAverage)
);
const nextCalories = parseFloat(
calculateAverageIntake(user, nextEntry, daysToAverage)
);

<h5 style={{color: 'black'}}>Weight Change</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={data}>
<XAxis dataKey="date" />
<YAxis />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Weight" type="monotone" dataKey="weightChange" stroke="blue" />
</LineChart>
</ResponsiveContainer>
// i - 2 because i starts at 1
const prevWeightChange =
data.length > 0 ? data[i - 2].totalWeightChange : 0;
const prevCaloricChange =
data.length > 0 ? data[i - 2].totalCaloricChange : 0;

<h5 style={{color: 'black'}}>Weight Variance</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={data}>
<XAxis dataKey="date" />
<YAxis />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Weight" type="monotone" dataKey="weightVariance" stroke="blue" />
</LineChart>
</ResponsiveContainer>
data.push({
date: curEntry.date,
totalWeightChange: nextWeight - curWeight + prevWeightChange,
totalCaloricChange: nextCalories - curCalories + prevCaloricChange,
dailyWeightChange: nextWeight - curWeight,
dailyCaloricChange: nextCalories - curCalories,
});
}
data.forEach((e) => {
e.totalWeightChange = e.totalWeightChange.toFixed(2);
e.dailyWeightChange = e.dailyWeightChange.toFixed(2);
});
}

<h5 style={{color: 'black'}}>Caloric Average</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={entries}>
<XAxis dataKey="date" />
<YAxis domain={[lastEntry.calories - 1000, lastEntry.calories + 1000]} />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Calories" type="monotone" dataKey="calories" stroke="blue" />
</LineChart>
</ResponsiveContainer>
if (user.entries.length <= 1) {
return;
}

<h5 style={{color: 'black'}}>Caloric Change</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={data}>
<XAxis dataKey="date" />
<YAxis />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Weight" type="monotone" dataKey="caloricChange" stroke="blue" />
</LineChart>
</ResponsiveContainer>
return (
<>
<Button
sx={{ marginTop: 2, marginLeft: 2 }}
color="primary"
variant="contained"
size="small"
onClick={() => setShow(!show)}
>
{show ? "Hide" : "Show"} Charts
</Button>
{show && (
<>
<Stack style={{ marginBottom: 15 }} margin={2} spacing={2}>
<TextField
onChange={(e) => setDaysToGraph(parseInt(e.target.value))}
name="steps"
type="number"
label="Number of Days to show on Graph"
value={daysToGraph}
/>
<TextField
onChange={(e) => setDaysToAverage(parseInt(e.target.value))}
name="steps"
type="number"
label="Number of Days used to average your Weight"
value={daysToAverage}
/>
</Stack>

<h5 style={{color: 'black'}}>Caloric Variance</h5>
<ResponsiveContainer width="95%" height={300}>
<LineChart data={data}>
<XAxis dataKey="date" />
<YAxis />
<CartesianGrid stroke="black" strokeDasharray="5 5"/>
<Line label="Weight" type="monotone" dataKey="caloricVariance" stroke="blue" />
</LineChart>
</ResponsiveContainer>
</>
}
{getCharts(data, entries).map((c, i) => (
<Graph
key={i}
desc={c.desc}
label={c.label}
data={c.data}
xAxisKey={c.xAxisKey}
dataKey={c.dataKey}
unit={c.unit}
/>
))}
</>
)
)}
</>
);
}
10 changes: 6 additions & 4 deletions app/components/DayEntryEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ export default function DayEntryEdit({ user, entry, setEntry, open, hideEdit, sa
setDateRequired(!entry.date);

if (entry.date) {
const dateAlreadyExists = user.entries.map(e => e.date).indexOf(entry.date) > -1;
if (dateAlreadyExists) {
alert('Date ' + entry.date + ' has already been logged.');
return;
if (!entry.id) {
const dateAlreadyExists = user.entries.map(e => e.date).indexOf(entry.date) > -1;
if (dateAlreadyExists) {
alert('Date ' + entry.date + ' has already been logged.');
return;
}
}
save();
hideEdit();
Expand Down

0 comments on commit 6c168ea

Please sign in to comment.