
Chart.js: HTML5 캔버스를 기반으로 한 데이터 시각화 라이브러리. 다양한 차트를 쉽게 생성할 수 있다.
react-chartjs-2: Chart.js를 React에서 사용할 수 있도록 래핑한 라이브러리
흐름
1. 차트 컴포넌트 - 리액트에서는react-chartjs-2로 컴포넌트로 차트를 그릴 수 있다.
2. register - 차트를 그리는 데에 필요한 것들은Chart.js에서 import하고 register 해야 한다.
3. 다양한 option - 다양한 옵션들을 사용하여 차트를 커스텀 할 수 있다.
react-chartjs-2를 통해 리액트에서 컴포넌트로 차트를 그릴 수 있다.
Line, Bar, Bubble 등 차트 종류 별로 컴포넌트 생성이 가능하다.
import { Line } from 'react-chartjs-2'
...
{/* tsx */}
<Line options={options} data={chartData} />
Chart 컴포넌트의 props로 data, options를 전달해줘야 한다.
data : 차트에 들어갈 데이터를 담고 있는 객체
data 객체 형태 예시
const labels = ['3월', '6월', '7월', '12월'] // y축 index
export const chartData = {
labels, // y축 index
datasets: [
{
label: '정산 가격', //그래프 분류되는 항목
data: [30, 100, 90, 200], //실제 그려지는 데이터(Y축 숫자)
borderColor: '#408249', //그래프 선 color
},
],
}
💠 labels(optional) : y축 index
💠 datasets : 데이터 관련 정보(값, 컬러, 라벨..)를 담은 dataset 객체들을 가지고 있는 배열이다. 한 차트에 다양한 데이터를 그릴 경우에는 이 배열에 객체를 추가해주면 된다.
💠 datasets의 data
data에 labels에 대치하는 값이 담긴 배열을 넣어준다.data 배열에 {x: .., y: ..}원소를 넣어준다. data: [
{ x: '3월', y: 30 },
{ x: '6월', y: 100 },
{ x: '7월', y: 90 },
{ x: '12월', y: 200 },
],
react-chartjs-2에서 import 해온 'Chart 컴포넌트'와는 별개로, Chart.js에서 필요한 것들을 import하고, register를 해야 차트를 렌더링 할 수 있다.
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
} from 'chart.js'
...
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend)
'Chart 컴포넌트'는 options prop을 통해 다양하게 차트를 커스텀할 수 있다. 정말 다양하기 때문에 내가 사용해본 옵션만 적어두었다.
options 객체 형태 예시
export const options = {
// 옵션 1️⃣
responsive: true,
// 옵션 2️⃣
plugins: {
legend: {
display: false,
// position: 'top' as const,
},
title: {
display: false,
text: '대시보드',
},
},
// 옵션 3️⃣
maintainAspectRatio: false, // 비율 유지 하지 않도록 설정
// 옵션 4️⃣
scales: {
x: {
offset: true,
grid: {
display: false,
},
},
y: {
border: {
display: false,
},
},
},
}
1️⃣ responsive : 부모 요소의 크기에 맞춰 자동으로 크기 조절하는 반응형 여부
2️⃣ plugins : 차트에 플러그인을 설정하는 객체
legend : 범례-차트의 한쪽에 위치하여 각 데이터 시리즈의 색상과 함께 해당 데이터의 이름을 나타낸다.3️⃣ maintainAspectRatio : 차트의 비율을 유지하도록 할 것인지에 대한 여부. 즉, false로 설정하면 차트가 부모 요소의 크기에 맞게 늘어나거나 줄어들 수 있다.
4️⃣ scales : 차트의 축(x축, y축)을 설정하는 객체
offset : x축의 시작 부분에 여백 추가 여부grid : 그리드 라인에 대한 설정. 즉, x축과 y축을 이어주는 그리드 라인 배경을 말하는 것이다.border : y축의 경계선 설정❗️ 반응형 차트를 만들기 위해 options의 responsive를 true로 바꿔주어도 다음과 같이 잘 되지 않는 모습을 확인할 수 있다.
✔️ 화면을 축소해도 대시보드만 축소되지 않는다.

