ERP-node/frontend/components/admin/dashboard/charts/DonutChartComponent.tsx

110 lines
2.9 KiB
TypeScript

'use client';
import React from 'react';
import {
PieChart,
Pie,
Cell,
Tooltip,
Legend,
ResponsiveContainer
} from 'recharts';
import { ChartConfig } from '../types';
interface DonutChartComponentProps {
data: any[];
config: ChartConfig;
width?: number;
height?: number;
}
/**
* 도넛 차트 컴포넌트
* - Recharts PieChart (innerRadius 사용) 사용
* - 비율 표시에 적합 (중앙 공간 활용 가능)
*/
export function DonutChartComponent({ data, config, width = 250, height = 200 }: DonutChartComponentProps) {
const {
xAxis = 'x',
yAxis = 'y',
colors = ['#3B82F6', '#EF4444', '#10B981', '#F59E0B', '#8B5CF6', '#EC4899'],
title,
showLegend = true
} = config;
// 파이 차트용 데이터 변환
const pieData = data.map(item => ({
name: String(item[xAxis] || ''),
value: typeof item[yAxis as string] === 'number' ? item[yAxis as string] : 0
}));
// 총합 계산
const total = pieData.reduce((sum, item) => sum + item.value, 0);
// 커스텀 라벨 (퍼센트 표시)
const renderLabel = (entry: any) => {
const percent = ((entry.value / total) * 100).toFixed(1);
return `${percent}%`;
};
return (
<div className="w-full h-full p-2 flex flex-col">
{title && (
<div className="text-center text-sm font-semibold text-gray-700 mb-2">
{title}
</div>
)}
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={pieData}
cx="50%"
cy="50%"
labelLine={false}
label={renderLabel}
outerRadius={80}
innerRadius={50}
fill="#8884d8"
dataKey="value"
>
{pieData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={colors[index % colors.length]} />
))}
</Pie>
<Tooltip
contentStyle={{
backgroundColor: 'white',
border: '1px solid #ccc',
borderRadius: '4px',
fontSize: '12px'
}}
formatter={(value: any) => [
typeof value === 'number' ? value.toLocaleString() : value,
'값'
]}
/>
{showLegend && (
<Legend
wrapperStyle={{ fontSize: '12px' }}
layout="vertical"
align="right"
verticalAlign="middle"
/>
)}
</PieChart>
</ResponsiveContainer>
{/* 중앙 총합 표시 */}
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 pointer-events-none">
<div className="text-center">
<div className="text-xs text-gray-500">Total</div>
<div className="text-sm font-bold text-gray-800">
{total.toLocaleString()}
</div>
</div>
</div>
</div>
);
}