diff --git a/frontend/components/admin/dashboard/charts/AreaChart.tsx b/frontend/components/admin/dashboard/charts/AreaChart.tsx
index 9304d406..cabc8f10 100644
--- a/frontend/components/admin/dashboard/charts/AreaChart.tsx
+++ b/frontend/components/admin/dashboard/charts/AreaChart.tsx
@@ -23,7 +23,7 @@ export function AreaChart({ data, config, width = 600, height = 400 }: AreaChart
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 60 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 60 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -221,17 +221,23 @@ export function AreaChart({ data, config, width = 600, height = 400 }: AreaChart
.text(config.yAxisLabel);
}
- // 범례
- if (config.showLegend !== false && data.datasets.length > 1) {
+ // 범례 (차트 하단 중앙)
+ if (config.showLegend !== false && data.datasets.length > 0) {
+ const legendItemWidth = 120;
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2;
+
const legend = svg
.append("g")
.attr("class", "legend")
- .attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
@@ -239,7 +245,7 @@ export function AreaChart({ data, config, width = 600, height = 400 }: AreaChart
.attr("opacity", config.areaOpacity !== undefined ? config.areaOpacity : 0.3)
.attr("rx", 3);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/BarChart.tsx b/frontend/components/admin/dashboard/charts/BarChart.tsx
index 3f619d05..4026802d 100644
--- a/frontend/components/admin/dashboard/charts/BarChart.tsx
+++ b/frontend/components/admin/dashboard/charts/BarChart.tsx
@@ -23,7 +23,7 @@ export function BarChart({ data, config, width = 600, height = 400 }: BarChartPr
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 60 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 60 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -196,24 +196,30 @@ export function BarChart({ data, config, width = 600, height = 400 }: BarChartPr
.text(config.yAxisLabel);
}
- // 범례
- if (config.showLegend !== false && data.datasets.length > 1) {
+ // 범례 (차트 하단 중앙)
+ if (config.showLegend !== false && data.datasets.length > 0) {
+ const legendItemWidth = 120; // 각 범례 항목의 너비
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2; // 중앙 정렬
+
const legend = svg
.append("g")
.attr("class", "legend")
- .attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", dataset.color || colors[i % colors.length])
.attr("rx", 3);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/ComboChart.tsx b/frontend/components/admin/dashboard/charts/ComboChart.tsx
index ce373d71..e3763784 100644
--- a/frontend/components/admin/dashboard/charts/ComboChart.tsx
+++ b/frontend/components/admin/dashboard/charts/ComboChart.tsx
@@ -25,7 +25,7 @@ export function ComboChart({ data, config, width = 600, height = 400 }: ComboCha
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 60 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 60 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -275,23 +275,32 @@ export function ComboChart({ data, config, width = 600, height = 400 }: ComboCha
.text(config.yAxisLabel);
}
- // 범례
+ // 범례 (차트 하단 중앙)
if (config.showLegend !== false && data.datasets.length > 0) {
- const legend = svg.append("g").attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ const legendItemWidth = 120;
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2;
+
+ const legend = svg
+ .append("g")
+ .attr("class", "legend")
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
// 범례 아이콘 (첫 번째는 사각형, 나머지는 라인)
if (i === 0) {
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", dataset.color || colors[i % colors.length])
.attr("rx", 3);
} else {
- legendRow
+ legendItem
.append("line")
.attr("x1", 0)
.attr("y1", 7)
@@ -300,7 +309,7 @@ export function ComboChart({ data, config, width = 600, height = 400 }: ComboCha
.attr("stroke", dataset.color || colors[i % colors.length])
.attr("stroke-width", 2);
- legendRow
+ legendItem
.append("circle")
.attr("cx", 7.5)
.attr("cy", 7)
@@ -308,7 +317,7 @@ export function ComboChart({ data, config, width = 600, height = 400 }: ComboCha
.attr("fill", dataset.color || colors[i % colors.length]);
}
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/ComboChartComponent.tsx b/frontend/components/admin/dashboard/charts/ComboChartComponent.tsx
index 6f11d0fe..c9c40bb2 100644
--- a/frontend/components/admin/dashboard/charts/ComboChartComponent.tsx
+++ b/frontend/components/admin/dashboard/charts/ComboChartComponent.tsx
@@ -59,7 +59,7 @@ export function ComboChartComponent({ data, config, width = 250, height = 200 }:
top: 5,
right: 30,
left: 20,
- bottom: 5,
+ bottom: 25,
}}
>
@@ -84,7 +84,7 @@ export function ComboChartComponent({ data, config, width = 250, height = 200 }:
name
]}
/>
- {showLegend && yKeys.length > 1 && (
+ {showLegend && (
diff --git a/frontend/components/admin/dashboard/charts/HorizontalBarChart.tsx b/frontend/components/admin/dashboard/charts/HorizontalBarChart.tsx
index 60fcb666..955a02c9 100644
--- a/frontend/components/admin/dashboard/charts/HorizontalBarChart.tsx
+++ b/frontend/components/admin/dashboard/charts/HorizontalBarChart.tsx
@@ -23,7 +23,7 @@ export function HorizontalBarChart({ data, config, width = 600, height = 400 }:
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 120 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 120 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -192,21 +192,30 @@ export function HorizontalBarChart({ data, config, width = 600, height = 400 }:
.text(config.yAxisLabel);
}
- // 범례
- if (config.showLegend !== false && data.datasets.length > 1) {
- const legend = svg.append("g").attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ // 범례 (차트 하단 중앙)
+ if (config.showLegend !== false && data.datasets.length > 0) {
+ const legendItemWidth = 120;
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2;
+
+ const legend = svg
+ .append("g")
+ .attr("class", "legend")
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", dataset.color || colors[i % colors.length])
.attr("rx", 3);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/LineChart.tsx b/frontend/components/admin/dashboard/charts/LineChart.tsx
index db4292a8..1d3c7a9a 100644
--- a/frontend/components/admin/dashboard/charts/LineChart.tsx
+++ b/frontend/components/admin/dashboard/charts/LineChart.tsx
@@ -23,7 +23,7 @@ export function LineChart({ data, config, width = 600, height = 400 }: LineChart
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 60 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 60 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -208,17 +208,23 @@ export function LineChart({ data, config, width = 600, height = 400 }: LineChart
.text(config.yAxisLabel);
}
- // 범례
- if (config.showLegend !== false && data.datasets.length > 1) {
+ // 범례 (차트 하단 중앙)
+ if (config.showLegend !== false && data.datasets.length > 0) {
+ const legendItemWidth = 120;
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2;
+
const legend = svg
.append("g")
.attr("class", "legend")
- .attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
- legendRow
+ legendItem
.append("line")
.attr("x1", 0)
.attr("y1", 7)
@@ -227,7 +233,7 @@ export function LineChart({ data, config, width = 600, height = 400 }: LineChart
.attr("stroke", dataset.color || colors[i % colors.length])
.attr("stroke-width", 3);
- legendRow
+ legendItem
.append("circle")
.attr("cx", 7.5)
.attr("cy", 7)
@@ -236,7 +242,7 @@ export function LineChart({ data, config, width = 600, height = 400 }: LineChart
.attr("stroke", "white")
.attr("stroke-width", 2);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/PieChart.tsx b/frontend/components/admin/dashboard/charts/PieChart.tsx
index f9ab4810..8afcb4c0 100644
--- a/frontend/components/admin/dashboard/charts/PieChart.tsx
+++ b/frontend/components/admin/dashboard/charts/PieChart.tsx
@@ -24,7 +24,7 @@ export function PieChart({ data, config, width = 500, height = 500, isDonut = fa
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 120, bottom: 40, left: 120 };
+ const margin = { top: 40, right: 150, bottom: 40, left: 120 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
const radius = Math.min(chartWidth, chartHeight) / 2;
@@ -136,28 +136,33 @@ export function PieChart({ data, config, width = 500, height = 500, isDonut = fa
.text(config.title);
}
- // 범례
+ // 범례 (차트 오른쪽, 세로 배치)
if (config.showLegend !== false) {
+ const legendX = width / 2 + radius + 30; // 차트 오른쪽
+ const legendY = (height - pieData.length * 25) / 2; // 세로 중앙 정렬
+
const legend = svg
.append("g")
.attr("class", "legend")
- .attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ .attr("transform", `translate(${legendX}, ${legendY})`);
pieData.forEach((d, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(0, ${i * 25})`);
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", colors[i % colors.length])
.attr("rx", 3);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
- .style("font-size", "12px")
+ .style("font-size", "11px")
.style("fill", "#333")
.text(`${d.label} (${d.value})`);
});
diff --git a/frontend/components/admin/dashboard/charts/StackedBarChart.tsx b/frontend/components/admin/dashboard/charts/StackedBarChart.tsx
index 1a18c622..8aed840a 100644
--- a/frontend/components/admin/dashboard/charts/StackedBarChart.tsx
+++ b/frontend/components/admin/dashboard/charts/StackedBarChart.tsx
@@ -23,7 +23,7 @@ export function StackedBarChart({ data, config, width = 600, height = 400 }: Sta
const svg = d3.select(svgRef.current);
svg.selectAll("*").remove();
- const margin = { top: 40, right: 80, bottom: 60, left: 60 };
+ const margin = { top: 40, right: 80, bottom: 80, left: 60 };
const chartWidth = width - margin.left - margin.right;
const chartHeight = height - margin.top - margin.bottom;
@@ -241,24 +241,30 @@ export function StackedBarChart({ data, config, width = 600, height = 400 }: Sta
.text(config.yAxisLabel);
}
- // 범례
+ // 범례 (차트 하단 중앙)
if (config.showLegend !== false) {
+ const legendItemWidth = 120;
+ const totalLegendWidth = data.datasets.length * legendItemWidth;
+ const legendStartX = (width - totalLegendWidth) / 2;
+
const legend = svg
.append("g")
.attr("class", "legend")
- .attr("transform", `translate(${width - margin.right + 10}, ${margin.top})`);
+ .attr("transform", `translate(${legendStartX}, ${height - 20})`);
data.datasets.forEach((dataset, i) => {
- const legendRow = legend.append("g").attr("transform", `translate(0, ${i * 25})`);
+ const legendItem = legend
+ .append("g")
+ .attr("transform", `translate(${i * legendItemWidth}, 0)`);
- legendRow
+ legendItem
.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", dataset.color || colors[i % colors.length])
.attr("rx", 3);
- legendRow
+ legendItem
.append("text")
.attr("x", 20)
.attr("y", 12)
diff --git a/frontend/components/admin/dashboard/charts/StackedBarChartComponent.tsx b/frontend/components/admin/dashboard/charts/StackedBarChartComponent.tsx
index a1115af5..5ddb7b85 100644
--- a/frontend/components/admin/dashboard/charts/StackedBarChartComponent.tsx
+++ b/frontend/components/admin/dashboard/charts/StackedBarChartComponent.tsx
@@ -54,7 +54,7 @@ export function StackedBarChartComponent({ data, config, width = 250, height = 2
top: 5,
right: 30,
left: 20,
- bottom: 5,
+ bottom: 25,
}}
>
@@ -79,7 +79,7 @@ export function StackedBarChartComponent({ data, config, width = 250, height = 2
name
]}
/>
- {showLegend && yKeys.length > 1 && (
+ {showLegend && (