Chart.js로 방사형 차트 그리기 (React, Typescript)

silnoon·2023년 1월 11일
8
post-thumbnail

솝트 30기 앱(웹)잼이 시작되었습니다. 저희 서비스는 프로젝트 중 팀원들의 생각을 공유하며 발전할 수 있도록 도와주는 서비스입니다. 채팅 형식으로 팀원들의 의견을 모아 개인 결과, 팀 결과를 분석해서 보여줍니다.

👩🏻‍💻 저에게는 예쁘게 그려진 방사형 차트를 만드는 임무가 주어졌습니다.

⬆️ 구현해야 할 차트 (w/ 피그마)

🤔 어떻게 구현하지?

1. 직접 구현

canvas에 직접 다각형을 그리는 방법을 구글링했습니다. 삼각함수로 다각형의 꼭지점의 좌표를 구해 여러 다각형을 그릴 수 있습니다. 원의 총 각도를 radian으로 구하고 좌표값을 구해 점을 찍고 그 점을 잇는 방식으로 구현할 수는 있을 것 같아 보였습니다.

번들 사이즈 문제와 더불어 타입스크립트와 사용하게 되면 예상하지 못한 타입 오류에 마주할 수 있기 때문에 최대한 라이브러리 사용을 지양하고자 했으나, 이 값을 일일이 좌표에 찍어주고 있자니 짧은 앱잼 기간에 차트만 잡고 있겠다는 생각이 들었습니다.

2. 라이브러리 비교

2-1. Chart.js

https://www.chartjs.org/ (204.9kB)

Chart.js는 차트 라이브러리 중 가장 많은 깃허브 스타와 npm 다운로드 수를 기록했다고 합니다. 검색했을 때도 소스가 많아 보이는 대중성 있는 라이브러리같아 보였습니다. 공식 깃허브에 들어가 보니 v.4.2가 가장 최신 업데이트였고, 업데이트 날짜가 몇 주 전이었습니다.(!) 제가 구현하려는 차트는 단순한 모양으로, 원하는 차트를 구현하는 데에는 무리가 없어 보여 chart.js를 찜 해놓고 하나를 더 찾아보았습니다.

2-2. Plotly

Plotly도 그래프 라이브러리입니다. 점 그래프, 막대 그래프 등 지도 위에 데이터를 표시 할 수 있고 3D 차트도 그릴 수 있습니다. Potly의 업데이트도 활발히 이루어지는 것처럼 보였습니다.
https://plotly.com/javascript/ (3.5mB)

사이트에 들어가 보면 상당히 다양한 종류의 차트를 구현할 수 있는 것으로 보입니다.

➡️ 그러나 결과적으로 적은 번들 사이즈로 소스가 많으며, 원하는 모양으로 충분히 구현 가능한 Chart.js를 사용하기로 결정했습니다.



1. Chart.js 설치

yarn add react-chartjs-2 chart.js

리액트를 사용하고 있기 때문에 react-chartjs-2도 함께 설치해 주었습니다. (yarn)

2. Chart 컴포넌트

1. import { Radar } from 'react-chartjs-2';
2. import { Chart as ChartJS } from 'chart.js/auto';
3. import type { ChartOptions } from 'chart.js';

1. 방사형 차트를 만들어야 하기 때문에 react-chartjs-2에서 Radar를 import 해줍니다. 이 모듈은 리턴문에서 컴포넌트로 쓰입니다.

2. 사용하는 속성을 등록(register)해줘야하기 때문에 속성을 import 해옵니다. chart.js/auto에서 가져오면 사용하는 속성을 자동으로 가져와줍니다.

3. chart.js에서 options에 쓰이는 타입을 가져옵니다.

      <StRadar>
        <Radar data={chartData} options={chartOptions} />
      </StRadar>

data : 차트가 나타낼 데이터 값을 넣어주는 props
options : 차트의 속성인 옵션을 지정하는 props

참고로 저는 차트를 담아두는 공간으로 StRadar를 이용해 스타일링을 했습니다.

