Files
calorie-counter/frontend/src/lib/components/Energy/Aggregated/AggregatedFoodTable.svelte
2024-11-08 10:36:24 +01:00

160 lines
4.0 KiB
Svelte

<script lang="ts">
import { Line } from "svelte-chartjs";
import AggregatedFoodComp from "$lib/components/Energy/Aggregated/AggregatedFoodComp.svelte";
import { main } from "$wails/models";
import type { ChartData, Point } from "chart.js";
import regression from "regression";
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip,
} from "chart.js";
import { CalculateR2 } from "$lib/utils";
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale);
export let items: main.AggregatedFood[] = [];
export let energyTarget: number = 2000;
export let energyLimit: number = 2500;
let reversedItems = items.slice().reverse();
const defaultOptions = {
backgroundColor: "rgba(59, 130, 246, 0.1)",
borderColor: "rgb(59, 130, 246)",
pointBorderColor: "rgb(59, 130, 246)",
pointBackgroundColor: "rgb(255, 255, 255)",
pointBorderWidth: 2,
pointHoverRadius: 6,
pointHoverBackgroundColor: "rgb(59, 130, 246)",
pointHoverBorderColor: "rgb(255, 255, 255)",
pointHoverBorderWidth: 2,
pointRadius: 3,
pointHitRadius: 20,
tension: 0.4,
};
const data: ChartData<"line", (number | Point)[]> = {
labels: reversedItems.map((f) => f.period),
datasets: [
{
...defaultOptions,
label: "Amount",
data: reversedItems.map((f) => f.amount),
borderColor: "#ff4dff",
pointBorderColor: "#ff4dff",
},
{
...defaultOptions,
label: "AvgPer100",
data: reversedItems.map((f) => f.avgPer100),
borderColor: "#ffb84d",
pointBorderColor: "#ffb84d",
},
{
...defaultOptions,
label: "Energy",
data: reversedItems.map((f) => f.energy),
borderColor: "#b8ff4d",
pointBorderColor: "#b8ff4d",
},
{
...defaultOptions,
label: "Target",
data: reversedItems.map((f) => energyTarget),
borderColor: "#00ff00",
pointBorderColor: "#00ff00",
},
{
...defaultOptions,
label: "Limit",
data: reversedItems.map((f) => energyLimit),
borderColor: "#ff0000",
pointBorderColor: "#ff0000",
},
],
};
data.datasets.push({
...defaultOptions,
label: "R2",
data: CalculateR2(reversedItems.map((f, i) => [i, f.energy])),
borderColor: "#04d1d1",
pointBorderColor: "#04d1d1",
pointRadius: 0,
});
</script>
<template>
<div class="flex flex-col gap-6 p-6 bg-gray-900 min-h-screen">
<div class="bg-gray-800 rounded-lg p-6 shadow-lg border border-gray-700">
<Line
{data}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: "top",
labels: {
padding: 20,
color: "rgb(229, 231, 235)",
font: {
size: 12,
family: "'Nunito', sans-serif",
},
},
},
},
scales: {
y: {
grid: {
color: "rgba(75, 85, 99, 0.2)",
},
ticks: {
color: "rgb(229, 231, 235)",
font: {
family: "'Nunito', sans-serif",
},
},
},
x: {
grid: {
color: "rgba(75, 85, 99, 0.2)",
},
ticks: {
color: "rgb(229, 231, 235)",
font: {
family: "'Nunito', sans-serif",
},
},
},
},
}}
class="max-h-[50vh] h-[50vh]"
/>
</div>
<div class="relative flex flex-col h-[43vh]" data-vaul-drawer-wrapper id="page">
<div class="relative overflow-x-auto shadow-md rounded-lg">
<table class="w-full text-sm text-left text-gray-400">
<thead class="text-xs uppercase bg-gray-800 text-gray-200 sticky top-0">
<tr>
<th class="px-6 py-4 font-semibold" scope="col">Period</th>
<th class="px-6 py-4 font-semibold" scope="col">Amount</th>
<th class="px-6 py-4 font-semibold" scope="col">AvgPer100</th>
<th class="px-6 py-4 font-semibold" scope="col">Energy</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-700">
{#each items as f}
<AggregatedFoodComp item={f} />
{/each}
</tbody>
</table>
</div>
</div>
</div>
</template>