dress/resources/js/components/charts/pie-chart.tsx

91 lines
2.8 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
} from "@/components/ui/chart"
import 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>
)
})