드디어 chart.js를 적용해보았다.
이미 기본 스타일, 애니메이션이 적용되어 있어 너무 만족스럽게 적용하였다.
다른 프로젝트에 적용할 땐 헤매지 않도록 말끔하게 정리해보자.
1. 터미널에서 chart.js 다운받기
npm install chart.js react-chartjs-2
2. ChartComponent.js 컴포넌트 작성하기
나는 제목, Bar, Grid 스타일을 수정했다. return은 Bar 태그에 props만 전달하면 되었기에 매우 간단하다.
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
ChartOptions,
} from "chart.js";
import { Bar } from "react-chartjs-2";
import * as m from "../styles/mainStyle";
interface ChartComponentProps {
incomeData: number[];
spendData: number[];
selectedYear: number;
}
const ChartComponent: React.FC<ChartComponentProps> = ({
incomeData,
spendData,
selectedYear,
}) => {
console.log(incomeData, spendData, selectedYear);
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend
);
const options: ChartOptions<"bar"> = {
responsive: true,
plugins: {
legend: {
position: "top",
labels: {
color: "#000000",
font: {
size: 16,
},
},
},
title: {
display: true,
text: `${selectedYear}년 한 눈에 알아보기`,
font: {
family: "Noto Sans KR",
size: 20,
weight: 400,
},
color: "#000000",
},
},
layout: {
padding: 10,
},
scales: {
x: {
grid: {
display: false,
},
ticks: {
color: "#000000",
font: {
size: 15,
},
},
},
y: {
grid: {
display: true,
color: "rgba(224, 229, 253, 0.7)",
},
ticks: {
color: "#000000",
font: {
size: 15,
},
},
},
},
};
const labels = [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월",
"7월",
"8월",
"9월",
"10월",
"11월",
"12월",
];
const data = {
labels,
datasets: [
{
label: "수입",
data: incomeData,
backgroundColor: "rgba(67, 30, 245, 0.4)",
borderColor: "#431ef5",
borderWidth: 1.5,
borderRadius: 6,
},
{
label: "지출",
data: spendData,
backgroundColor: "rgba(235, 1, 48, 0.4)",
borderColor: "#EB0130",
borderWidth: 1.5,
borderRadius: 6,
},
],
};
return (
<m.ChartContainer>
<div className="contentWrap">
<div className="contentInner">
<Bar options={options} data={data} />
</div>
</div>
</m.ChartContainer>
);
};
export default ChartComponent;
3. 전달 props 코드 작성하기
년도별로 선택했을 때, 월별 수입/지출 총 금액이 표기되길 원했기에 기존 report 데이터를 변형해야했다.
incomeReports와 spendReports가 supabase에서 꺼내와 Redux store에서 가져오는 것이라,
2번씩 호출되는게 비효율적으로 느껴진다.
추후 테이블을 수정해서 1번씩만 불러올 수 있게끔 수정해보아야겠다.
// 년도별 reports 반환
const filterReportsByYear = (reports: Report[]) => {
return reports.filter((report) => {
const reportDate = new Date(report.date);
return reportDate.getFullYear() === selectedYear;
});
};
// 월별 총 수입/지출
const getMonthTotals = (reports: Report[]) => {
const monthTotal: { [key: number]: number } = {};
reports.forEach((report) => {
const date = new Date(report.date);
const month = date.getMonth() + 1;
if (!monthTotal[month]) {
monthTotal[month] = 0;
}
monthTotal[month] += report.amount;
});
return Array.from({ length: 12 }, (_, i) => monthTotal[i + 1] || 0);
};
const filterIncomeData = filterReportsByYear(incomeReports);
const filterSpendData = filterReportsByYear(spendReports);
const incomeData = getMonthTotals(filterIncomeData);
const spendData = getMonthTotals(filterSpendData);
<ChartComponent
incomeData={incomeData}
spendData={spendData}
selectedYear={selectedYear}
/>
장점 가득한 라이브러리였는데, 하나의 단점을 뽑자면 즉각 반응형이 아니라는거.
다른 블로그 몇개를 보아하니 다들 같은 현상을 경험했다.
responsive: true,
이걸 false 처리하고, 직접 컨트롤하는 방법이 있다고는 하지만 그럼 다른 요소들도 수정을 해야하기에..