Canvas 차트 vs SVG 차트 무엇이 베스트 프렉티스인가?
🤷♂️ 실무에서 차트 라이브러리, 정답은 없다?
개발을 하면서 ‘차트 라이브러리’ 선택은 항상 쉽지 않은 숙제였습니다.
저 역시 Vue 프로젝트에서는 Chart.js를 React 프로젝트에서는 Recharts 사용한 경험이 있습니다.
돌이켜보면, 선택에 기준점이 없었지만 두 라이브러리 사용하면서 모두 별다른 문제 없이 잘 동작했고, 앞으로도 충분히 무난하게 사용할 수 있으리라 생각합니다. 다만, 그 당시 선택함에 있어 뚜렷한 기준이 있었냐고 묻는다면 솔직히 자신 있게 대답하긴 어렵습니다.
레거시 프로젝트에 이미 적용되어 있거나, 혹은 당장 가장 손쉽게 도입할 수 있었던 라이브러리를 자연스럽게 선택했던 것이 사실이죠.
이제는 직접 사용해본 경험을 바탕으로 "어떤 상황에서 Canvas 기반 차트와 SVG기반 차트를 선택하는 것이 더 나을까?" 라는 질문에 나만의 기준을 세우고, 이를 회고 해보겠습니다.
1. 그 당시 왜 Chart.js와 Recharts였나?
(1) Chart.js (Canvas 기반)
- 프로젝트에 처음 투입되었을 당시, 기존에 백오피스를 Vue로 구현한 레거시 프로젝트가 있었습니다.
단기간 내에 신규 프로젝트에 대한 MVP를 완성해야 하는 상황이었고, “가능한 한 기존에 있는 것을 최대한 활용하라”는 요청이 있었습니다.
그 결과, 이미 적용되어 있던
Chart.js를 그대로 사용하게 되었습니다.
다만, 실무에서 직접 사용하면서 Chart.js를 쓰다 보면 툴팁 커스텀이 생각보다 번거롭던 기억이 있었습니다. 예를 들어, 기획팀에서 “툴팁에 특정 스타일을 적용하고, 그래프 밖에 별도로 띄우자”는 요청이 왔을 때, Chart.js의 기본 옵션만으로는 한계가 있어 결국 Canvas 렌더링 이벤트를 감지하고, 바닐라 자바스크립트로 DOM 요소를 직접 생성·제어해야 했습니다. 이 과정에서 차트 데이터 좌표를 계산하고, 위치를 수동으로 잡고, 이벤트마다 요소를 업데이트하는 작업이 꽤 귀찮았죠.
공식 문서나 Stack Overflow, 블로그들을 찾아가며 구현하긴 했지만, 매번 이런 패턴을 반복하는 건 그때 당시 개발의 효율성이 떨어진다고 느꼈습니다.
- 간단한 코드/구현 예시

// Vue + vue-chartjs
import { HorizontalBar, mixins } from 'vue-chartjs';
import { createToolTip } from './utils';
export default {
extends: HorizontalBar,
mixins: [mixins.reactiveProp],
mounted() {
this.renderChart(this.chartData, {
tooltips: {
enabled: false,
position: 'custom',
custom: createToolTip, // DOM 생성·위치 계산
},
plugins: {
datalabels: { color: 'white', font: { size: 16, weight: 'bold' } },
},
});
},
};
// utils.js
export function createToolTip(model) {
let el = document.getElementById('chartjs-tooltip');
if (!el) {
el = document.createElement('div');
el.id = 'chartjs-tooltip';
el.innerHTML = '<table></table>';
document.body.appendChild(el);
}
if (model.opacity === 0) {
el.style.opacity = 0;
return;
}
const rect = this._chart.canvas.getBoundingClientRect();
el.style.opacity = 1;
el.style.position = 'absolute';
el.style.left = rect.left + window.pageXOffset + model.caretX + 'px';
el.style.top = rect.top + window.pageYOffset + rect.height + 'px';
}(2) Recharts (SVG 기반)
-
Chart.js를 통해 불편했던 점을Recharts의 경우 React 컴포넌트로 그대로 커스텀할 수 있다는 것이었습니다.content와label프로퍼티에 JSX를 주입하면, DOM 직접 생성이나 좌표 수동 계산 없이 어느정도 보정 값만 찾으면 원하는 UI를 구현할 수 있었고, React의 상태 관리 및 MUI 테마와도 자연스럽게 연동되었습니다. 결과적으로, 이전에Chart.js에서 경험했던 “DOM 직접 제어와 위치 계산”의 번거로움이 없었기에 선택을 하게 되었습니다. -
간단한 코드/구현 예시
- 아래 예시는 실제 실무에서 사용했던 스택형 가로 막대 차트로,
Tooltip을 MUI 테마와 연동하여 스타일링Label좌표를 직접 계산하여 값과 라벨을 각각 양쪽에 배치
하는 케이스 입니다.

