Files
dyolink/frontend/src/components/today/TodayBarChart.tsx

119 lines
3.4 KiB
TypeScript

'use client';
import {
Bar,
BarChart,
CartesianGrid,
Cell,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import type { TodayChartBucket } from '@/types/today';
import { TodayChartFrame } from '@/components/today/TodayChartFrame';
import {
TODAY_CHART_AXIS_COLOR,
TODAY_CHART_COLORS,
TODAY_CHART_GRID_COLOR,
TODAY_CHART_TOOLTIP_BG,
TODAY_CHART_TOOLTIP_BORDER,
} from '@/components/today/chart-theme';
interface TodayBarChartProps {
data: TodayChartBucket[];
colorForCode?: (code: string, index: number) => string;
}
export function TodayBarChart({ data, colorForCode }: TodayBarChartProps) {
const chartData = data.map((item) => ({
...item,
shortLabel: truncateLabel(item.label),
}));
return (
<TodayChartFrame>
<ResponsiveContainer width="100%" height="100%">
<BarChart
data={chartData}
margin={{ top: 8, right: 8, left: -12, bottom: 0 }}
>
<CartesianGrid stroke={TODAY_CHART_GRID_COLOR} vertical={false} />
<XAxis
dataKey="shortLabel"
tick={
colorForCode
? (props) => {
const { x, y, payload } = props as {
x: number;
y: number;
payload: { value: string };
};
const index = chartData.findIndex((row) => row.shortLabel === payload.value);
const entry = chartData[index];
const fill =
entry != null
? colorForCode(entry.code, index >= 0 ? index : 0)
: TODAY_CHART_AXIS_COLOR;
return (
<text
x={x}
y={y}
dy={16}
textAnchor="middle"
fill={fill}
fontSize={11}
>
{payload.value}
</text>
);
}
: { fill: TODAY_CHART_AXIS_COLOR, fontSize: 11 }
}
axisLine={{ stroke: TODAY_CHART_GRID_COLOR }}
tickLine={false}
interval={0}
/>
<YAxis
allowDecimals={false}
tick={{ fill: TODAY_CHART_AXIS_COLOR, fontSize: 11 }}
axisLine={false}
tickLine={false}
width={32}
/>
<Tooltip
cursor={{ fill: 'rgba(0, 188, 255, 0.08)' }}
contentStyle={{
backgroundColor: TODAY_CHART_TOOLTIP_BG,
border: `1px solid ${TODAY_CHART_TOOLTIP_BORDER}`,
borderRadius: '6px',
color: '#f5f9ff',
fontSize: '12px',
}}
labelFormatter={(_, payload) => {
const row = payload?.[0]?.payload as TodayChartBucket | undefined;
return row?.label ?? '';
}}
/>
<Bar dataKey="count" radius={[4, 4, 0, 0]} maxBarSize={48}>
{chartData.map((entry, index) => (
<Cell
key={entry.code}
fill={
colorForCode?.(entry.code, index) ??
TODAY_CHART_COLORS[index % TODAY_CHART_COLORS.length]
}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</TodayChartFrame>
);
}
function truncateLabel(label: string, max = 12): string {
if (label.length <= max) return label;
return `${label.slice(0, max - 1)}`;
}