✔️ 화면을 축소했다가 확대하면 대시보드의 height가 돌아오지 않는다. 즉, 확대된 height가 유지된다.

🙆🏻♀️ 해결방법
1. options의 responsive는 웬만하면 true로 두자.
그렇지 않으면 hover, 클릭 이벤트가 제대로 동작하지 못하는 경우가 생긴다.
2. options의 maintainAspectRatio를 false로 변경한다.
true인 경우에는 뷰포트가 달라지더라도 원래의 비율을 유지한 채 늘어나기 때문에
반응형인 경우 해당 옵션을 추가하면 비율이 아닌 부모의 크기에 맞춰 늘어나고 줄어든다.
export const options = {
...
maintainAspectRatio: false,
...
3. 2번을 통해 부모의 크기에 맞춰지도록 설정 하였으니 부모 컨테이너에 적절한 스타일링을 하자.
4. 당연히 자식 컨테이너에도 적절한 스타일링이 필요하다.
이때 canvas에 직접 스타일을 하는게 아니라 canvas를 div로 감싸고, 해당 div에 스타일을 적용해야 한다.
return (
<ParentContainer>
// ✅ 3. 부모 요소에 h-full 주기 (height: 100%)
<Flex className="h-full flex-col gap-3" direction="column" align="center">
{/* 헤더 */}
<Flex justify="between" className="w-full">
<span className="text-lg font-black">대시보드</span>
<Flex gap="4">
{/* 날짜별 기준 */}
<Select.Root onValueChange={onDateChange}>
<Select.Trigger placeholder="날짜별 기준" />
<Select.Content>
<Select.Item value="yesterday">어제</Select.Item>
<Select.Item value="recent-week">최근 7일간</Select.Item>
<Select.Item value="recent-month">최근 한 달간</Select.Item>
<Select.Item value="month">월간</Select.Item>
<Select.Item value="year">연간</Select.Item>
</Select.Content>
</Select.Root>
{/* 카테고리 */}
<Select.Root onValueChange={onCategoryChange}>
<Select.Trigger placeholder="카테고리" />
<Select.Content>
<Select.Item value="visitors">방문자 수</Select.Item>
<Select.Item value="product-clicks">상품 클릭 수</Select.Item>
<Select.Item value="orders">주문 건 수</Select.Item>
<Select.Item value="total-sale">총 할인 금액</Select.Item>
<Select.Item value="exchange">교환 건 수</Select.Item>
<Select.Item value="refunds">환불 건 수</Select.Item>
<Select.Item value="order-price">주문 금액</Select.Item>
</Select.Content>
</Select.Root>
</Flex>
</Flex>
{/* 대시보드 */}
// ✅ 4.
// 이때 부모 컨테이너의 빈 부분을 채우기 위해 grow를 사용한다.
// width에 적절한 값의 vw를 준다.
<div className="w-[35vw] grow">
<Line options={options} data={chartData} />
</div>
</Flex>
</ParentContainer>
)
}
export default Dashboard
이때 width에 왜 100%는 적용이 안되고, vw를 주어야 하는걸까?
❗️ 부모 요소가 고정되어 있지 않은데도 불구하고 자식 요소canvas를 감싸는 div에w-full을 주면 반응형이 되지 않는다.➡️ Responsive Charts: 반응형 차트 부분 공식문서에서도 vw, vh를 주고 있는 것을 확인할 수 있다.
나는 vw, vh 단위는 전체 화면의 큰 레이아웃 부분을 잡을 때만 사용해주고는 했다.
사실 정확히 왜 이렇게 작동하는지 알아내지는 못했지만, 이러한 외부 라이브러리를 사용할 때는 vw, vh 단위가 유용하게 쓰인다는 것을 알고 있으면 될 거 같다!
vw: 뷰포트 너비에 상대적인 단위로, 현재 뷰포트의 너비에 대한 백분율로 계산된다.
ex) 1vw는 현재 뷰포트 너비의 1%에 해당한다.
결과 화면

Chart.js 공식문서
react-chartjs-2 공식문서 not found
React에서 Chart.js 사용하기 (with TypeScript)