Merge commit 'b00e5c48435a3507ad24cf5c8fab12f1d86e5ced' into iipbs/wr/form_fuction
This commit is contained in:
@@ -1,27 +1,116 @@
|
||||
"use client"
|
||||
|
||||
import { Pie, PieChart } from "recharts";
|
||||
|
||||
import type { CSSProperties } from "react";
|
||||
import {
|
||||
Card,
|
||||
CardContent
|
||||
} from "./lib/card";
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig
|
||||
} from "./lib/chart";
|
||||
import { ChartContainer, ChartTooltip } from "./lib/chart";
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
export default (props: { chartConfig: ChartConfig; chartData: never[] | undefined; chartTitle:string}) =>{
|
||||
type ChartDataItem = {
|
||||
label: string;
|
||||
val: number;
|
||||
};
|
||||
|
||||
type ChartConfigItem = {
|
||||
label: string;
|
||||
fill: string;
|
||||
};
|
||||
|
||||
type ChartConfig = {
|
||||
[key: string]: ChartConfigItem;
|
||||
};
|
||||
|
||||
type TooltipPayloadItem = {
|
||||
name: string;
|
||||
value: number;
|
||||
payload: {
|
||||
label: string;
|
||||
val: number;
|
||||
fill: string;
|
||||
};
|
||||
};
|
||||
|
||||
type LegendEntry = {
|
||||
value: string;
|
||||
fill: string;
|
||||
type?: string;
|
||||
payload: {
|
||||
label: string;
|
||||
val: number;
|
||||
fill: string;
|
||||
};
|
||||
};
|
||||
|
||||
type LegendProps = {
|
||||
payload?: LegendEntry[];
|
||||
};
|
||||
|
||||
/** 차트 기본 스타일 */
|
||||
const customStyles = {
|
||||
legendContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
gap: "20px",
|
||||
fontSize: "9px",
|
||||
fontWeight: "bold",
|
||||
marginTop: "10px",
|
||||
} as CSSProperties,
|
||||
};
|
||||
|
||||
// 커스텀 툴팁
|
||||
const CustomTooltip = ({ active, payload, label }: {
|
||||
active?: boolean;
|
||||
payload?: TooltipPayloadItem[];
|
||||
label?: string
|
||||
}) => {
|
||||
if (active && payload && payload.length) {
|
||||
return (
|
||||
<div className="w-[180px] rounded bg-white p-2.5 shadow-[0px_2px_10px_rgba(0,0,0,0.2)]">
|
||||
<p className="text-[12px] font-bold m-3">{label}</p>
|
||||
{payload.map((item, index) => (
|
||||
<div key={index} style={{ marginTop: "10px", display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<div style={{ width: "10px", height: "10px", backgroundColor: item.payload.fill, borderRadius: "50%" }}></div>
|
||||
<span className="text-[11px] font-bold">{` ${item.name} : ${item.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// 커스텀 범례
|
||||
const CustomLegend = (props: LegendProps) => {
|
||||
const { payload } = props;
|
||||
if (!payload) return null;
|
||||
|
||||
return (
|
||||
<div style={customStyles.legendContainer}>
|
||||
{payload.map((entry: LegendEntry, index: number) => (
|
||||
<div key={`legend-${index}`} className="flex items-center gap-2">
|
||||
<div className="w-[14px] h-[14px] ml-10" style={{ backgroundColor: entry.fill }}></div>
|
||||
<span className="text-[12px]">{entry.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function DoughnutChart(props: {
|
||||
chartConfig: ChartConfig;
|
||||
chartData: ChartDataItem[] | undefined;
|
||||
chartTitle: string
|
||||
}) {
|
||||
return (
|
||||
<Card className="flex flex-col">
|
||||
<CardContent className="flex-1 pb-0">
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>): null}
|
||||
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
|
||||
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
|
||||
{props.chartTitle}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="h-[calc(100%-42px)] justify-center">
|
||||
<ChartContainer
|
||||
config={props.chartConfig}
|
||||
@@ -30,18 +119,22 @@ export default (props: { chartConfig: ChartConfig; chartData: never[] | undefine
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
content={<CustomTooltip />}
|
||||
/>
|
||||
<Pie
|
||||
data={props.chartData}
|
||||
data={props.chartData?.map(item => ({
|
||||
...item,
|
||||
fill: props.chartConfig[item.label]?.fill || 'blue'
|
||||
}))}
|
||||
dataKey="val"
|
||||
nameKey="label"
|
||||
innerRadius={60}
|
||||
/>
|
||||
<CustomLegend />
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -92,9 +92,6 @@ export default function LineBarchart({
|
||||
return <div>데이터가 없습니다.</div>;
|
||||
}
|
||||
|
||||
const barConfig = chartConfig?.barVal;
|
||||
const lineConfig = chartConfig?.lineVal;
|
||||
|
||||
// 데이터의 최대값 계산
|
||||
const getMaxValue = (data: any[], keyPrefix: string) => {
|
||||
return Math.max(...data.map(item =>
|
||||
|
||||
Reference in New Issue
Block a user