'use client';
import { LineChart, Line, YAxis, XAxis, CartesianGrid, Tooltip, Area, Label } from 'recharts';
import spacetime from 'spacetime';
import regression from 'regression';
import { PureComponent } from 'react';
class CustomizedAxisTick extends PureComponent {
render() {
const { x, y, stroke, payload } = this.props;
if (spacetime(payload.value).day() == 1) {
return (
{spacetime(payload.value).format('{date}')}
);
}
}
}
interface DataPoint {
id: string; // measurement.id
datetime: Date;
value: number;
unit: string;
};
function polynomialTrendline(data: DataPoint[], degree: number) {
// Map your data to the form required by regression-js: [x, y]
// Here we convert datetime to a numeric value (e.g., milliseconds since epoch)
const regressionData = data.map((dp, i) => [i, dp.value]) as [number, number][];
const result = regression.polynomial(regressionData, { order: degree });
// result.equation contains the polynomial coefficients,
// and result.predict(x) returns the predicted y for a given x value.
return result;
}
function formatXAxis(tickItem: [number, number]) {
return spacetime(tickItem).format('{date}');
}
function yAxisTicks(data: DataPoint[]) {
const bounds = data.map(dp => Math.round(dp.value)).sort().filter((_v, i, a) => i === 0 || i === a.length - 1);
const lowerBound = bounds[0] - (bounds[0] % 2);
const upperBound = bounds[1] + (2 - bounds[1] % 2);
// Create an array of ticks from lowerBound to upperBound in increments of 2
return Array.from({ length: (upperBound - lowerBound) / 2 + 1 }, (_, i) => lowerBound + 2 * i);
}
function xAxisTicks(data: DataPoint[]) {
const bounds = data.sort().filter((_v, i, a) => i === 0 || i === a.length - 1).map(dp => spacetime(dp.datetime));
// Create array from bounds[0] to bounds[1] showing only Mondays
const ticks = [];
let tick = bounds[0].startOf('week').add(1, 'day');
while (tick.isBefore(bounds[1])) {
ticks.push(tick.format('{date}'));
tick = tick.add(2, 'day');
}
console.log(ticks);
return ticks;
}
export default function TimeseriesChart({ data, timeseriesName }: { data: DataPoint[], timeseriesName: string }) {
const unit = data[0] ? data[0].unit : '';
const polyResult = polynomialTrendline(data, 1)// 2 for quadratic
const dataWithFit = (data.map((dp, i) => {
return {
datetime: dp.datetime,
value: dp.value,
smoothed: polyResult.predict(i)[1],
};
}));
return (
Trend: {(7 * polyResult.equation[0]).toFixed(1)} {unit}/week
`${spacetime(d).format("{month-short} {date}, {hour}{ampm}")}`}
labelStyle={{ color: 'white' }}
formatter={(value, name, props) => [value, name === 'smoothed' ? 'Trend' : timeseriesName]}
contentStyle={{ backgroundColor: 'hsl(var(--border))', color: 'black' }}
/>
}
interval={0}
// tickFormatter={formatXAxis}
/>
i === 0 || i === yAxisTicks(data).length - 1)}
allowDecimals={false}
ticks={yAxisTicks(data)} />
0 ? "red" : "green"} dot={false} />
);
}