이번에는 ChartJS 의 options 를 활용하여 차트를 이쁘게 꾸며보겠다.
먼저 options 에 대한 설명을 주석으로 달아보겠다.
const options = {
// 기본 설정
spanGaps: true, // 데이터가 중간중간 없을 때 이어 그릴지의 여부
grouped: true, // x축 값이 같은 것끼리 묶일지의 여부 (주로 Line Chart에서)
responsive: true, // canvas의 반응형 여부
maintainAspectRatio: false, // 캔버스의 가로세로 비율 유지 여부
// 차트 크기 설정
aspectRatio: 2, // maintainAspectRatio가 true일 때 사용되는 비율
// 애니메이션 설정
animation: {
duration: 1000, // 애니메이션 지속 시간 (밀리초)
easing: 'easeInOutQuart', // 이징 함수 설정
delay: (context) => context.dataIndex * 100, // 각 데이터 포인트별 딜레이
mode: 'linear', // 애니메이션 모드
},
// 인터랙션 설정
interaction: {
mode: 'index' as const, // 같은 선상(index)에 있는 값들 툴팁 다 보여줌
// mode: 'point' as const, // 특정 지점에 마우스를 호버하였을 때, 해당 툴팁 보여줌
axis: 'x' as const, // mode가 index일 때, 같은 선상이 x축인지 y축인지
intersect: false, // 교차 지점에서만 상호작용할지 여부
},
// 호버 설정
hover: {
mode: 'nearest',
intersect: true,
animationDuration: 400,
},
plugins: {
// 범례(Legend) 설정
legend: {
display: true, // legend 표시 여부
position: 'top' as const, // 'top'|'left'|'bottom'|'right'
align: 'center' as const, // 'start'|'center'|'end'
labels: {
padding: 10,
boxWidth: 13,
color: '#000',
usePointStyle: true, // 포인트 스타일 사용 여부
pointStyle: 'circle', // circle, cross, dash, line, rect, star, triangle
font: {
family: 'Noto Sans KR',
size: 12,
lineHeight: 2,
weight: 'normal',
},
generateLabels: (chart) => {
// 커스텀 레이블 생성 로직
return [];
},
},
onClick: (e, legendItem, legend) => {
// 범례 클릭 이벤트 핸들러
},
},
// 툴팁 설정
tooltip: {
enabled: true, // 툴팁 표시 여부
reverse: true, // 반대로 보일건지 여부
padding: 20,
caretPadding: 10,
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'rgba(0, 0, 0, 0.1)',
borderWidth: 1,
font: {
family: "'Noto Sans KR', sans-serif" as const,
size: 14,
},
titleMarginBottom: 10,
titleSpacing: 10,
bodySpacing: 10,
filter: (item: { parsed: any }) => item.parsed.y !== null,
// 툴팁에 보여질 데이터를 필터링해줌. 위 코드는 null인 값은 보이지 않게 함
usePointStyle: false,
callbacks: {
beforeTitle: (tooltipItems) => {
// 타이틀 이전에 표시될 내용
return '';
},
title: (tooltipItems) => {
// 타이틀 커스터마이징
return tooltipItems[0].label;
},
label: (context: any) => {
if (context.parsed.y === 0) {
return ' ' + context.dataset.label + ' -건';
}
return ' ' + context.dataset.label + ' ' + context.parsed.y + '건';
},
afterLabel: (tooltipItem) => {
// 라벨 이후에 표시될 내용
return '';
},
},
events: ['click'], // 이벤트 발생 여부에 대해서 컨트롤 가능
},
// 타이틀 설정
title: {
display: true,
text: '차트 제목',
position: 'top', // 'top', 'bottom', 'left', 'right'
align: 'center', // 'start', 'center', 'end'
color: '#666',
font: {
family: 'Noto Sans KR',
size: 16,
weight: 'bold',
},
padding: {
top: 10,
bottom: 10,
},
},
},
// 스케일 설정
scales: {
x: {
axis: 'x',
display: true, // 축 표시 여부
position: 'bottom', // 축의 위치
offset: true, // 오프셋 적용 여부
grid: {
display: true, // 그리드 표시 여부
color: '#ddd', // 그리드 색상
lineWidth: 1, // 그리드 굵기
drawBorder: true, // 테두리 그리기
drawOnChartArea: true, // 차트 영역에 그리기
drawTicks: true, // 틱 마크 그리기
borderDash: [], // 점선 설정
borderDashOffset: 0,
},
afterDataLimits: (scale: { max: number }) => {
scale.max = scale.max * 1;
// 정해진 범위만큼 보일건지, 그 이상으로 넓혀지게 보일건지
},
title: {
display: false,
align: 'end' as const,
color: '#808080',
font: {
size: 12,
family: "'Noto Sans KR', sans-serif",
weight: 300,
},
text: '건수',
padding: {
top: 10,
bottom: 10,
},
},
ticks: {
display: true, // 틱 표시 여부
color: '#808080',
padding: 8,
stepSize: 1, // 틱 간격
maxRotation: 45, // 최대 회전 각도
minRotation: 0, // 최소 회전 각도
autoSkip: true, // 자동 건너뛰기
autoSkipPadding: 10, // 자동 건너뛰기 패딩
callback: (value) => {
// 틱 라벨 커스터마이징
return value;
},
},
},
y: {
// y축은 x축과 동일한 옵션을 사용할 수 있음
beginAtZero: true, // 0부터 시작할지 여부
min: 0, // 최소값
max: 100, // 최대값
ticks: {
stepSize: 20, // 눈금 간격
callback: (value) => value + '%', // 단위 표시
},
},
},
// 레이아웃 설정
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 10,
},
},
// 데이터셋별 설정
elements: {
point: {
radius: 4, // 포인트 크기
hoverRadius: 6, // 호버 시 포인트 크기
borderWidth: 2,
backgroundColor: '#fff',
},
line: {
tension: 0.4, // 선의 곡률
borderWidth: 2,
fill: false, // 선 아래 영역 채우기
},
bar: {
borderWidth: 1,
borderRadius: 4,
borderSkipped: false,
},
},
};
위의 옵션들을 활용하여 실제로 차트를 구현해보면 아래와 같이 사용할 수 있다.
import { Line } from 'react-chartjs-2';
const MyChart = () => {
const data = {
labels: ['1월', '2월', '3월', '4월', '5월'],
datasets: [
{
label: '매출',
data: [10, 20, 30, 40, 50],
borderColor: '#36A2EB',
backgroundColor: 'rgba(54, 162, 235, 0.2)',
},
],
};
return <Line options={options} data={data} />;
};
export default MyChart;
const simpleLineOptions = {
responsive: true,
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
},
},
scales: {
x: {
grid: {
display: false,
},
},
y: {
beginAtZero: true,
grid: {
color: '#f0f0f0',
},
},
},
};
const dashboardBarOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
usePointStyle: true,
padding: 20,
},
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
padding: 12,
titleFont: {
size: 14,
},
bodyFont: {
size: 13,
},
},
},
scales: {
x: {
grid: {
display: false,
},
},
y: {
grid: {
borderDash: [2, 4],
},
},
},
};
const reportOptions = {
responsive: true,
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
title: {
display: true,
text: '월별 실적 리포트',
font: {
size: 16,
weight: 'bold',
},
},
legend: {
position: 'bottom',
labels: {
padding: 20,
usePointStyle: true,
},
},
},
scales: {
x: {
ticks: {
maxRotation: 45,
minRotation: 45,
},
},
y: {
beginAtZero: true,
ticks: {
callback: (value) => value.toLocaleString() + '원',
},
},
},
};
이렇게 ChartJS의 다양한 옵션들을 활용하면, 목적에 맞는 차트를 더욱 완성도 있게 구현할 수 있다. 특히 plugins와 scales 옵션을 잘 활용하면 차트의 시각적 요소와 사용자 경험을 크게 개선할 수 있다는 점을 기억하자.