Study/IT

[어쨌든, 바이브 코딩] Chart.js로 인터랙티브 대시보드 만들기

oon정 2026. 2. 23. 17:51

참고 자료 : 어쨌든, 바이브 코딩 - 코다프레스

https://product.kyobobook.co.kr/detail/S000218783328

 

어쨌든, 바이브 코딩 | 코다프레스 - 교보문고

어쨌든, 바이브 코딩 | 프롬프트 한 줄이면 충분하다 기술이 없는 게 아니라 방식이 바뀐 거다 아이디어로 바로 만드는 창작 경험 50개 생각났다면 바로 만들어라 아이디어는 이제 '시작 신호'다.

product.kyobobook.co.kr

Tutorial

01. Chart.js로 인터랙티브 차트 대시보드 만들기


목표 

사용자가 인터랙티브 차트로 데이터를 시각화할 수 있는 반응형 대시보드 제작

- 막대 차트와 꺾은선 차트를 나란히 표시하기

- 개별 데이터 세트를 켜고 끄기

- 실시간으로 차트에 새 데이터 스트리밍하기

 

도구

- HTML / CSS / 자바스크립트

- Chart.js

 

익힐 기술

- Chart.js 구성

- DOM 조작

- 이벤트 처리

- 데이터 실시간 업데이트

 

AI

- Claude AI Opus4.6

 

완성된 결과물

https://claude.ai/public/artifacts/2321eaaf-bffd-433b-9922-347c9ca8890d

 

Interactive Sales Dashboard with Live Charts & CSV Import

Create dynamic sales dashboards with real-time bar, line, and pie charts. Upload CSV data, toggle datasets, pause live updates, and export charts as PNG images instantly.

claude.ai

 


 

claude 에 접속한다. 데스크톱 앱도 좋고 웹에서 접속해도 좋다. 첫 채팅을 시작하고 단계별 지침을 따라 앱을 제작해보자.

 

1단계 : HTML 기본 구조 설명하기

 

프롬프트

빈 차트 두 개가 나란히 있는 기본 웹 페이지를 만들어줘. Chart.js도 로드해 줘.

 

예시 응답 코드 : 간단한 페이지 구조

<body>

  <div class="container">
    <div class="chart-box">
      <h2>Chart 1</h2>
      <canvas id="chart1"></canvas>
    </div>
    <div class="chart-box">
      <h2>Chart 2</h2>
      <canvas id="chart2"></canvas>
    </div>
  </div>

  <script>
    const chart1 = new Chart(document.getElementById('chart1'), {
      type: 'bar',
      data: { labels: [], datasets: [] },
      options: { responsive: true }
    });

    const chart2 = new Chart(document.getElementById('chart2'), {
      type: 'line',
      data: { labels: [], datasets: [] },
      options: { responsive: true }
    });
  </script>

</body>

 

차트에 빈 캔버스 2개가 만들어진다.

 

 

2단계 : 차트 초기화하기

 

프롬프트

월별 판매를 막대로, 누적 합계를 선으로 보여 주는 코드를 추가해줘.

 

예시 응답 코드 : 초기화 스크립트

const months = ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'];
    const sales  = [120, 95, 140, 175, 160, 200, 230, 210, 185, 250, 270, 310];

    // 누적 합계 계산
    const cumulative = sales.reduce((acc, v) => {
      acc.push((acc.length ? acc[acc.length - 1] : 0) + v);
      return acc;
    }, []);

    // Chart 1 – 월별 판매 (막대)
    new Chart(document.getElementById('chart1'), {
      type: 'bar',
      data: {
        labels: months,
        datasets: [{
          label: '월별 판매',
          data: sales,
          backgroundColor: 'rgba(59,130,246,0.6)',
          borderColor: 'rgba(59,130,246,1)',
          borderWidth: 1,
          borderRadius: 4
        }]
      },
      options: {
        responsive: true,
        plugins: {
          legend: { display: true, position: 'top' }
        },
        scales: {
          y: { beginAtZero: true, title: { display: true, text: '판매량' } }
        }
      }
    });

    // Chart 2 – 누적 합계 (선)
    new Chart(document.getElementById('chart2'), {
      type: 'line',
      data: {
        labels: months,
        datasets: [{
          label: '누적 합계',
          data: cumulative,
          borderColor: 'rgba(16,185,129,1)',
          backgroundColor: 'rgba(16,185,129,0.15)',
          fill: true,
          tension: 0.3,
          pointRadius: 4,
          pointBackgroundColor: 'rgba(16,185,129,1)'
        }]
      },
      options: {
        responsive: true,
        plugins: {
          legend: { display: true, position: 'top' }
        },
        scales: {
          y: { beginAtZero: true, title: { display: true, text: '누적 판매량' } }
        }
      }
    });

 

3단계 : 차트 초기화하기

 

프롬프트

클릭하면 막대를 숨기거나 보여 주는 버튼을 만들어줘.

 

예시 응답 코드 : 간단한 토글 핸들러

// 막대 토글
    function toggleBars() {
      const ds = chart1.data.datasets[0];
      const btn = document.getElementById('toggleBtn');
      ds.hidden = !ds.hidden;
      btn.textContent = ds.hidden ? '막대 보이기' : '막대 숨기기';
      btn.style.background = ds.hidden ? '#9ca3af' : '#3b82f6';
      chart1.update();
    }

 

 