3. data props

  const chartData = {
    labels: ['협업', '성장', '동기부여', '개인생활', '건강'],
    datasets: [
      {
        label: '팀 점수',
        data: data,
        backgroundColor: 'rgba(255, 108, 61, 0.2)',
      },
    ],
  };

labels : 각 요소들의 이름
datasets : 차트가 나타내는 데이터셋. '팀 점수'라는 이름의 데이터를 지정한 backgroundColor에 맞춰 보여줍니다. data는 숫자 다섯 개로 이루어진 배열입니다. ex.[6.6, 5.2, 9.1, 5.6, 5.5]

4. options props

  const chartOptions: ChartOptions<'radar'> & ChartOptions = {
    elements: {
      //데이터 속성.
      line: {
        borderWidth: 2,
        borderColor: COLOR.ORANGE_1,
      },
      //데이터 꼭짓점.
      point: {
        pointBackgroundColor: COLOR.ORANGE_1,
      },
    },
    scales: {
      r: {
        ticks: {
          stepSize: 2.5,
          display: false,
        },
        grid: {
          color: COLOR.GRAY_9E,
        },
        //라벨 속성 지정.
        pointLabels: {
          font: {
            size: 12,
            weight: '700',
            family: 'Pretendard',
          },
          color: COLOR.BLACK,
        },
        angleLines: {
          display: false,
        },
        suggestedMin: 0,
        suggestedMax: 10,
      },
    },
    //위에 생기는 데이터 속성 label 타이틀을 지워줍니다.
    plugins: {
      legend: {
        display: false,
      },
    },
    //기본 값은 가운데에서 펴져나가는 애니메이션 형태입니다.
    animation: {
      duration: 0,
    },
  };

다양한 option을 설정해 줄 수 있습니다. 아까 import해준 ChartOptions<'radar'>과 ChartOptions를 타입으로 지정해 주었습니다. 공식 문서에 가서 원하는 타입의 차트 문서를 찾아보면 사용할 수 있는 옵션이 설명되어 있어 참고하며 작성했습니다.
Radar chart 옵션 링크

0~10까지 값을 가지며 0, 2.5, 5, 7.5 10으로 나뉜 그래프가 완성됩니다. 짠

5. 고민 중인 부분 (*backgroundColor)

원하는 차트의 오각형 부분 배경에는 흰색의 배경이 지정되어 있습니다.

scales: {
      r: {
      	backgroundColor: 'white'
        }
       }

옵션에 이와 같이 지정하니 원하는 대로 배경을 흰색으로 채워주지만 타입 형식에 backgroundColor가 없다며 타입 에러가 났습니다. 여러 옵션 타입을 찾아보았지만 빨간줄이 사라지지 않아, 다소 무식한 방법으로 코드는 길어졌지만 원하는 모양을 나타내는 방법을 찾았습니다.

    datasets: [
      {
        label: '팀 점수',
        data: data,
        backgroundColor: 'rgba(255, 108, 61, 0.2)',
      },
      {
        label: '배경1',
        data: [2.5, 2.5, 2.5, 2.5, 2.5],
        borderColor: 'gray',
        backgroundColor: 'white',
        borderWidth: 1,
        pointBackgroundColor: 'transparent',
        pointBorderColor: 'transparent',
      },
	//(...배경2는 5, 배경3은 7.5, 배경4는 10으로 dataset에 추가)
    ],

이와 같은 식으로 배경이 흰색이며 테두리가 회색인 dataset 4개를 추가했습니다. 가장 밑에 있는 [10, 10, 10, 10, 10]의 값을 가진 dataset이 가장 나중에 옵니다.

📊 완성된 그래프


Chart.js 라이브러리를 이용해 방사형 차트를 구현해보았습니다. 여러 옵션이 있고 공식 문서에도 정리가 잘 되어 있어 차트를 구현하기 좋은 라이브러리라는 생각이 들었습니다.

차트 내 배경색은 원하는 방식으로 구현하지 못해 아쉬움이 남네요! 혹시 아시는 분이 계시다면 알려주시면 감사하겠습니다 :) 긴 글 읽어주셔서 감사합니다.

profile
원래 실눈캐가 사기캐잖아요 (v ̄▽ ̄)

0개의 댓글