본문 바로가기
🔥Next 뽀개기

Chart.js 라이브러리로 달성률 시각화 구현하기(feat. Doughnut 차트)

by 짱돌보리 2024. 12. 20.
728x90

📊Chart.js 라이브러리로 달성률 시각화 구현하기(feat. Doughnut 차트)

‼️구현하고자 하는 것

  1. 전체 수행 날짜 대비 완료된 날짜의 비율을 계산하기
  2. Chart.js의 Doughnut 차트를 사용해 완료/미완료 비율을 시각적으로 표현하기

전체 수행 날짜 대비 완료된 날짜의 비율을 계산하기

HabitCard 컴포넌트 안에 자식인 HabitCardChart 컴포넌트를 넣어준다.

 const startDate = new Date(habit.startDate)
  const endDate = new Date(habit.endDate)

  // frequency에 해당하는 요일을 계산
  const frequencySet = new Set(habit.frequency.map((day) => day.toLowerCase())) // 요일을 소문자로 변환하여 Set 생성

  // 총 수행 일수 계산 (frequency에 해당하는 요일만)
  let totalDays = 0
  for (
    let date = new Date(startDate);
    date <= endDate;
    date.setDate(date.getDate() + 1)
  ) {
    const dayOfWeek = date
      .toLocaleString('default', { weekday: 'short' })
      .toLowerCase() 
    if (frequencySet.has(dayOfWeek)) {
      totalDays++
    }
  }

  // 완료된 날짜 수 계산
  const completedCount = habit.completedDates.length

  // 달성률 계산
  const achievementRate =
    totalDays > 0 ? Math.floor((completedCount / totalDays) * 100) : 0

  <HabitCardChart
            completedCount={completedCount}
            totalCount={totalDays}
          />
  • 사용자가 지정한 시작일(startDate)과 종료일(endDate)을 기반으로 Date 객체를 생성한다.
  • habit.frequency는 사용자가 습관을 실행하려는 요일 목록이다. habit.frequency에 포함된 요일(ex: ["Mon", "Wed", "Fri"])을 소문자로 변환 후 Set으로 저장해 중복 제거를 해준다.
  • 시작일부터 종료일까지 하루씩 반복하며 각 날짜의 요일을 추출한다. (수행 요일(frequencySet)에 포함된 날짜만 카운트)

Chart.js의 Doughnut 차트를 사용해 완료/미완료 비율을 시각적으로 표현하기

Chart.js 설치 및 사용법

pnpm add chart.js react-chartjs-2
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';

ChartJS.register(ArcElement, Tooltip, Legend);
  • ArcElement: 도넛 차트의 조각을 그리는 역할
  • Tooltip: 마우스오버 시 데이터 값을 표시하는 역할
  • Legend: 차트의 범례를 그려주는 역할

❓register하는 이유

Chart.js는 경량화를 위해 모든 기능이 기본으로 포함되어 있지 않다.
사용자가 필요한 요소만 명시적으로 등록하면, 불필요한 코드를 제외해 번들 크기를 줄이고 성능을 최적화할 수 있다!

const data = {
    labels: ['완료', '미완료'],
    datasets: [
      {
        label: '달성률',
        data: [completedCount, totalCount - completedCount],
        backgroundColor: ['#1E4A19', '#edecdf'],
        borderWidth: 1,
        borderRadius: 8,
      },
    ],
  }

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'bottom' as const,
        labels: {
          usePointStyle: true,
          boxWidth: 5,
        },
      },
      title: {
        display: true,
        text: '달성률',
      },
    },
  }

 

Data (데이터)

  • labels: 차트 조각의 이름 (예: ['완료', '미완료'])
  • label: 데이터 세트의 이름
  • data: 각 조각의 값
  • backgroundColor: 조각 색상
  • borderWidth: 조각의 테두리 두께
  • borderRadius: 8 (약간 둥글느낌 원해서 넣었음)

+ 차트 옆에 옵션 추가해서 무슨 색이 어떤 라벨인지 표현할 수 있음!!

 

👇🏻풀코드👇🏻

'use client'
import { Doughnut } from 'react-chartjs-2'
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'

ChartJS.register(ArcElement, Tooltip, Legend)

type HabitCardChartProps = {
  completedCount: number
  totalCount: number
}

export default function HabitCardChart({
  completedCount,
  totalCount,
}: HabitCardChartProps) {
  const data = {
    labels: ['완료', '미완료'],
    datasets: [
      {
        label: '달성률',
        data: [completedCount, totalCount - completedCount],
        backgroundColor: ['#1E4A19', '#edecdf'],
        borderWidth: 1,
        borderRadius: 8,
      },
    ],
  }

  const options = {
    responsive: true,
    plugins: {
      legend: {
        position: 'bottom' as const,
        labels: {
          usePointStyle: true,
          boxWidth: 5,
        },
      },
      title: {
        display: true,
        text: '달성률',
      },
    },
  }

  return (
    <div className="size-24 md:size-40">
      <Doughnut data={data} options={options} />
    </div>
  )
}

 

 

위와 같은 방법으로 전체 루틴에 관한 총 달성률도 구현해봤다 🙂

참고