토큰 핸들러가 생성되었다. 막대 숨기기를 클릭하면 문구가 '막대 보이기'로 변경되며 색상이 바뀌는 것을 확인할 수 있다.

 

추가로 시도해 볼 수 있는 아이디어

단일 버튼을 각 데이터 세트에 대한 체크박스로 변경해보자

 

예시 응답 코드 : 체크박스 생성

// 데이터셋 토글 (어떤 차트든 사용 가능)
    function toggleDataset(chart, index, visible) {
      chart.data.datasets[index].hidden = !visible;
      chart.update();
    }

 

 

 

이때 어떻게 하면 좋을까 -> 디자인을 어느 위치에 두면 좋을까 에 대한 말인데, 다음에는 구체적으로 '체크박스 위치를 사용자가 편하게 누를 수 있도록 배치해줘' 라고 프롬프트를 개선해야겠다.

 

4단계 : 실시간 데이터 스트리밍하기

 

프롬프트

몇 초마다 랜덤하게 판매 수치를 추가하고 두 차트 모두 최신 상태로 유지해 줘.

 

예시 응답 코드 : 타이머 기반 업데이트 루프

   // 실시간 업데이트 — 3초마다 새 월 데이터 추가
    let monthCounter = 13;                       // 다음 달 번호
    const maxPoints  = 24;                       // 화면에 유지할 최대 포인트 수

    setInterval(() => {
      const newSale = Math.floor(Math.random() * 250) + 50;   // 50 ~ 299
      const label   = monthCounter + '월';
      monthCounter++;

      // 막대 차트 업데이트
      chart1.data.labels.push(label);
      chart1.data.datasets[0].data.push(newSale);

      // 누적 합계 업데이트
      const lastCum = cumulative[cumulative.length - 1] || 0;
      cumulative.push(lastCum + newSale);
      chart2.data.labels.push(label);
      chart2.data.datasets[0].data.push(lastCum + newSale);

      // 포인트가 너무 많으면 앞에서 제거
      if (chart1.data.labels.length > maxPoints) {
        chart1.data.labels.shift();
        chart1.data.datasets[0].data.shift();
        chart2.data.labels.shift();
        chart2.data.datasets[0].data.shift();
        cumulative.shift();
      }

      chart1.update();
      chart2.update();
    }, 3000);

 

 

추가로 시도해 볼 수 있는 아이디어

 

- 실시간 업데이트를 일시 중지하거나 재시작하는 토글 추가하기

 

- 12월 -> 다음해 1월이 되도록 수정하기

   // 실시간 업데이트 — 3초마다 새 월 데이터 추가
    const maxPoints  = 24;
    let isRunning    = true;

    function nextLabel() {
      currentMonth++;
      if (currentMonth > 12) {
        currentMonth = 1;
        currentYear++;
      }
      return String(currentYear).padStart(2,'0') + '년 ' + currentMonth + '월';
    }

    function addDataPoint() {
      const newSale = Math.floor(Math.random() * 250) + 50;
      const label   = nextLabel();

      chart1.data.labels.push(label);
      chart1.data.datasets[0].data.push(newSale);

      const lastCum = cumulative[cumulative.length - 1] || 0;
      cumulative.push(lastCum + newSale);
      chart2.data.labels.push(label);
      chart2.data.datasets[0].data.push(lastCum + newSale);

      if (chart1.data.labels.length > maxPoints) {
        chart1.data.labels.shift();
        chart1.data.datasets[0].data.shift();
        chart2.data.labels.shift();
        chart2.data.datasets[0].data.shift();
        cumulative.shift();
      }

      chart1.update();
      chart2.update();
    }

    let intervalId = setInterval(addDataPoint, 3000);

    function toggleLive() {
      const btn = document.getElementById('pauseBtn');
      if (isRunning) {
        clearInterval(intervalId);
        btn.innerHTML = '▶ 재시작';
        btn.style.background = '#22c55e';
      } else {
        intervalId = setInterval(addDataPoint, 3000);
        btn.innerHTML = '⏸ 일시 중지';
        btn.style.background = '#ef4444';
      }
      isRunning = !isRunning;
    }

 

 

5단계 : 레이아웃을 반응형으로 만들기

프롬프트

CSS를 사용해서 노트북에서는 두 차트가 나란히 보이지만 휴대폰에서는 위아래로 쌓이도록 해줘.

 

예시 응답 코드 : 간단한 스타일시트

   @media (max-width: 768px) {
      body { padding: 16px; }
      .chart-box { flex: 1 1 100%; }
    }

 

추가로 시도해 볼 수 있는 아이디어

각 캔버스에 음영을 약하게 주고 여백을 추가하세요.

 

  .chart-box canvas {
      background: #fafafa;
      border-radius: 8px;
      padding: 12px;
      box-shadow: inset 0 1px 4px rgba(0,0,0,0.06);
      margin-top: 8px;
    }

 

 

완성한 작업

이제 자동으로 업데이트되는 인터랙티브 차트가 포함된 실시간 반응형 대시보드가 생겼습니다.

 

기능 요약

- 한 페이지에 막대 및 꺾은선 차트

- 데이터세트를 토글하는 버튼

- 실시간 데이터 스트리밍

- 반응형 2열 레이아웃

 

추가로 시도해 볼 수 있는 아이디어

시장 점유율을 보여주는 원형 차트를 추가

대시보드를 png이미지로 내보내기

사용자가 CSV를 업로드하고 차트를 다시 그리도록 허용하기