Wrap ThemedChart with convenient series-based API that transforms ChartSeries[] into the flat record format ThemedChart expects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
102 lines
2.3 KiB
TypeScript
102 lines
2.3 KiB
TypeScript
import { useMemo } from 'react'
|
|
import { Line, ReferenceLine } from 'recharts'
|
|
import { ThemedChart } from '../ThemedChart/ThemedChart'
|
|
import { CHART_COLORS } from '../../utils/rechartsTheme'
|
|
|
|
export interface DataPoint {
|
|
x: any
|
|
y: number
|
|
}
|
|
|
|
export interface ChartSeries {
|
|
label: string
|
|
data: DataPoint[]
|
|
color?: string
|
|
}
|
|
|
|
interface LineChartProps {
|
|
series: ChartSeries[]
|
|
height?: number
|
|
width?: number
|
|
yLabel?: string
|
|
xLabel?: string
|
|
threshold?: { value: number; label: string }
|
|
className?: string
|
|
}
|
|
|
|
function formatTime(d: Date): string {
|
|
const h = String(d.getHours()).padStart(2, '0')
|
|
const m = String(d.getMinutes()).padStart(2, '0')
|
|
return `${h}:${m}`
|
|
}
|
|
|
|
export function LineChart({
|
|
series,
|
|
height,
|
|
width,
|
|
yLabel,
|
|
xLabel,
|
|
threshold,
|
|
className,
|
|
}: LineChartProps) {
|
|
const { data, hasDateX } = useMemo(() => {
|
|
const map = new Map<string, Record<string, any>>()
|
|
let dateDetected = false
|
|
|
|
for (const s of series) {
|
|
for (const pt of s.data) {
|
|
const isDate = pt.x instanceof Date
|
|
if (isDate) dateDetected = true
|
|
const key = isDate ? pt.x.getTime().toString() : String(pt.x)
|
|
if (!map.has(key)) {
|
|
map.set(key, { _x: isDate ? formatTime(pt.x) : pt.x })
|
|
}
|
|
map.get(key)![s.label] = pt.y
|
|
}
|
|
}
|
|
|
|
return { data: Array.from(map.values()), hasDateX: dateDetected }
|
|
}, [series])
|
|
|
|
const chart = (
|
|
<ThemedChart
|
|
data={data}
|
|
height={height}
|
|
xDataKey="_x"
|
|
xType={hasDateX ? 'category' : 'category'}
|
|
xTickFormatter={hasDateX ? (v: any) => String(v) : undefined}
|
|
yLabel={yLabel}
|
|
className={className}
|
|
>
|
|
{series.map((s, i) => (
|
|
<Line
|
|
key={s.label}
|
|
type="monotone"
|
|
dataKey={s.label}
|
|
stroke={s.color ?? CHART_COLORS[i % CHART_COLORS.length]}
|
|
dot={false}
|
|
strokeWidth={1.5}
|
|
/>
|
|
))}
|
|
{threshold && (
|
|
<ReferenceLine
|
|
y={threshold.value}
|
|
stroke="var(--text-muted)"
|
|
strokeDasharray="4 4"
|
|
label={{
|
|
value: threshold.label,
|
|
position: 'insideTopRight',
|
|
style: { fontSize: 10, fill: 'var(--text-muted)' },
|
|
}}
|
|
/>
|
|
)}
|
|
</ThemedChart>
|
|
)
|
|
|
|
if (width) {
|
|
return <div style={{ width }}>{chart}</div>
|
|
}
|
|
|
|
return chart
|
|
}
|