@@ -48,6 +48,7 @@ type LegendProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** 차트 기본 스타일 */
|
/** 차트 기본 스타일 */
|
||||||
|
/*
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
legendContainer: {
|
legendContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -58,6 +59,23 @@ const customStyles = {
|
|||||||
marginTop: "10px",
|
marginTop: "10px",
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 차트 기본 스타일 (라인차트와 동일하게) */
|
||||||
|
const customStyles = {
|
||||||
|
legendContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap", // 여러 줄로 자동 줄바꿈
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "12px", // 아이템 간 간격
|
||||||
|
fontSize: "13px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
marginTop: "16px",
|
||||||
|
marginBottom: "8px",
|
||||||
|
minHeight: "32px", // 범례 영역 높이 통일
|
||||||
|
} as CSSProperties,
|
||||||
|
};
|
||||||
|
|
||||||
// 커스텀 툴팁
|
// 커스텀 툴팁
|
||||||
const CustomTooltip = ({ active, payload, label }: {
|
const CustomTooltip = ({ active, payload, label }: {
|
||||||
@@ -82,6 +100,7 @@ const CustomTooltip = ({ active, payload, label }: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 커스텀 범례
|
// 커스텀 범례
|
||||||
|
/*
|
||||||
const CustomLegend = (props: LegendProps) => {
|
const CustomLegend = (props: LegendProps) => {
|
||||||
const { payload } = props;
|
const { payload } = props;
|
||||||
if (!payload) return null;
|
if (!payload) return null;
|
||||||
@@ -97,12 +116,52 @@ const CustomLegend = (props: LegendProps) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
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"
|
||||||
|
style={{
|
||||||
|
minWidth: "90px",
|
||||||
|
margin: "2px 0",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "14px",
|
||||||
|
height: "14px",
|
||||||
|
backgroundColor: entry.fill,
|
||||||
|
borderRadius: "3px",
|
||||||
|
marginRight: "8px",
|
||||||
|
minWidth: "14px",
|
||||||
|
minHeight: "14px",
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>
|
||||||
|
{entry.payload?.label || entry.value}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default function DoughnutChart(props: {
|
export default function DoughnutChart(props: {
|
||||||
chartConfig: any;
|
chartConfig: any;
|
||||||
chartData: ChartDataItem[] | undefined;
|
chartData: ChartDataItem[] | undefined;
|
||||||
chartTitle: string
|
chartTitle: string
|
||||||
}) {
|
}) {
|
||||||
|
const legendData = props.chartData?.map(item => ({
|
||||||
|
value: item.label,
|
||||||
|
fill: props.chartConfig?.[item.label]?.fill || 'blue',
|
||||||
|
})) ?? [];
|
||||||
return (
|
return (
|
||||||
<Card className="flex flex-col">
|
<Card className="flex flex-col">
|
||||||
<CardContent className="flex-1 pb-0">
|
<CardContent className="flex-1 pb-0">
|
||||||
@@ -130,9 +189,9 @@ export default function DoughnutChart(props: {
|
|||||||
nameKey="label"
|
nameKey="label"
|
||||||
innerRadius={60}
|
innerRadius={60}
|
||||||
/>
|
/>
|
||||||
<CustomLegend />
|
|
||||||
</PieChart>
|
</PieChart>
|
||||||
</ChartContainer>
|
</ChartContainer>
|
||||||
|
<CustomLegend payload={legendData} />
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type LineChartProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 차트 기본 스타일 */
|
/** 차트 기본 스타일 */
|
||||||
|
/*
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
legendContainer: {
|
legendContainer: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -28,6 +29,23 @@ const customStyles = {
|
|||||||
marginTop: "10px",
|
marginTop: "10px",
|
||||||
} as CSSProperties,
|
} as CSSProperties,
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 차트 기본 스타일 */
|
||||||
|
const customStyles = {
|
||||||
|
legendContainer: {
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "12px",
|
||||||
|
fontSize: "13px",
|
||||||
|
fontWeight: "normal",
|
||||||
|
marginTop: "16px",
|
||||||
|
marginBottom: "8px",
|
||||||
|
minHeight: "32px",
|
||||||
|
} as CSSProperties,
|
||||||
|
};
|
||||||
|
|
||||||
type LegendEntry = {
|
type LegendEntry = {
|
||||||
value: string;
|
value: string;
|
||||||
@@ -60,7 +78,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
|
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
|
||||||
const CustomLegend = (props: LegendProps) => {
|
/*const CustomLegend = (props: LegendProps) => {
|
||||||
const { payload } = props;
|
const { payload } = props;
|
||||||
if (!payload) return null;
|
if (!payload) return null;
|
||||||
|
|
||||||
@@ -74,6 +92,40 @@ const CustomLegend = (props: LegendProps) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
};*/
|
||||||
|
|
||||||
|
// 커스텀 범례 (도넛차트와 동일하게)
|
||||||
|
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"
|
||||||
|
style={{
|
||||||
|
minWidth: "90px",
|
||||||
|
margin: "2px 0",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "14px",
|
||||||
|
height: "14px",
|
||||||
|
backgroundColor: entry.color,
|
||||||
|
borderRadius: "3px",
|
||||||
|
marginRight: "8px",
|
||||||
|
minWidth: "14px",
|
||||||
|
minHeight: "14px",
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type DataType = {label: string; val: string};
|
type DataType = {label: string; val: string};
|
||||||
@@ -141,7 +193,7 @@ export default function Linechart({
|
|||||||
>
|
>
|
||||||
<CartesianGrid vertical={false} />
|
<CartesianGrid vertical={false} />
|
||||||
<XAxis dataKey="label" fontSize="8px" fontWeight="bold" />
|
<XAxis dataKey="label" fontSize="8px" fontWeight="bold" />
|
||||||
<YAxis yAxisId="left" className="text-[12px] font-bold" domain={[0, Math.ceil(lineMaxValue * 1.1)]} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
|
<YAxis yAxisId="left" className="text-[12px] font-bold" tickFormatter={(value) => value.toLocaleString()} tickCount={6} orientation="left" label={{ value: yFieldText, className:"text-[12px] font-bold", angle: -90, position: 'insideLeft' }} />
|
||||||
<Tooltip content={<CustomTooltip />} />
|
<Tooltip content={<CustomTooltip />} />
|
||||||
{showLegend && <Legend content={CustomLegend as ContentType}/>}
|
{showLegend && <Legend content={CustomLegend as ContentType}/>}
|
||||||
{Object.keys(chartData).map((key) => {
|
{Object.keys(chartData).map((key) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user