diff --git a/packages/common/business_components/src/ui/chart/BarChart.tsx b/packages/common/business_components/src/ui/chart/BarChart.tsx index 1b75beb8b..b75bf373c 100644 --- a/packages/common/business_components/src/ui/chart/BarChart.tsx +++ b/packages/common/business_components/src/ui/chart/BarChart.tsx @@ -42,7 +42,7 @@ const CustomTooltip = ({ }>; label?: string; }) => { - if (active && payload && payload.length) {ㅇ + if (active && payload && payload.length) { return (

{label}

diff --git a/packages/common/business_components/src/ui/chart/LineBarChart.tsx b/packages/common/business_components/src/ui/chart/LineBarChart.tsx index 98f804abf..35d757619 100644 --- a/packages/common/business_components/src/ui/chart/LineBarChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineBarChart.tsx @@ -1,10 +1,6 @@ "use client" import type { CSSProperties } from "react"; import { Bar, CartesianGrid, ComposedChart, Legend, Line, Tooltip, XAxis, YAxis } from "recharts"; -import { - Card, - CardContent -} from "./lib/card"; import { ChartContainer, type ChartConfig @@ -23,20 +19,29 @@ const customStyles = { } as CSSProperties, }; +type LineBarChartProps = { + chartConfig: ChartConfig | undefined; + chartData: any[] | undefined; + chartTitle: string; + chartClassName?: string; + graphSize?: number; + yFieldText?: string; + showLegend?: boolean; +} + +type LegendEntry = { + value: string; + color: string; + type?: string; + payload?: unknown; +}; + +type LegendProps = { + payload?: LegendEntry[]; +}; + // 커스텀 툴팁 -const CustomTooltip = ({ - active, - payload, - label -}: { - active?: boolean; - payload?: Array<{ - name: string; - value: number; - color: string; - }>; - label?: string; -}) => { +const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: Array<{ name: string; value: number; color: string }>; label?: string }) => { if (active && payload && payload.length) { return (
@@ -55,11 +60,13 @@ const CustomTooltip = ({ }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -const CustomLegend = (props: any) => { +const CustomLegend = (props: LegendProps) => { const { payload } = props; + if (!payload) return null; + return (
- {payload.map((entry: any, index: number) => ( + {payload.map((entry: LegendEntry, index: number) => (
{entry.value} @@ -69,33 +76,66 @@ const CustomLegend = (props: any) => { ); }; -export default function LineBarchart(props: { chartConfig: ChartConfig; chartData: any[] | undefined; chartTitle:string }) { +export default function LineBarchart({ + chartConfig, + chartData, + chartTitle, + chartClassName = 'w-full h-full', + graphSize = 40, + yFieldText, + showLegend = true +}: LineBarChartProps) { + if (!chartData || chartData.length === 0) { + return
데이터가 없습니다.
; + } + + const barConfig = chartConfig?.barVal; + const lineConfig = chartConfig?.lineVal; + return ( - - - {props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? ( +
+ {chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
- {props.chartTitle} -
): null} -
- - - - - {/* 왼쪽 Y축: lineVal (정상) */} - - {/* 오른쪽 Y축: barVal (위에서 아래로 반전) */} - - } /> - - {/* 바 차트 (오른쪽 Y축 사용, 위에서 아래로) */} - - {/* 라인 차트 (왼쪽 Y축 사용) */} - - - + {chartTitle}
- - - ) + ) : null} +
+ + + + + {/* 왼쪽 Y축: lineVal */} + + {/* 오른쪽 Y축: barVal */} + + } /> + {showLegend && } + {/* 바 차트 (오른쪽 Y축 사용) */} + + {/* 라인 차트 (왼쪽 Y축 사용) */} + + + +
+
+ ); } \ No newline at end of file diff --git a/packages/common/business_components/src/ui/chart/LineChart.tsx b/packages/common/business_components/src/ui/chart/LineChart.tsx index c005efbdf..1679f8d45 100644 --- a/packages/common/business_components/src/ui/chart/LineChart.tsx +++ b/packages/common/business_components/src/ui/chart/LineChart.tsx @@ -1,35 +1,24 @@ "use client" import type { CSSProperties } from "react"; import { CartesianGrid, Legend, Line, LineChart, Tooltip, XAxis, YAxis } from "recharts"; -import { - Card, - CardContent -} from "./lib/card"; import { ChartContainer, type ChartConfig } from "./lib/chart"; +import type { ContentType } from "recharts/types/component/DefaultLegendContent"; + +type LineChartProps = { + chartConfig: ChartConfig | undefined; + chartData: ChartDataType | undefined; + chartTitle: string; + chartClassName?: string; + graphSize?: number; + yFieldText?: string; + showLegend?: boolean; +} /** 차트 기본 스타일 */ -const styles = { - tooltipDiv: { - borderRadius: "5px", - backgroundColor: "white", - padding: "10px", - boxShadow: "0px 2px 10px rgba(0,0,0,0.2)", - width: "180px", // 적절한 크기로 설정 - } as React.CSSProperties, - tooltipLabel: { - fontWeight: "bold", - fontSize: "12px", - marginBottom: "5px", - borderBottom: "1px solid #ddd", - paddingBottom: "3px", - } as React.CSSProperties, - tooltipText: { - fontSize: "11px", - fontWeight:"bold", - } as React.CSSProperties, +const customStyles = { legendContainer: { display: "flex", justifyContent: "center", @@ -39,29 +28,29 @@ const styles = { marginTop: "10px", } as CSSProperties, }; + +type LegendEntry = { + value: string; + color: string; + type?: string; + payload?: unknown; +}; + +type LegendProps = { + payload?: LegendEntry[]; +}; + // 커스텀 툴팁 -const CustomTooltip = ({ - active, - payload, - label -}: { - active?: boolean; - payload?: Array<{ - name: string; - value: number; - color: string; - }>; - label?: string; -}) => { +const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: Array<{ name: string; value: number; color: string }>; label?: string }) => { if (active && payload && payload.length) { return ( -
-

{label}

+
+

{label}

{payload.map((item, index) => (
{/* 색상 박스 추가 (범례 색상과 동일) */}
- {`${item.name}: ${item.value}`} + {` ${item.name} : ${item.value}`}
))}
@@ -71,60 +60,90 @@ const CustomTooltip = ({ }; // 커스텀 범례 (글씨 크기 키우기 + 스타일 추가) -const CustomLegend = (props: any) => { +const CustomLegend = (props: LegendProps) => { const { payload } = props; + if (!payload) return null; + return ( -
- {payload.map((entry, index) => ( -
-
- {entry.value} +
+ {payload.map((entry: LegendEntry, index: number) => ( +
+
+ {entry.value}
))}
); }; -type DataType = {label : string; val:number}; +type DataType = {label: string; val: string}; + type ChartDataType = { - chartData1: DataType[]; - chartData2: DataType[]; + [key: string]: DataType[]; }; -export default function Linechart(props: { chartConfig: ChartConfig; chartData: ChartDataType; chartTitle:string}) { - const mergedData = Object.values(props.chartData).reduce((acc, dataset) => { +export default function Linechart({ + chartConfig, + chartData, + chartTitle, + chartClassName = 'w-full h-full', + graphSize = 40, + yFieldText, + showLegend = true +}: LineChartProps) { + if(!chartData || Object.keys(chartData).length === 0){ + return
데이터가 없습니다.
+ } + + // 데이터 병합 및 변환 + const mergedData = Object.entries(chartData).reduce>((acc, [key, dataset]) => { dataset.forEach((entry, index) => { if (!acc[index]) { - acc[index] = { label: entry.label }; // label 추가 + acc[index] = { label: entry.label }; } - const key = Object.keys(props.chartData).find(k => props.chartData[k] === dataset); - if (key) acc[index][key] = entry.val; + acc[index][key] = parseFloat(entry.val); }); return acc; - }, [] as any[]); + }, []); return ( - - - {props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? ( +
+ {chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
- {props.chartTitle} -
): null} -
- - - - - - } /> - - {Object.keys(props.chartData).map((key, index) => ( - - ))} - - + {chartTitle}
- - - ) + ) : null} +
+ + + + + + } /> + {showLegend && } + {Object.keys(chartData).map((key) => { + const config = chartConfig?.[key]; + return ( + + ); + })} + + +
+
+ ); } \ No newline at end of file diff --git a/packages/common/business_components/src/ui/chart/index.tsx b/packages/common/business_components/src/ui/chart/index.tsx index 0ed410630..87cabc18a 100644 --- a/packages/common/business_components/src/ui/chart/index.tsx +++ b/packages/common/business_components/src/ui/chart/index.tsx @@ -37,7 +37,7 @@ function MainChart(props: MainChartProps) { ); } else if( props.chartForm == CHART_FORM.LINE ){ return ( - + ); } else if( props.chartForm == CHART_FORM.DN ){ @@ -47,7 +47,7 @@ function MainChart(props: MainChartProps) { ); } else if (props.chartForm == CHART_FORM.LINEBAR){ return ( - + ); }