- 아래 예시는 실제 실무에서 사용했던 스택형 가로 막대 차트로,
// (요약) Recharts 예시 – 핵심 구조
<ResponsiveContainer width="100%" height={70}>
<BarChart data={data} layout="vertical">
<XAxis type="number" hide />
<YAxis type="category" dataKey="name" hide />
<Tooltip cursor={false} isAnimationActive={false}
content={<CustomTooltip currentKey={currentKey} />} />
{keys.map((key, index) => (
<Bar key={key}
dataKey={key}
stackId={uuid}
fill={colors[index]}
onMouseOver={() => setCurrentKey(key)}
onMouseOut={() => setCurrentKey('')}
label={<CustomizedLabel currentIndex={index}
title={keys[index]}
titleLabelValue={data[0][keys[index]]} />}
/>
))}
</BarChart>
</ResponsiveContainer>2. Canvas vs SVG 실무 관점 비교
(1) 성능, 커스텀 난이도, 인터랙션, 확장성, 접근성 등 표나 리스트로 비교
- 차트 라이브러리에 대한 학습이 없었을 시절에는 팀 적합성과 러닝 커브에 집중을 하였지만 실제로 아래와 같은 비교표를 통해 사용을 달리해야 하는 점을 알 수 있습니다.
| 구분 | Canvas 기반 (예: Chart.js) | SVG 기반 (예: Recharts) |
|---|---|---|
| 렌더링 방식 | 픽셀 단위 비트맵 렌더링 | DOM 노드로 구성된 벡터 렌더링 |
| 성능 | 수천~수만 개 데이터 처리에 유리 (고성능) | 데이터 포인트가 많으면 DOM 노드 폭증으로 성능 저하 가능 |
| 커스텀 난이도 | 복잡함 — 좌표 계산, DOM 직접 제어 필요 | 간단함 — JSX/CSS로 직접 스타일·레이아웃 제어 |
| 툴팁/라벨 커스텀 | custom 옵션 + DOM 수동 생성 | content·label prop에 컴포넌트 주입 |
| 반응형 처리 | 별도 계산·처리 필요 | 기본적으로 반응형 지원 |
| 팀 적합성 | UI 변경이 적고, 대량 데이터 중심 프로젝트 | React 기반 UI·UX 커스텀이 잦은 프로젝트 |
| 테마·상태 연동 | 직접 구현 필요 (전역 상태·테마 수동 반영) | React 상태관리·MUI 테마와 자연스럽게 연동 |
| 러닝 커브 | 단순 차트 구현은 쉬움, 고급 커스텀은 어려움 | React 경험이 있다면 진입장벽 낮음 |
(2) 둘 차이의 렌더링 방식과 브라우저 동작 방식의 차이는 어떠한가?
- Canvas (픽셀 기반) 렌더링 방식
- Canvas는 HTML
<canvas>요소 하나에 그림을 “픽셀” 단위로 그려 넣는 방식으로 화면에 그려지는 모든 내용은 하나의 비트맵 이미지처럼 취급 됩니다. 예를 들어 수천~수만 개의 데이터 포인트를 찍더라도, 결국 한 장의 그림으로만 브라우저에 전달되게 됩니다. - 브라우저 입장에서는 "DOM 노드가 하나"라서, DOM 관리 비용이 거의 없기 때문에 새로 그릴 때는 전체 픽셀을 지우고, GPU 가속 활용 가능으로 다시 그리기만 하면 됩니다.
- SVG (픽셀 기반) 렌더링 방식
- SVG는
<path>,<circle>,<rect>등 각 도형을 DOM 노드로 생성하여 데이터가 많아질수록 브라우저 DOM에 추가되는 요소 수도 비례해 증가하게 됩니다. 예를 들어 10,000개의 점도표를 사용 해야하는 그래프의 경우 10,000개의<circle>DOM 노드를 사용하게 됩니다. - 브라우저는 DOM 트리의 각 노드에 대한 간단한 렌더링 과정은 아래와 같습니다.
- 레이아웃 계산(Layout)
- 스타일 계산(Style)
- 그리기(Paint)
- 이벤트 바인딩 처리
- DOM 노드가 수천 개 이상이 되면 이 과정에서 렌더링 지연이 발생될 수 밖에 없습니다.
3. 회고 및 앞으로의 고민
두 라이브러리를 실무에서 직접 사용해본 결과, 정답은 없고 상황에 맞춰 선택하는 것이 최선이라는 결론에 도달했습니다. 다만, 선택 전에 반드시 기획 요구사항과 제약 사항을 충분히 파악하고, 사용하려는 차트 라이브러리의 렌더링 방식과 동작 원리 등 이론적 배경을 팀원들에게 명확히 설명하는 과정이 필요하다는 점을 깨달았습니다.
SVG의 커스터마이징 편의성과 Canvas의 대량 데이터 처리 성능은 장단점이 뚜렷합니다. 그러나 최근에는 ECharts를 접하며 “이 라이브러리면 두 영역을 모두 어느 정도 커버할 수 있겠다”는 생각이 들었습니다.
- ECharts는 내부적으로 Canvas를 기본 엔진으로 사용하면서, 필요할 경우 SVG 모드로 전환이 가능합니다.
- 이를 통해 대량 데이터 처리 성능과 벡터 기반 커스터마이징을 모두 지원할 수 있습니다.
앞으로 새로운 프로젝트에서는 다음과 같은 기준을 가이드라인으로 삼고자 합니다.
- 데이터량이 많고 성능이 중요한 경우 → Canvas 모드 ECharts
- 데이터량이 적고 UI/UX 커스터마이징이 중요한 경우 → SVG 기반 Recharts
물론, 최종 선택은 팀의 개발 가이드와 기존 기술 스택을 우선시해야 하지만, 각 방식의 차이와 특성을 충분히 이해하고 의사결정하는 것이 중요하다고 생각합니다.