"use client"; /** * 게이지 서브타입 컴포넌트 * * SVG 기반 반원형 게이지 (외부 라이브러리 불필요) * min/max/target/current 표시, 달성률 구간별 색상 */ import React from "react"; import type { DashboardItem } from "../../types"; import { abbreviateNumber } from "../utils/formula"; // ===== Props ===== export interface GaugeItemProps { item: DashboardItem; data: number | null; /** 동적 목표값 (targetDataSource로 조회된 값) */ targetValue?: number | null; } // ===== 게이지 색상 판정 ===== function getGaugeColor( percentage: number, ranges?: { min: number; max: number; color: string }[] ): string { if (ranges?.length) { const match = ranges.find((r) => percentage >= r.min && percentage <= r.max); if (match) return match.color; } // 기본 색상 (달성률 기준) if (percentage >= 80) return "#10b981"; // emerald if (percentage >= 50) return "#f59e0b"; // amber return "#ef4444"; // rose } // ===== 메인 컴포넌트 ===== export function GaugeItemComponent({ item, data, targetValue, }: GaugeItemProps) { const { visibility, gaugeConfig } = item; const current = data ?? 0; const min = gaugeConfig?.min ?? 0; const max = gaugeConfig?.max ?? 100; const target = targetValue ?? gaugeConfig?.target ?? max; // 달성률 계산 (0~100) const range = max - min; const percentage = range > 0 ? Math.min(100, Math.max(0, ((current - min) / range) * 100)) : 0; const gaugeColor = getGaugeColor(percentage, gaugeConfig?.colorRanges); // SVG 반원 게이지 수치 const cx = 100; const cy = 90; const radius = 70; // 반원: 180도 -> percentage에 비례한 각도 const startAngle = Math.PI; // 180도 (왼쪽) const endAngle = Math.PI - (percentage / 100) * Math.PI; // 0도 (오른쪽) 방향 const startX = cx + radius * Math.cos(startAngle); const startY = cy - radius * Math.sin(startAngle); const endX = cx + radius * Math.cos(endAngle); const endY = cy - radius * Math.sin(endAngle); const largeArcFlag = percentage > 50 ? 1 : 0; return (
{/* 라벨 */} {visibility.showLabel && (

{item.label}

)} {/* 게이지 SVG - 높이/너비 모두 반응형 */}
{/* 배경 반원 (회색) */} {/* 값 반원 (색상) */} {percentage > 0 && ( )} {/* 중앙 텍스트 */} {visibility.showValue && ( {abbreviateNumber(current)} )} {/* 퍼센트 */} {percentage.toFixed(1)}%
{/* 목표값 */} {visibility.showTarget && (

목표: {abbreviateNumber(target)}

)}
); }