데이터 시각화 레퍼런스 · Chart.js 4
Chart.js 4 기반 인터랙티브 차트 15종 — 라이브 데모 + 복사 가능 코드 + 비즈니스 사용 기준 + Remotion 연계 가이드까지. 이 파일 하나면 발표자료 어떤 차트도 대응 가능.
언제: 기간별 실적·매출 비교. 카테고리 수 7개 이하일 때 가장 깔끔.
new Chart(canvas, {
type: 'bar',
data: {
labels: ['1Q','2Q','3Q','4Q'],
datasets: [{ label: '매출(억)',
data: [42,58,51,73],
backgroundColor: '#38bdf8',
borderRadius: 6 }]
},
options: { plugins:{legend:{display:false}},
scales:{y:{beginAtZero:true}} }
});
interpolate(frame,[0,20],[0,data])로 바 높이 애니메이션 — BarRace.tsx 패턴 그대로 적용언제: 시계열 트렌드. 기간이 8개 이상이면 바보다 라인이 훨씬 명확.
new Chart(canvas, {
type: 'line',
data: {
labels: months, // 12개 월
datasets: [{ label: '방문자',
data: values,
borderColor: '#38bdf8',
tension: 0.4, // 부드러운 곡선
fill: false,
pointRadius: 4 }]
},
options: { scales:{y:{beginAtZero:false}} }
});
언제: 5개 이하 구성비. 가운데 공간에 핵심 숫자 삽입하면 KPI 카드 대용.
new Chart(canvas, {
type: 'doughnut',
data: {
labels: ['A','B','C','D'],
datasets: [{ data: [40,25,20,15],
backgroundColor: [
'#38bdf8','#818cf8',
'#34d399','#fbbf24'],
borderWidth: 2,
borderColor: '#111c33' }]
},
options: { cutout: '65%' }
});
언제: 라인 트렌드에 양(Volume) 강조가 필요할 때. 스택드 면적은 구성비 변화.
datasets: [{ label: 'DAU',
data: values,
borderColor: '#818cf8',
backgroundColor: 'rgba(129,140,248,.18)',
fill: true, // ← 면적 채우기
tension: 0.4
}]
언제: "A사 vs B사 × 분기별" 등 2차원 비교. 그룹 수 3개 이하 권장.
datasets: [
{ label:'목표', data:[50,60,55,70],
backgroundColor:'#334155' },
{ label:'실적', data:[42,58,61,73],
backgroundColor:'#38bdf8' }
]
// options.scales.x.grouped = true (기본값)
언제: 항목 이름이 길거나 순위 비교. "Top 10" 형식에 최적.
options: {
indexAxis: 'y', // ← 수평 전환 핵심
plugins:{ legend:{display:false} },
scales:{ x:{beginAtZero:true} }
}
언제: 동일 기준 5~8개 항목 역량/성과 비교. 팀·개인 평가에 자주 사용.
new Chart(canvas, {
type: 'radar',
data: {
labels: ['기획','디자인','개발',
'커뮤니케이션','리더십'],
datasets: [{ label:'A팀',
data: [80,65,90,70,75],
fill: true,
backgroundColor:'rgba(56,189,248,.2)',
borderColor:'#38bdf8' }]
}
});
언제: 합계+구성비 동시 표현. 기간별 구성 변화 파악.
options: {
scales: {
x: { stacked: true },
y: { stacked: true,
beginAtZero: true }
}
}
// datasets 각각 stack:'total' 필요 없음 — stacked:true로 자동
언제: 실적(바)과 목표선·성장률(라인) 동시 표현. 가장 많이 쓰이는 임원 보고 차트.
datasets: [
{ type:'bar', label:'매출',
data:[42,58,51,73,68,82],
backgroundColor:'#1e3a5f',
borderColor:'#38bdf8',
borderWidth:1 },
{ type:'line', label:'목표',
data:[50,50,55,65,70,75],
borderColor:'#fbbf24',
borderDash:[6,3],
pointRadius:0 }
]
언제: 두 변수 간 상관관계 파악. "광고비 ↔ 전환율" 등 인과관계 시각화.
new Chart(canvas, {
type: 'scatter',
data: {
datasets: [{ label:'제품군',
data: [
{ x:10, y:20 },
{ x:15, y:34 }
// ...더 많은 포인트
],
pointRadius: 6,
backgroundColor:'rgba(56,189,248,.7)'
}]
}
});
언제: x·y·크기 3변수. "시장규모(크기)×성장률(y)×점유율(x)" 포트폴리오 분석.
new Chart(canvas, {
type: 'bubble',
data: {
datasets: [{ data: [
{ x:20, y:30, r:15 },
{ x:40, y:10, r:25 },
{ x:60, y:50, r:10 }
], backgroundColor:'rgba(129,140,248,.5)'
}]
}
});
언제: 시작값→증감 항목별→최종값 분석. P&L 설명, 비용 구조 분해.
// 투명 오프셋 바 + 실제 값 바 stacked
datasets: [
{ label:'offset',
data: offsets, // 투명 바 (기준점)
backgroundColor:'transparent',
stack:'w' },
{ label:'증가',
data: positives,
backgroundColor:'#34d399',
stack:'w' },
{ label:'감소',
data: negatives,
backgroundColor:'#f87171',
stack:'w' }
]
핵심 지표를 한 눈에 — 숫자가 스크롤 시 0에서 카운트업으로 올라옵니다.
function countUp(el, target, dur=1800, suffix='') {
const start = performance.now();
const tick = t => {
const p = Math.min(1, (t-start)/dur);
const ease = 1 - Math.pow(1-p, 3); // easeOut cubic
el.textContent = Math.round(target * ease) + suffix;
if (p < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}
// 사용: countUp(document.getElementById('kpi'), 847, 2000, '억')
new Chart(canvas, {
type: 'doughnut',
data: {
datasets: [{ data: [76, 24], // 값, 나머지
backgroundColor: ['#38bdf8', '#1e293b'],
borderWidth: 0, cutout: '75%' }]
},
options: {
rotation: -90, // 반원 시작점
circumference: 180, // 반원
plugins: { legend: { display: false } }
}
});
언제: 표·리스트에 트렌드를 함께 보여줄 때. 별도 축 없이 방향성만 전달.
new Chart(sparkCanvas, {
type: 'line',
data: { labels: data.map((_,i)=>i),
datasets: [{ data: sparkData,
borderColor: color,
borderWidth: 2,
fill: false,
pointRadius: 0,
tension: 0.4 }] },
options: {
animation: false,
responsive: false,
scales: { x:{display:false}, y:{display:false} },
plugins: { legend:{display:false} }
}
});
| 상황 | 데이터 특성 | 추천 차트 | 피해야 할 것 |
|---|---|---|---|
| 기간 비교 | 8개 이하 기간 | 수직 바 | 파이 (변화량 안 보임) |
| 기간 비교 | 12개 이상 기간 | 라인 or 면적 | 바 (너무 빽빽함) |
| 구성비 | 5개 이하 항목 | 도넛 or 파이 | 3D 파이 (왜곡) |
| 구성비 | 6개 이상 항목 | 수평 바 (정렬) | 파이 (색 구분 불가) |
| 순위 비교 | 항목명이 긴 경우 | 수평 바 | 수직 바 (라벨 겹침) |
| 2차원 비교 | 그룹 × 기간 | 그룹 바 | 누적 바 (합계 오해) |
| 구성+합계 | 시간 흐름 포함 | 누적 바 | 그룹 바 (합계 안 보임) |
| 상관관계 | 2변수 포인트 | 산점도 | 라인 (순서 오해) |
| 3변수 분석 | 포트폴리오 | 버블 | 3D 바 (읽기 어려움) |
| 증감 분석 | P&L·비용 분해 | 폭포 | 단순 라인 (출발점 손실) |
| 역량 평가 | 동일 기준 5~8항목 | 레이더 | 바 (비교 구조 약함) |
| 실적+목표 | 임원 보고 | 혼합형 (바+점선) | 이중 바 (목표 묻힘) |
| 달성률 | 단일 KPI | 게이지 or 도넛 | 파이 (기준 불명확) |
Chart.js는 웹 발표, Remotion은 mp4 영상. 두 세계의 데이터 구조는 동일 — JSON만 공유하면 됨.
// 이 데이터를 Chart.js와 Remotion이 공유
export const salesData = [
{ label: '1Q', value: 42 },
{ label: '2Q', value: 58 },
{ label: '3Q', value: 51 },
{ label: '4Q', value: 73 },
];
data.map(d=>d.value) / Remotion → interpolate(frame,...) 동일 데이터 소비Chart.js 바 차트를 그대로 Remotion SVG로 변환하는 핵심 패턴.
import { useCurrentFrame, interpolate } from 'remotion';
export const BarChart = ({ data }) => {
const frame = useCurrentFrame();
return (
<svg viewBox="0 0 800 400">
{data.map((d, i) => {
const h = interpolate(
frame,
[i*5, i*5+30], // 스태거
[0, d.value * 3],
{ extrapolateRight:'clamp' }
);
return <rect key={i}
x={i*180+20} y={400-h}
width={120} height={h}
fill="#38bdf8" rx={6} />;
})}
</svg>
);
};