diff --git a/src/App.tsx b/src/App.tsx index 67dccb7..95660b7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -87,7 +87,7 @@ export default function App() {

Error creating graph

Error -
{error.message}
+
{error.message}
{error}
diff --git a/src/Graph.tsx b/src/Graph.tsx index ea51bf7..8faa5ba 100644 --- a/src/Graph.tsx +++ b/src/Graph.tsx @@ -1,4 +1,4 @@ -import { createEffect, For, from, type Accessor, type JSX } from "solid-js"; +import { createEffect, For, Show, type Accessor, type JSX } from "solid-js"; import type { Entry } from "./data"; function* repeat(times: number) { @@ -43,13 +43,23 @@ type Aggregation = { x: number; y: number; }; - ranges: { + ranges?: { x: Range; y: Range; }; }; function aggregate(entries: Entry[], xScope: Range): Aggregation { + if (entries.length === 0) + return { + sums: { + xSquared: 0, + xTimesY: 0, + x: 0, + y: 0, + }, + }; + const sums = { xSquared: 0, xTimesY: 0, @@ -59,17 +69,18 @@ function aggregate(entries: Entry[], xScope: Range): Aggregation { const ranges = { x: { - from: Number.NEGATIVE_INFINITY, - to: Number.POSITIVE_INFINITY, + from: 0, + to: 0, }, y: { - from: Number.NEGATIVE_INFINITY, - to: Number.POSITIVE_INFINITY, + from: 0, + to: 0, }, }; for (const entry of entries) { - const x = entry.timestamp.getTime() - xScope.from; + const x = entry.timestamp.getTime() - xScope.from / 1_000_000; + // If the timestamp is before the start of the month if (x < 0) continue; @@ -86,12 +97,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 ): { - trendLine: Accessor; + trendLine: Accessor; aggregation: Accessor; } { const n = () => entries().length; @@ -99,20 +110,32 @@ function useTrendLine( const slope = () => { const { sums } = aggregation(); - const dividend = n() * sums.xTimesY - sums.x * sums.y; - const divisor = n() * sums.xSquared - sums.x * sums.x; + const currentN = n(); + if (currentN === 0) return 0; + + const dividend = currentN * sums.xTimesY - sums.x * sums.y; + if (dividend === 0) return 0; + + const divisor = currentN * sums.xSquared - sums.x * sums.x; + if (divisor === 0) return Infinity; + return dividend / divisor; }; const xAverage = () => aggregation().sums.x / n(); const yAverage = () => aggregation().sums.y / n(); - const yIntercept = () => yAverage() - slope() * xAverage(); + const yIntercept = () => { + console.debug("yIntercept", yAverage(), slope(), xAverage()); + return yAverage() - slope() * xAverage(); + }; const y = (x: number) => slope() * x + yIntercept(); - const trendLine = (): TrendLine => { + const trendLine = (): TrendLine | undefined => { const { ranges } = aggregation(); + console.debug("trendLine RANGES", ranges, yIntercept()); + if (ranges === undefined) return; return { x1: 0, x2: ranges.x.to, @@ -138,53 +161,62 @@ export default function Graph({ entries }: Properties) { console.debug("trendLine", trendLine()); }); - const maxX = () => aggregation().ranges.x.to; - const maxY = () => aggregation().ranges.y.to; return ( - - {/* Y markers */} - - {(y) => ( - - )} - - {/* X markers */} - - {(x) => ( - - )} - - - - {(entry) => { - return ( - // TODO filter out values out of range - - ); - }} - - + + {(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; + return ( + + {/* Y markers */} + + {(y) => ( + + )} + + {/* X markers */} + + {(x) => ( + + )} + + + + + + {(entry) => { + return ( + // TODO filter out values out of range + + ); + }} + + + ); + }} + ); }