/* * @Author: ZhaoYing * @Date: 2026-02-10 13:35:45 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-16 11:34:30 */ /* * PieChart Component * * A reusable pie chart component built with ECharts that displays data distribution * in a donut chart format with customizable colors and responsive behavior. * * Features: * - Donut-style pie chart with percentage labels * - Customizable color palette * - Responsive resizing using ResizeObserver * - Hover tooltips showing percentage values * - Legend at the bottom with horizontal layout * - Empty state when no data is available * - Shadow effects for better visual depth */ import { type FC, useEffect, useRef } from 'react' import ReactEcharts from 'echarts-for-react'; import Empty from '@/components/Empty' /** Default color palette for pie chart segments */ const Colors = ['#171719', '#155EEF', '#4DA8FF', '#9C6FFF', '#ABEBFF', '#DFE4ED'] /** * Data structure for each pie chart segment * * @interface ChartData * @property {string} name - Label for the segment (displayed in legend) * @property {number} value - Numeric value for the segment (determines size) */ export interface ChartData { name: string; value: number; } /** * Props for the PieChart component * * @interface PieChartProps * @property {ChartData[]} chartData - Array of data points to display in the chart * @property {number} [height=260] - Height of the chart in pixels * @property {string[]} [colors] - Custom color array for chart segments (defaults to Colors) */ interface PieChartProps { chartData: ChartData[]; height?: number; colors?: string[]; itemGap?: number; seriesWidth?: number; seriesHeight?: number; seriesLabel?: boolean; seriesTop?: number; } /** * PieChart Component * * Renders a donut-style pie chart with percentage labels and legend. * Automatically resizes when container dimensions change. * * @param {PieChartProps} props - Component props * @returns {JSX.Element} Rendered pie chart or empty state * * @example * ```tsx * * ``` */ const PieChart: FC = ({ chartData, height = 260, seriesWidth = 182, seriesHeight = 182, colors = Colors, itemGap = 48, seriesLabel = true, seriesTop = 24, }) => { /** Reference to the ECharts instance for programmatic control */ const chartRef = useRef(null); /** Flag to prevent multiple simultaneous resize operations */ const resizeScheduledRef = useRef(false) /** * Set up responsive behavior using ResizeObserver * Resizes chart when parent container dimensions change */ useEffect(() => { const handleResize = () => { if (chartRef.current && !resizeScheduledRef.current) { resizeScheduledRef.current = true // Use requestAnimationFrame for smooth resize performance requestAnimationFrame(() => { chartRef.current?.getEchartsInstance().resize(); resizeScheduledRef.current = false }); } } const resizeObserver = new ResizeObserver(handleResize) const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement if (chartElement) { resizeObserver.observe(chartElement) } // Cleanup: disconnect observer when component unmounts return () => { resizeObserver.disconnect() } }, [chartData]) return (
{chartData && chartData.length > 0 ? : }
) } export default PieChart