레슨 7 / 8·25분
실전: 대시보드 만들기
실전 프로젝트: 매출 분석 대시보드
지금까지 배운 Chart.js 기능을 조합하여 실제 매출 분석 대시보드를 만들어 봅니다. 여러 차트를 하나의 페이지에 배치하고, 필터링과 실시간 업데이트 기능을 구현합니다.
1단계: HTML 레이아웃 구성
html
<div class="dashboard">
<h1>매출 분석 대시보드</h1>
<!-- 필터 영역 -->
<div class="filters">
<select id="yearFilter">
<option value="2024">2024년</option>
<option value="2023">2023년</option>
</select>
<select id="regionFilter">
<option value="all">전체 지역</option>
<option value="seoul">서울</option>
<option value="busan">부산</option>
</select>
</div>
<!-- 차트 그리드 -->
<div class="chart-grid">
<div class="chart-card">
<canvas id="revenueChart"></canvas>
</div>
<div class="chart-card">
<canvas id="categoryChart"></canvas>
</div>
<div class="chart-card">
<canvas id="trendChart"></canvas>
</div>
<div class="chart-card">
<canvas id="performanceChart"></canvas>
</div>
</div>
</div>2단계: 데이터 모델 정의
javascript
// 샘플 데이터
var salesData = {
months: ['1월', '2월', '3월', '4월', '5월', '6월',
'7월', '8월', '9월', '10월', '11월', '12월'],
revenue: [120, 190, 150, 250, 220, 300, 280, 310, 260, 340, 290, 380],
costs: [80, 120, 100, 160, 140, 180, 170, 190, 160, 210, 180, 230],
categories: {
labels: ['전자제품', '의류', '식품', '도서', '기타'],
values: [35, 25, 20, 12, 8],
},
performance: {
labels: ['매출 성장률', '고객 만족도', '재구매율', '배송 속도', '품질 평가'],
current: [85, 90, 75, 80, 88],
target: [90, 85, 80, 90, 85],
},
};3단계: 매출/비용 복합 차트
javascript
// 매출 vs 비용 복합 차트
var revenueCtx = document.getElementById('revenueChart').getContext('2d');
var revenueGradient = revenueCtx.createLinearGradient(0, 0, 0, 300);
revenueGradient.addColorStop(0, 'rgba(54, 162, 235, 0.4)');
revenueGradient.addColorStop(1, 'rgba(54, 162, 235, 0.0)');
var revenueChart = new Chart(revenueCtx, {
type: 'bar',
data: {
labels: salesData.months,
datasets: [
{
type: 'bar',
label: '매출',
data: salesData.revenue,
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderRadius: 4,
order: 2,
},
{
type: 'bar',
label: '비용',
data: salesData.costs,
backgroundColor: 'rgba(255, 159, 64, 0.6)',
borderRadius: 4,
order: 3,
},
{
type: 'line',
label: '순이익',
data: salesData.revenue.map(function(r, i) {
return r - salesData.costs[i];
}),
borderColor: 'rgb(75, 192, 192)',
backgroundColor: revenueGradient,
fill: true,
tension: 0.3,
order: 1,
},
],
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: '월별 매출/비용/순이익',
font: { size: 16 },
},
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(v) { return v + '만원'; },
},
},
},
},
});4단계: 카테고리 도넛 차트
javascript
// 카테고리별 매출 비중
var categoryCtx = document.getElementById('categoryChart').getContext('2d');
var categoryChart = new Chart(categoryCtx, {
type: 'doughnut',
data: {
labels: salesData.categories.labels,
datasets: [{
data: salesData.categories.values,
backgroundColor: [
'rgba(54, 162, 235, 0.7)',
'rgba(255, 99, 132, 0.7)',
'rgba(75, 192, 192, 0.7)',
'rgba(255, 205, 86, 0.7)',
'rgba(153, 102, 255, 0.7)',
],
hoverOffset: 10,
}],
},
options: {
responsive: true,
cutout: '55%',
plugins: {
title: {
display: true,
text: '카테고리별 매출 비중',
font: { size: 16 },
},
legend: { position: 'bottom' },
},
},
});5단계: 필터 연동
javascript
// 필터 변경 시 차트 업데이트
document.getElementById('yearFilter').addEventListener('change', function(e) {
var year = e.target.value;
// API에서 데이터 가져오기 (여기서는 시뮬레이션)
var newData = fetchDataByYear(year);
// 차트 데이터 업데이트
revenueChart.data.datasets[0].data = newData.revenue;
revenueChart.data.datasets[1].data = newData.costs;
revenueChart.data.datasets[2].data = newData.revenue.map(function(r, i) {
return r - newData.costs[i];
});
revenueChart.update();
categoryChart.data.datasets[0].data = newData.categories;
categoryChart.update();
});
function fetchDataByYear(year) {
// 실제로는 API 호출
return {
revenue: salesData.revenue.map(function(v) {
return Math.round(v * (year === '2023' ? 0.85 : 1));
}),
costs: salesData.costs.map(function(v) {
return Math.round(v * (year === '2023' ? 0.9 : 1));
}),
categories: salesData.categories.values,
};
}💡
대시보드를 구성할 때는 반응형 레이아웃(CSS Grid나 Flexbox)과 함께 Chart.js의 responsive: true, maintainAspectRatio: false 옵션을 활용하세요. 다양한 화면 크기에서 차트가 올바르게 표시됩니다.