88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
"use client"
|
|
|
|
import React, { useMemo } from "react"
|
|
import { LabelList, Pie, PieChart } from "recharts"
|
|
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card"
|
|
import {
|
|
ChartContainer,
|
|
ChartTooltip,
|
|
ChartTooltipContent,
|
|
type ChartConfig,
|
|
} from "@/components/ui/chart"
|
|
|
|
export const CustomPieChart = React.memo(function CustomPieChart({
|
|
title,
|
|
description,
|
|
data,
|
|
colorOffset = 0,
|
|
}: {
|
|
title: string
|
|
description: string
|
|
data: any[]
|
|
colorOffset?: number
|
|
}) {
|
|
const { config, chartData } = useMemo(() => {
|
|
const cfg: ChartConfig = {
|
|
total: { label: "Total" },
|
|
}
|
|
|
|
const formattedData = data.map((item, index) => {
|
|
const key = String(item.name).toLowerCase().replace(/[^a-z0-9]/g, '_')
|
|
|
|
// Generate distinct HSL color based on index and chart-level offset
|
|
// 137.5 is the golden angle, which distributes colors nicely
|
|
const hue = Math.floor((index * 137.5 + colorOffset) % 360)
|
|
|
|
cfg[key] = {
|
|
label: String(item.name),
|
|
color: `hsl(${hue}, 70%, 50%)`,
|
|
}
|
|
return {
|
|
...item,
|
|
fill: `var(--color-${key})`,
|
|
name: String(item.name),
|
|
}
|
|
})
|
|
return { config: cfg, chartData: formattedData }
|
|
}, [data, colorOffset])
|
|
|
|
return (
|
|
<Card className="flex flex-col">
|
|
<CardHeader className="items-center pb-0">
|
|
<CardTitle>{title}</CardTitle>
|
|
<CardDescription>{description}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="flex-1 pb-0">
|
|
<ChartContainer
|
|
config={config}
|
|
className="mx-auto aspect-square max-h-[250px] pb-0 [&_.recharts-pie-label-text]:fill-foreground [&_.recharts-wrapper]:outline-none [&_.recharts-surface]:outline-none"
|
|
>
|
|
<PieChart style={{ outline: "none" }}>
|
|
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
|
|
<Pie
|
|
data={chartData}
|
|
dataKey="total"
|
|
nameKey="name"
|
|
label
|
|
>
|
|
<LabelList
|
|
dataKey="name"
|
|
className="fill-background font-medium"
|
|
stroke="none"
|
|
fontSize={12}
|
|
/>
|
|
</Pie>
|
|
</PieChart>
|
|
</ChartContainer>
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
})
|