"use client"; /** * 차트 서브타입 컴포넌트 * * Recharts 기반 막대/원형/라인 차트 * 컨테이너 크기가 너무 작으면 "차트 표시 불가" 메시지 */ import React from "react"; import { BarChart, Bar, PieChart, Pie, Cell, LineChart, Line, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer, CartesianGrid, } from "recharts"; import type { DashboardItem } from "../../types"; import { TEXT_ALIGN_CLASSES } from "../../types"; import { abbreviateNumber } from "../utils/formula"; // ===== Props ===== export interface ChartItemProps { item: DashboardItem; /** 차트에 표시할 데이터 행 */ rows: Record[]; /** 컨테이너 너비 (px) - 최소 크기 판단용 */ containerWidth: number; } // ===== 기본 색상 팔레트 ===== const DEFAULT_COLORS = [ "#6366f1", // indigo "#8b5cf6", // violet "#06b6d4", // cyan "#10b981", // emerald "#f59e0b", // amber "#ef4444", // rose "#ec4899", // pink "#14b8a6", // teal ]; // ===== 최소 표시 크기 ===== const MIN_CHART_WIDTH = 120; // ===== 메인 컴포넌트 ===== export function ChartItemComponent({ item, rows, containerWidth, }: ChartItemProps) { const { chartConfig, visibility, itemStyle } = item; const chartType = chartConfig?.chartType ?? "bar"; const colors = chartConfig?.colors?.length ? chartConfig.colors : DEFAULT_COLORS; const xKey = chartConfig?.xAxisColumn ?? "name"; const yKey = chartConfig?.yAxisColumn ?? "value"; // 라벨 정렬만 사용자 설정 const labelAlignClass = TEXT_ALIGN_CLASSES[itemStyle?.labelAlign ?? "center"]; // 컨테이너가 너무 작으면 메시지 표시 if (containerWidth < MIN_CHART_WIDTH) { return (
차트
); } // 데이터 없음 if (!rows.length) { return (
데이터 없음
); } // X축 라벨이 긴지 판정 (7자 이상이면 대각선) const hasLongLabels = rows.some( (r) => String(r[xKey] ?? "").length > 7 ); const xAxisTickProps = hasLongLabels ? { fontSize: 10, angle: -45, textAnchor: "end" as const } : { fontSize: 10 }; // 긴 라벨이 있으면 하단 여백 확보 const chartMargin = hasLongLabels ? { top: 5, right: 10, bottom: 40, left: 10 } : { top: 5, right: 10, bottom: 5, left: 10 }; return (
{/* 라벨 - 사용자 정렬 적용 */} {visibility.showLabel && (

{item.label}

)} {/* 차트 영역 */}
{chartType === "bar" ? ( []} margin={chartMargin}> abbreviateNumber(v)} /> ) : chartType === "line" ? ( []} margin={chartMargin}> abbreviateNumber(v)} /> 250} /> ) : ( /* pie - 카테고리명 + 값 라벨 표시 */ []} dataKey={yKey} nameKey={xKey} cx="50%" cy="50%" outerRadius={containerWidth > 400 ? "70%" : "80%"} label={ containerWidth > 250 ? ({ name, value, percent }: { name: string; value: number; percent: number }) => `${name} ${abbreviateNumber(value)} (${(percent * 100).toFixed(0)}%)` : false } labelLine={containerWidth > 250} > {rows.map((_, index) => ( ))} [abbreviateNumber(value), name]} /> {containerWidth > 300 && ( )} )}
); }