"use client" import { useMemo, useState } from "react" interface SimpleBarChartProps { data: Record[] dataKey: string xAxisKey: string fill?: string height?: number } export function SimpleBarChart({ data, dataKey, xAxisKey, fill = "#f59e0b", height = 250, }: SimpleBarChartProps) { const [tooltip, setTooltip] = useState<{ x: number y: number label: string value: number } | null>(null) const padding = { top: 20, right: 20, bottom: 40, left: 50 } const chartWidth = 600 const chartHeight = height const innerWidth = chartWidth - padding.left - padding.right const innerHeight = chartHeight - padding.top - padding.bottom const { bars, xLabels, yLabels } = useMemo(() => { if (data.length === 0) return { bars: [], xLabels: [], yLabels: [] } const values = data.map(d => Number(d[dataKey]) || 0) const maxVal = Math.max(...values, 1) const yMax = Math.ceil(maxVal * 1.2) const barCount = data.length const barGap = barCount > 1 ? (innerWidth * 0.1) / (barCount - 1) : 0 const totalGap = barGap * (barCount - 1) const barWidth = Math.min((innerWidth - totalGap) / barCount, 50) const startX = padding.left + (innerWidth - (barWidth * barCount + totalGap)) / 2 const brs = data.map((d, i) => { const val = Number(d[dataKey]) || 0 const barHeight = (val / yMax) * innerHeight return { x: startX + i * (barWidth + barGap), y: padding.top + innerHeight - barHeight, width: barWidth, height: barHeight, label: String(d[xAxisKey] ?? ""), value: val, } }) const xLbls = brs.map(b => ({ x: b.x + b.width / 2, label: b.label, })) const yTickCount = 5 const yLbls = Array.from({ length: yTickCount + 1 }, (_, i) => { const val = Math.round((yMax / yTickCount) * i) return { y: padding.top + innerHeight - (val / yMax) * innerHeight, label: String(val), } }) return { bars: brs, xLabels: xLbls, yLabels: yLbls } }, [data, dataKey, xAxisKey, innerWidth, innerHeight]) if (data.length === 0) { return (
暂无数据
) } return (
{yLabels.map(yl => ( {yl.label} ))} {bars.map((bar, i) => ( setTooltip({ x: bar.x + bar.width / 2, y: bar.y, label: bar.label, value: bar.value, }) } onMouseLeave={() => setTooltip(null)} /> ))} {xLabels.map((xl, i) => i % Math.ceil(xLabels.length / 10) === 0 || i === xLabels.length - 1 ? ( {xl.label} ) : null, )} {tooltip && (
{tooltip.label}
{tooltip.value}
)}
) }