Trim first and last sparkline data points to avoid partial bucket skew
All checks were successful
CI / build (push) Successful in 1m0s
CI / docker (push) Successful in 46s
CI / deploy (push) Successful in 32s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-13 18:38:49 +01:00
parent d1940b98e5
commit 868cf84c4e

View File

@@ -8,17 +8,20 @@ interface SparklineProps {
export function Sparkline({ data, color }: SparklineProps) { export function Sparkline({ data, color }: SparklineProps) {
const gradientId = useId(); const gradientId = useId();
// Drop first and last buckets — they are partial time windows and skew the trend
const trimmed = useMemo(() => (data.length > 4 ? data.slice(1, -1) : data), [data]);
const { linePath, fillPath } = useMemo(() => { const { linePath, fillPath } = useMemo(() => {
if (data.length < 2) return { linePath: '', fillPath: '' }; if (trimmed.length < 2) return { linePath: '', fillPath: '' };
const w = 200; const w = 200;
const h = 24; const h = 24;
const max = Math.max(...data); const max = Math.max(...trimmed);
const min = Math.min(...data); const min = Math.min(...trimmed);
const range = max - min || 1; const range = max - min || 1;
const step = w / (data.length - 1); const step = w / (trimmed.length - 1);
const points = data.map( const points = trimmed.map(
(v, i) => `${i * step},${h - ((v - min) / range) * (h - 2) - 1}`, (v, i) => `${i * step},${h - ((v - min) / range) * (h - 2) - 1}`,
); );
@@ -26,9 +29,9 @@ export function Sparkline({ data, color }: SparklineProps) {
linePath: points.join(' '), linePath: points.join(' '),
fillPath: `0,${h} ${points.join(' ')} ${w},${h}`, fillPath: `0,${h} ${points.join(' ')} ${w},${h}`,
}; };
}, [data]); }, [trimmed]);
if (data.length < 2) return null; if (trimmed.length < 2) return null;
return ( return (
<div style={{ marginTop: 10, height: 24 }}> <div style={{ marginTop: 10, height: 24 }}>