Files
frontend/apps/st/src/components/statistics/management/PopulationStatusChart.tsx
T

120 lines
2.9 KiB
TypeScript

import { Chart } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarController,
BarElement,
LineController,
LineElement,
PointElement,
Title,
Tooltip,
Legend,
} from "chart.js";
import type { ChartOptions } from "chart.js";
ChartJS.register(
CategoryScale,
LinearScale,
BarController,
BarElement,
LineController,
LineElement,
PointElement,
Title,
Tooltip,
Legend,
);
// 차트 설정 외부 정의 (Mixed 타입 명시)
const options: ChartOptions<"bar" | "line"> = {
responsive: true,
maintainAspectRatio: false,
scales: {
x: { stacked: true },
y: {
stacked: true,
beginAtZero: true,
title: { display: true, text: "인구수(명)" },
},
y1: {
position: "right",
beginAtZero: true,
grid: { drawOnChartArea: false },
title: { display: true, text: "총 인구(명)" },
},
},
plugins: {
legend: { position: "bottom" },
},
};
export type PopulationChartData = {
X_AXIS: string[];
TOT: number[];
ORIGIN_MALE: (number | null)[];
ORIGIN_FEMALE: (number | null)[];
FOREIGN_MALE: (number | null)[];
FOREIGN_FEMALE: (number | null)[];
};
type Props = {
chartData: PopulationChartData | null;
};
const SERIES_META = [
{ key: "ORIGIN_MALE", name: "내국인 남성", color: "#3B82F6" },
{ key: "ORIGIN_FEMALE", name: "내국인 여성", color: "#EC4899" },
{ key: "FOREIGN_MALE", name: "외국인 남성", color: "#10B981" },
{ key: "FOREIGN_FEMALE", name: "외국인 여성", color: "#F59E0B" },
] as const;
const PopulationStatusChart = ({ chartData }: Props) => {
if (!chartData || chartData.X_AXIS.length === 0) {
return (
<div className="flex items-center justify-center h-full min-h-[40rem] w-full text-gray-400 text-[1.4rem] border border-gray-200 rounded">
조회된 데이터가 없습니다. 조회 버튼을 눌러주세요.
</div>
);
}
const data = {
labels: chartData.X_AXIS.map((yr) => `${yr}년`),
datasets: [
...SERIES_META
.filter((s) => chartData[s.key]?.some((v) => v !== null))
.map((s) => ({
type: "bar" as const,
label: s.name,
data: chartData[s.key].map((v) => v ?? 0),
backgroundColor: s.color,
stack: "stack1",
})),
{
type: "line" as const,
label: "총 인구",
data: chartData.TOT,
borderColor: "#1F2937",
backgroundColor: "#1F2937",
borderDash: [5, 5],
tension: 0.1,
yAxisID: "y1",
},
],
};
return (
<div className="h-full w-full border border-gray-200 rounded p-4">
{/* 제네릭 타입을 통해 Mixed Chart 지원, 부모 컨테이너 크기에 맞춰 반응형으로 리사이즈됨 */}
<Chart<"bar" | "line", (string | number)[], string>
type="bar"
data={data}
options={options}
/>
</div>
);
};
export default PopulationStatusChart;