From f4ae63c499d92b9fdcc9d4a6c905d70b907ef9cb Mon Sep 17 00:00:00 2001 From: Claas Date: Sat, 16 Aug 2025 13:28:12 +0200 Subject: [PATCH] Create debug page to reduce noise debugging graph --- package.json | 1 + pnpm-lock.yaml | 12 ++++ src/Debug.tsx | 101 +++++++++++++++++++++++++++ src/Graph.tsx | 181 +++++++++++++++++++++++++++++++++---------------- src/index.tsx | 12 +++- 5 files changed, 247 insertions(+), 60 deletions(-) create mode 100644 src/Debug.tsx diff --git a/package.json b/package.json index 395f062..478a187 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "preview": "vite preview" }, "dependencies": { + "@solidjs/router": "^0.15.3", "@tailwindcss/vite": "^4.1.11", "idb": "^8.0.3", "solid-js": "^1.9.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1b8e398..721cc74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@solidjs/router': + specifier: ^0.15.3 + version: 0.15.3(solid-js@1.9.8) '@tailwindcss/vite': specifier: ^4.1.11 version: 4.1.11(vite@7.1.1(jiti@2.5.1)(lightningcss@1.30.1)) @@ -391,6 +394,11 @@ packages: cpu: [x64] os: [win32] + '@solidjs/router@0.15.3': + resolution: {integrity: sha512-iEbW8UKok2Oio7o6Y4VTzLj+KFCmQPGEpm1fS3xixwFBdclFVBvaQVeibl1jys4cujfAK5Kn6+uG2uBm3lxOMw==} + peerDependencies: + solid-js: ^1.8.6 + '@tailwindcss/node@4.1.11': resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} @@ -1119,6 +1127,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.46.2': optional: true + '@solidjs/router@0.15.3(solid-js@1.9.8)': + dependencies: + solid-js: 1.9.8 + '@tailwindcss/node@4.1.11': dependencies: '@ampproject/remapping': 2.3.0 diff --git a/src/Debug.tsx b/src/Debug.tsx new file mode 100644 index 0000000..6e68077 --- /dev/null +++ b/src/Debug.tsx @@ -0,0 +1,101 @@ +import { + createEffect, + createResource, + createSignal, + ErrorBoundary, + For, + Show, +} from "solid-js"; +import { openDatabase } from "./data"; +import Graph from "./Graph"; + +type Unit = "kg" | "lb"; + +export default function Debug() { + const [database] = createResource(openDatabase); + + const [entries, { refetch }] = createResource(database, async (database) => { + const entries = await database.getAll("entries"); + + return entries; + }); + + async function handleSubmit( + event: SubmitEvent & { currentTarget: HTMLFormElement } + ) { + event.preventDefault(); + console.debug("handleSubmit", event); + + const input = event.currentTarget.elements.namedItem("weight"); + if (!(input instanceof HTMLInputElement)) + throw new Error("Expected input element"); + + const weight = input.valueAsNumber; + + const currentDatabase = database(); + console.debug("currentDatabase", currentDatabase); + const now = new Date(); + currentDatabase?.add( + "entries", + { + timestamp: now, + weight, + }, + now.getTime() + ); + event.currentTarget.reset(); + refetch(); + } + + async function remove(date: Date) { + const currentDatabase = database(); + if (!currentDatabase) throw new Error("Expected database to be ready"); + + currentDatabase.delete("entries", date.getTime()); + refetch(); + } + + const [unit, setUnit] = createSignal("kg"); + + function format(weight: number, unit: Unit) { + if (unit === "kg") return weight; + // If 1lb = 0.45_359_237kg + // Then divide both sides by 45359237 to get 1/45_359_237lb and 0.00_000_001kg + // Multiply both sides by 100_000_000 to get 2.2_046_226_218lbs = 1kg + // 1/45_359_237*100_000_000 + return weight * 2.2046226218; + } + + let weightInput: HTMLInputElement | undefined; + + createEffect(() => { + // Need to access unit here to register it as a effect dependency + const currentUnit = unit(); + if (!weightInput?.valueAsNumber) return; + weightInput.valueAsNumber = + currentUnit === "kg" + ? weightInput.valueAsNumber / 2.2046226218 + : weightInput.valueAsNumber * 2.2046226218; + }); + + return ( +
+

Debug

+ ( +
+

Error creating graph

+
+ Error +
{error.message}
+
{error}
+
+ +
+ )} + > + entries() ?? []} /> +
+
+ ); +} diff --git a/src/Graph.tsx b/src/Graph.tsx index 8faa5ba..51b1d18 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -36,6 +36,11 @@ type Range = { to: number; }; +type Ranges = { + x: Range; + y: Range; +}; + type Aggregation = { sums: { xSquared: number; @@ -43,13 +48,10 @@ type Aggregation = { x: number; y: number; }; - ranges?: { - x: Range; - y: Range; - }; + ranges?: Ranges; }; -function aggregate(entries: Entry[], xScope: Range): Aggregation { +function aggregate(entries: Entry[]): Aggregation { if (entries.length === 0) return { sums: { @@ -79,7 +81,10 @@ function aggregate(entries: Entry[], xScope: Range): Aggregation { }; for (const entry of entries) { - const x = entry.timestamp.getTime() - xScope.from / 1_000_000; + // const timeInRange = entry.timestamp.getTime() - xScope.from; + // // x in minutes + // const x = timeInRange / 1_000 / 60; + const x = entry.timestamp.getTime(); // If the timestamp is before the start of the month if (x < 0) continue; @@ -98,15 +103,12 @@ function aggregate(entries: Entry[], xScope: Range): Aggregation { return { sums, ranges }; } //TODO write tests for 1, 2, n inputs -function useTrendLine( - entries: Accessor, - xRange: Range -): { +function useTrendLine(entries: Accessor): { trendLine: Accessor; aggregation: Accessor; } { const n = () => entries().length; - const aggregation = () => aggregate(entries(), xRange); + const aggregation = () => aggregate(entries()); const slope = () => { const { sums } = aggregation(); @@ -125,28 +127,95 @@ function useTrendLine( const xAverage = () => aggregation().sums.x / n(); const yAverage = () => aggregation().sums.y / n(); - const yIntercept = () => { - console.debug("yIntercept", yAverage(), slope(), xAverage()); - return yAverage() - slope() * xAverage(); - }; + const yIntercept = () => yAverage() - slope() * xAverage(); const y = (x: number) => slope() * x + yIntercept(); const trendLine = (): TrendLine | undefined => { const { ranges } = aggregation(); - console.debug("trendLine RANGES", ranges, yIntercept()); if (ranges === undefined) return; return { x1: 0, x2: ranges.x.to, - y1: ranges.y.to - yIntercept(), - y2: ranges.y.to - y(ranges.x.to), + y1: yIntercept(), + y2: y(ranges.x.to), }; }; return { trendLine, aggregation }; } +type Point = { + x: number; + y: number; +}; + +function XAxisMarks({ height }: { height: number }) { + return ( + + {(x) => ( + + )} + + ); +} + +function YAxisMarks({ width }: { width: number }) { + return ( + + {(y) => ( + + )} + + ); +} + +// const adjustToSvgSpace = () => { +// const { x, y } = ranges(); +// const maxX = x.to; +// const maxY = y.to; + +// return (x: number, y: number) => { +// // Percent of the max value +// // Percent of the width +// x = (x / maxX) * width; +// y = (y / maxY) * height; + +// return [height - y, width - x]; +// }; +// }; + +function adjustToSvgSpace( + x: number, + y: number, + maxX: number, + maxY: number, + width: number, + height: number +) { + // Percent of the max value + // Percent of the width + x = (x / maxX) * width; + y = (y / maxY) * height; + + console.debug({ x, y, maxX, maxY, width, height }); + + return [height - y, width - x]; +} + export default function Graph({ entries }: Properties) { //TODO make range configurable // Need to curb time stamp or we get overflow @@ -155,65 +224,59 @@ export default function Graph({ entries }: Properties) { from: startOfMonth(now.getFullYear(), now.getMonth()).getTime(), to: Number.POSITIVE_INFINITY, }; - const { trendLine, aggregation } = useTrendLine(entries, xRange); + const { trendLine, aggregation } = useTrendLine(entries); + + const width = 100; + const height = 100; - createEffect(() => { - console.debug("trendLine", trendLine()); - }); + createEffect(() => console.debug("trendLine", trendLine())); return ( {(ranges) => { - //TODO don't use max for sizing SVG as it makes lines super thin and invisible. Use relative sizes instead - const maxX = () => ranges().x.to; - const maxY = () => ranges().y.to; + const adjust = (x: number, y: number) => { + const { x: xRange } = ranges(); + const relativeX = (x / xRange.to) * 100; + + return adjustToSvgSpace(relativeX, y, 100, 100, width, height); + }; return ( - - {/* Y markers */} - - {(y) => ( - - )} - - {/* X markers */} - - {(x) => ( - - )} - + + + - + {(trendLine) => { + const line = trendLine(); + const [x1, y1] = adjust(line.x1 as number, line.x2 as number); + const [x2, y2] = adjust(line.x2 as number, line.x2 as number); + return ( + + ); + }} - {(entry) => { + {({ weight, timestamp }) => { + const [x, y] = adjust(timestamp.getTime(), weight); return ( // TODO filter out values out of range ); }} + ); }} diff --git a/src/index.tsx b/src/index.tsx index 833cfc9..751c1c4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,5 +2,15 @@ import { render } from "solid-js/web"; import "./index.css"; import App from "./App.tsx"; +import { Route, Router } from "@solidjs/router"; +import Debug from "./Debug.tsx"; -render(() => , document.body); +render( + () => ( + + + + + ), + document.body +); -- 2.51.2