Chart.js는 HTML5 Canvas 요소를 활용하여 다양한 형태의 차트를 손쉽게 생성할 수 있는 경량 자바스크립트 라이브러리입니다. 간결한 API를 통해 실시간 데이터 갱신, 반응형 디자인, 그리고 높은 수준의 커스터마이징을 지원합니다. 이 글에서는 막대 그래프, 원형 차트, 선 그래프, 레이더 차트 등 주요 차트 유형을 실제 예제 코드와 함께 살펴보고, 프로젝트에 Chart.js를 통합하고 최적화하는 방법을 단계별로 안내합니다.
1. Chart.js 개요 및 설계 철학
Chart.js는 복잡한 데이터 시각화를 간단한 자바스크립트 객체 설정만으로 구현할 수 있도록 설계되었습니다. Canvas 기반으로 동작하기 때문에 SVG나 DOM 조작에 비해 성능이 우수하며, CSS와의 결합을 통해 디자인의 유연성을 극대화할 수 있습니다. 데이터 대시보드, 보고서 페이지, 실시간 모니터링 시스템 등 다양한 웹 환경에서 활용 가능합니다.
// 기본 선 그래프 생성 예시
const ctx = document.getElementById('myLineChart').getContext('2d');
const lineChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['1월', '2월', '3월', '4월', '5월', '6월'],
datasets: [{
label: '월별 방문자 수',
data: [120, 190, 80, 150, 210, 170],
borderColor: 'rgb(75, 192, 192)',
tension: 0.3
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
2. 주요 차트 유형별 구현
2.1 막대 그래프 (Bar Chart)
막대 그래프는 범주별 데이터 크기를 비교할 때 가장 널리 쓰입니다. Chart.js에서는 type: 'bar'로 간단히 생성할 수 있으며, 각 막대의 색상과 테두리를 개별적으로 지정할 수 있습니다.
const barCtx = document.getElementById('barChart').getContext('2d');
const barChart = new Chart(barCtx, {
type: 'bar',
data: {
labels: ['사과', '바나나', '포도', '오렌지'],
datasets: [{
label: '판매량',
data: [50, 80, 30, 65],
backgroundColor: [
'rgba(255, 99, 132, 0.6)',
'rgba(54, 162, 235, 0.6)',
'rgba(255, 206, 86, 0.6)',
'rgba(75, 192, 192, 0.6)'
],
borderWidth: 2
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false }
}
}
});
2.2 원형 차트 (Pie Chart)
원형 차트는 전체에서 각 항목이 차지하는 비율을 직관적으로 보여줍니다. Chart.js의 hoverOffset 속성을 활용하면 마우스를 올렸을 때 해당 조각이 강조되는 효과를 줄 수 있습니다.
const pieCtx = document.getElementById('pieChart').getContext('2d');
const pieChart = new Chart(pieCtx, {
type: 'pie',
data: {
labels: ['직접 방문', '검색 엔진', '소셜 미디어'],
datasets: [{
data: [300, 150, 100],
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56'],
hoverOffset: 8
}]
}
});
2.3 선 그래프 (Line Chart)
선 그래프는 시간에 따른 추세나 연속적인 변화를 표현하는 데 적합합니다. 여러 개의 데이터셋을 동시에 표시할 수 있어 비교 분석에도 유용합니다.
const lineCtx = document.getElementById('multiLineChart').getContext('2d');
const multiLineChart = new Chart(lineCtx, {
type: 'line',
data: {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
datasets: [
{
label: '제품 A',
data: [30, 45, 60, 80],
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.1)',
fill: true
},
{
label: '제품 B',
data: [20, 35, 50, 70],
borderColor: 'rgb(54, 162, 235)',
backgroundColor: 'rgba(54, 162, 235, 0.1)',
fill: true
}
]
},
options: {
interaction: {
mode: 'index',
intersect: false
}
}
});
2.4 레이더 차트 (Radar Chart)
레이더 차트는 여러 기준에 대한 데이터를 다각형으로 표현하여 종합적인 성능이나 특성을 비교할 때 사용합니다. 각 축은 동일한 간격으로 배치되며, 데이터셋마다 다른 색상을 적용할 수 있습니다.
const radarCtx = document.getElementById('radarChart').getContext('2d');
const radarChart = new Chart(radarCtx, {
type: 'radar',
data: {
labels: ['속도', '정확도', '안정성', '호환성', '비용'],
datasets: [{
label: '제품 X',
data: [90, 80, 70, 85, 60],
backgroundColor: 'rgba(153, 102, 255, 0.2)',
borderColor: 'rgb(153, 102, 255)',
pointBackgroundColor: 'rgb(153, 102, 255)'
}, {
label: '제품 Y',
data: [70, 95, 85, 60, 90],
backgroundColor: 'rgba(255, 159, 64, 0.2)',
borderColor: 'rgb(255, 159, 64)',
pointBackgroundColor: 'rgb(255, 159, 64)'
}]
}
});
3. Chart.js의 핵심 장점
3.1 사용자 친화적 API
Chart.js는 최소한의 코드만으로도 작동하는 차트를 만들 수 있습니다. 복잡한 설정이 필요한 경우에도 단일 설정 객체 내에서 대부분의 옵션을 제어할 수 있어 학습 곡선이 낮습니다. 예를 들어, 실시간 데이터 갱신은 chart.update() 메서드 호출 한 번으로 가능합니다.
// 실시간 데이터 업데이트 함수
function updateChartWithNewData(newValues) {
const dataset = myChart.data.datasets[0];
dataset.data = newValues;
myChart.update();
}
// 3초마다 임의의 데이터로 갱신
setInterval(() => {
const randomData = Array.from({length: 6}, () => Math.floor(Math.random() * 100));
updateChartWithNewData(randomData);
}, 3000);
3.2 반응형 및 크로스 플랫폼 지원
Chart.js는 기본적으로 responsive: true 옵션이 활성화되어 있어, 컨테이너 크기에 따라 차트가 자동으로 리사이징됩니다. 또한 모든 최신 브라우저(Chrome, Firefox, Safari, Edge)에서 문제없이 동작하며, 모바일 환경에서도 일관된 경험을 제공합니다.
3.3 높은 확장성 (플러그인 시스템)
Chart.js의 플러그인 아키텍처를 활용하면 데이터 레이블, 줌, 애니메이션 등 추가 기능을 쉽게 붙일 수 있습니다. 공식 및 서드파티 플러그인을 통해 기능을 확장하거나, 직접 플러그인을 작성하여 고유한 요구사항을 충족시킬 수 있습니다.
// chartjs-plugin-datalabels를 사용한 데이터 레이블 표시 예시
const chartWithLabels = new Chart(ctx, {
type: 'bar',
data: data,
options: {
plugins: {
datalabels: {
color: '#333',
anchor: 'end',
align: 'top',
formatter: (value) => value + '건'
}
}
},
plugins: [ChartDataLabels]
});
4. Chart.js 프로젝트 통합 및 파일 구조
Chart.js를 프로젝트에 도입하는 방법은 크게 CDN 방식과 npm 패키지 방식으로 나뉩니다. CDN을 사용하면 HTML 파일에 <script> 태그 하나만 추가하면 되며, npm을 사용하면 모듈 번들러(Webpack, Vite 등)와 함께 효율적으로 관리할 수 있습니다.
// npm 설치
// npm install chart.js
// ES 모듈 방식으로 import
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
// 또는 CDN 사용
// <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
Chart.js의 주요 파일 구조는 다음과 같습니다:
chart.js/chart.min.js: 핵심 라이브러리 파일dist/: 빌드된 배포 파일 디렉토리src/: 소스 코드 디렉토리 (커스텀 빌드 시 필요)plugins/: 공식 플러그인 모음examples/: 다양한 사용 예제 코드
5. 성능 최적화 전략
대용량 데이터를 다루거나 여러 개의 차트를 동시에 렌더링해야 하는 경우, 아래 기법들을 적용하면 성능을 크게 개선할 수 있습니다.
- 데이터 포인트 축소: 불필요하게 세밀한 데이터는 병합하거나 샘플링하여 포인트 수를 줄입니다.
- 애니메이션 비활성화:
animation: false로 설정하면 초기 렌더링 속도가 빨라집니다. - Canvas 재사용: 차트 인스턴스를 파기(destroy)하지 않고 재사용하면 메모리 누수를 방지할 수 있습니다.
- 디커플링(decoupling) 업데이트: 데이터 변경 시
chart.update('none')을 호출하여 불필요한 애니메이션을 생략합니다.
// 성능 최적화 적용 예
const optimizedChart = new Chart(ctx, {
type: 'line',
data: largeDataset,
options: {
animation: false, // 애니메이션 비활성화
responsive: true,
maintainAspectRatio: false,
elements: {
point: { radius: 0 } // 데이터 포인트 숨김
},
scales: {
x: { ticks: { maxTicksLimit: 10 } } // x축 레이블 제한
}
}
});
// 데이터만 빠르게 갱신
function fastUpdate(newData) {
optimizedChart.data.datasets[0].data = newData;
optimizedChart.update('none');
}
6. 데이터 바인딩과 동적 업데이트
Chart.js는 데이터 배열을 직접 조작하는 방식으로 동적 업데이트를 구현합니다. 배열의 요소를 추가, 삭제, 변경한 후 chart.update()를 호출하면 차트가 즉시 다시 그려집니다. 아래 예시는 웹소켓을 통해 실시간 주가 데이터를 차트에 반영하는 방법을 보여줍니다.
// 웹소켓을 통한 실시간 데이터 업데이트 예
const socket = new WebSocket('wss://example.com/stock-price');
socket.onmessage = (event) => {
const newPrice = JSON.parse(event.data).price;
const chartData = stockChart.data.datasets[0].data;
// 새 데이터 추가
chartData.push(newPrice);
// 오래된 데이터 제거 (최근 20개 유지)
if (chartData.length > 20) {
chartData.shift();
}
// 레이블도 동기화
const labelData = stockChart.data.labels;
labelData.push(new Date().toLocaleTimeString());
if (labelData.length > 20) {
labelData.shift();
}
stockChart.update('none');
};
7. 인터랙션 기능 구현
Chart.js는 기본적으로 툴팁, 범례, 클릭 이벤트 등을 지원합니다. options.onClick 콜백을 활용하면 사용자가 차트 요소를 클릭했을 때 추가 동작을 수행할 수 있습니다. 아래 코드는 막대를 클릭하면 해당 데이터를 콘솔에 출력하고, 툴팁에 사용자 정의 텍스트를 표시하는 예제입니다.
const interactiveChart = new Chart(ctx, {
type: 'bar',
data: chartData,
options: {
onClick: (event, elements) => {
if (elements.length > 0) {
const firstElement = elements[0];
const value = interactiveChart.data.datasets[firstElement.datasetIndex].data[firstElement.index];
const label = interactiveChart.data.labels[firstElement.index];
alert(`${label}: ${value}`);
}
},
plugins: {
tooltip: {
callbacks: {
label: (context) => {
const value = context.parsed.y;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = ((value / total) * 100).toFixed(1);
return `${context.label}: ${value} (${percentage}%)`;
}
}
}
}
}
});