React에서 Chart.js 사용하기 (with TypeScript)

남주영·2022년 4월 10일
64

개발 기록

목록 보기
4/5
post-thumbnail

한 프로젝트에서 chart.js를 이용해 차트를 그리는 것을 해보고 싶었는데, 감사하게도 팀원들이 저에게 맡겨줬기에 이를 구현하며 알게 된 지식을 공유하려고 합니다!

설치하기

리액트에서 Chart.js를 사용하려면 chart.js 뿐만 아니라 리액트에서 Chart.js를 렌더링하기 위해 필요한 react-chartjs-2도 설치를 해야 합니다.

yarn add react-chartjs-2 chart.js
npm install react-chartjs-2 chart.js

차트 그리는 방법

리액트에서 Chart.js로 차트를 그리는 방법을 요약하자면 아래와 같습니다.

  1. 차트 컴포넌트 - 리액트에서는 컴포넌트로 차트를 그릴 수 있습니다.
  2. register - 사용하려는 차트 컴포넌트뿐만 아니라 차트를 그리는 데에 필요한 것들을 import 한 후 register 해야 합니다.
  3. 다양한 option - 다양한 option과 plugin을 통해 차트를 커스텀 할 수 있습니다.

위 각각의 항목에 대해 자세히 알아보도록 하겠습니다!

1. 차트 컴포넌트

리액트에서는 컴포넌트로 차트를 그릴 수 있습니다.
Line, Bar, Bubble 등 차트 종류 별로 컴포넌트를 react-chartjs-2에서 import 해와 사용하면 됩니다.

한 차트에서 여러 종류의 그래프를 표현해야 한다면 특정 종류의 차트가 아닌 Chart 컴포넌트를 사용하면 됩니다. (Multitype Chart)
➡️ 예시 보러 가기

<Line data={data} />
<Bar data={data} options={options} />
<Chart type='bar' data={data} />

차트의 종류는 Chart.js 공식 문서의 Chart Types에서 확인할 수 있습니다.

data 객체

컴포넌트의 prop을 보면 data, type, options 같은 것들이 있는데 options는 뒤에서 다룰 예정입니다.
type은 Multitype Chart 외에는 굳이 써주지 않아도 됩니다.

data는 말그대로 차트에 들어갈 데이터를 담고 있는 객체를 넣어줘야 하고, 이것이 제대로 갖춰지지 않으면 차트가 렌더링되지 않습니다.

data 객체의 형태 예시와 그 타입은 아래와 같습니다.

const data = {
    labels,
    datasets: [
      {
        data: data,
        borderColor: "#F1B0BC",
        backgroundColor: "#97CDBD",
      },
    ],
  }
export interface ChartData<
  생략
> {
  labels?: TLabel[];
  datasets: ChartDataset<TType, TData>[];
}

보다시피 labels는 optional인데 이와 관련해서는 아래에서 간단히 다룹니다.

datasets는 데이터 관련 정보(값, 컬러, 라벨 등)을 담은 dataset 객체들을 가지고 있는 배열입니다.
한 차트에 다양한 데이터를 그릴 수도 있기 때문에 배열 형태로 저장합니다.
dataset의 속성은 자유롭게 설정해줄 수 있습니다.

예를 들어 label을 넣어줄 수도 있고, Bar 컴포넌트의 각각의 y축에 다른 컬러를 지정하고 바의 너비도 지정할 수 있습니다.

datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]

color 관련 속성을 넣어주지 않을 수도 있습니다. 그렇다면 흑백으로 렌더링이 됩니다.

이렇게 자유도가 높으니 원하는 디자인에 맞게 data 객체를 설정해주면 됩니다.
다양한 예시를 참고하면 좋습니다.

data 객체에 값 설정하기

data 객체에 값을 설정하는 방법은 두 가지가 있습니다.
labels 속성을 활용하느냐, 하지 않느냐에 따라 달라집니다.


아래에서 위 차트를 각각의 방법을 사용해서 만든 예시를 보겠습니다.

예시 출처 - https://tech.toktokhan.dev/2021/07/20/start-chartjs/

labels 활용 O
labels가 y축 index가 되어줍니다.
dataset 객체의 data에 그에 대치하는 값이 담긴 배열을 넣어줍니다.

import styled from 'styled-components';
import { Line } from 'react-chartjs-2';

const data = {
  labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
  datasets: [
    {
      type: 'line',
      label: 'Dataset 1',
      borderColor: 'rgb(54, 162, 235)',
      borderWidth: 2,
      data: [1, 2, 3, 4, 5],
    },
    {
      type: 'bar',
      label: 'Dataset 2',
      backgroundColor: 'rgb(255, 99, 132)',
      data: [1, 2, 3, 4, 5, 6],
      borderColor: 'red',
      borderWidth: 2,
    },
    {
      type: 'bar',
      label: 'Dataset 3',
      backgroundColor: 'rgb(75, 192, 192)',
      data: [1, 2, 3, 4, 5, 6],
    },
  ],
};

const Chart = () => {
  return (
    <Container>
      <Chart data={data} />
    </Container>
  );
};

export default Chart;

const Container = styled.div`
  width: 90vw;
  max-width: 900px;
`;

참고로 이 경우에 labels가 없으면 오류는 나지 않지만 렌더링이 되지 않습니다.

labels 활용 X
dataset 객체의 data 배열의 각각의 원소를 {x: 어쩔, y: 저쩔} 형태의 객체로 넣습니다.

const data = {
  // labels 사용 안 함
  // labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
  datasets: [
    {
      type: 'line',
      label: 'Dataset 1',
      borderColor: 'rgb(54, 162, 235)',
      borderWidth: 2,
      data: [
        { x: 'January', y: 1 },
        { x: 'February', y: 2 },
        { x: 'March', y: 3 },
        { x: 'April', y: 4 },
        { x: 'May', y: 5 }
      ],
    },
    {
      type: 'bar',
      label: 'Dataset 2',
      backgroundColor: 'rgb(255, 99, 132)',
      data: [
        { x: 'January', y: 1 },
        { x: 'February', y: 2 },
        { x: 'March', y: 3 },
        { x: 'April', y: 4 },
        { x: 'May', y: 5 },
        { x: 'June', y: 6 }
      ],
      borderColor: 'red',
      borderWidth: 2,
    },
    {
      type: 'bar',
      label: 'Dataset 3',
      backgroundColor: 'rgb(75, 192, 192)',
      data: [
        { x: 'January', y: 1 },
        { x: 'February', y: 2 },
        { x: 'March', y: 3 },
        { x: 'April', y: 4 },
        { x: 'May', y: 5 },
        { x: 'June', y: 6 }
      ],
    },
  ],
};

차트 크기 조절하기

아래의 '3. 다양한 option' 부분의 'responsive'에서 설명합니다.

2. register

react-chartjs-2에서 import 해오는 차트 컴포넌트와 별개로 chart.js에서 필요한 것들을 import 해온 후 register를 해야 차트를 렌더링 할 수 있습니다.

Chart.js는 일반 자바스크립트 프로젝트인지, Webpack, Rollup과 같은 번들러를 사용하는 프로젝트인지 여부에 따라 모듈을 로드하는 방식이 달라집니다.
우리는 리액트 프로젝트에서 사용할 것이기 때문에 번들러를 사용할 때의 방식을 따릅니다.

방법은 아래와 같이 필요한 것들을 import 해온 후, Chart(ChartJS)의 register 함수에 넣어주면 됩니다.

import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
} from "chart.js";

ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement);

수많은 컨트롤러, 엘리먼트, 스캐일(Scale) 등이 있지만 필요한 것들만 해주면 됩니다.

기능마다 정확히 어떤 것들이 필요한지 잘 정리되어 있는 문서를 찾지는 못했습니다.
그래서 저는 react-chartjs-2 공식 문서의 컴포넌트 사용 예시를 참고하기도 했고,
필요한 것이 register 되지 않았다면 차트가 렌더링 되지 않고 에러를 발생시키니 어떤 것이 필요한지 쉽게 알 수 있었습니다.

예를 들어 Line 컴포넌트에서 필수인 LineElement를 register 하지 않는다면 다음과 같은 오류가 나며 차트가 렌더링되지 않습니다.

3. 다양한 option

차트 컴포넌트의 options prop을 통해 dataset 객체에서 설정하는 것 이외에도 아주 다양하게 차트를 커스텀 할 수 있습니다.

굉장히 다양한 옵션이 있기 때문에 제가 실제로 사용했던 몇 가지만 적어보도록 하겠습니다.

참고하면 좋을만한 곳
chartjs 공식 문서 - options, configuration
react-chartjs-2 공식 문서의 example

살펴볼 예시의 최종 형태는 아래와 같습니다.

...

export default function Chart(props: ChartProps) {
  ...

  const options = {
    // 옵션 (1)
    responsive: false,
    // 옵션 (2)
    interaction: {
      mode: "index" as const,
      intersect: false,
    },
    // 옵션 (3)
    scales: {
      x: {
        grid: {
          display: false,
        },
      },
      y: {
        grid: {
          color: "#E3E3E3",
        },
      },
    },
  };
  ...
  return (
    ...
      <Line options={options} data={data} width="894px" height="320px" />
    ...
  );
}

...

여기서 쓰인 option을 하나하나 살펴보도록 하겠습니다.

(1) responsive

이것은 container(부모 엘리먼트) 크기에 맞춰 차트가 반응형이 될지 말지 여부입니다.
제가 만들고자 했던 차트의 디자인은 반응형을 고려하지 않았기에 false로 설정해주었습니다.

true로 설정해주면 container에 맞춰 아주 유연하게 차트의 비율이 조절됩니다.

이 옵션에 따라 차트의 크기를 지정하는 방법도 두 가지가 될 수 있습니다.

  1. 이 예시처럼 responsivefalse로 하고 차트 컴포넌트에 직접 prop으로 width, height를 줄 수 있습니다.
  2. responsivetrue로 하고 container를 따로 만들어서 container 크기에 맞출 수 있습니다. 이 경우에는 차트 컴포넌트에 prop으로 width, height를 줘도 무시해버립니다.

(2) interaction

이는 차트 데이터 각각의 지점에 커서를 올리면 뜨는 이 친구를 말합니다.

interaction: {
      mode: "index" as const,
      intersect: false,
    },

modeintersect를 어떻게 설정하느냐에 따라 다르게 표현됩니다.

  • mode는 매우 다양하므로 아래에 첨부한 글을 참고하시는 것이 좋겠습니다.
  • intersect는 근처에만 가도 뜨게 할 것인지 직접 커서를 올려야 가야 뜨게 할 것인지를 말합니다. true가 default이며 후자(직접 커서 올려야)로 설정되는 것을 의미합니다. 이 또한 말로만 해서는 이해가 안될 수 있으니 아래 문서를 한 번 보는 것을 추천합니다.

이는 아래 자료에서 각각의 설정에 따라 어떻게 달라지는지 다양한 예시를 직접 확인해볼 수 있습니다.
< https://minaminaworld.tistory.com/182 >

우리 예시는 mode는 디자인 요구 사항에 따랐으며,
intersect는 라인 위의 점이 작기 때문에 직접 커서를 가져다 대는 것이 까다롭다고 판단하여 false로 설정해주었습니다.

<mode: "index"as const를 붙여준 이유>
타입스크립트를 사용할 때에는 이렇게 하지 않으면 오류가 나기 때문입니다.
오류 내용은 아래와 같습니다.
Type 'string' is not assignable to type '"index" | "x" | "y" | "dataset" | "point" | "nearest" | undefined'.
리터럴 타입 몇 가지와 undefined로 이루어진 유니언 타입이어야 하는데 그냥 string 타입이 왔기 때문에 오류가 난 것입니다.
그런데 string 타입에 as const를 붙여주면 리터럴 타입이 되기 때문에 이렇게 해결했습니다. 타스 꿀팁!~

(3) scales

scale은 척도라는 뜻인데 차트에서 척도가 의미하는 바를 정확히 이해하진 못했습니다.
그렇지만 우리는 차트 전문가는 아니니 디자인 요구 사항에 맞게 구현만 잘 하면 되지 않겠습니깐,, 그 정도로 설명해보겠습니다!

scales는 굉장히 다양한 옵션이 다양한데 이 또한 우리 예시에서 사용된 것 외에는 관련 자료를 참고하는 것이 좋겠습니다.

이곳에서는 여러 종류의 그래프를 그리고 있어서 축에 id 값도 지정해서 scale을 다양하게 다루고 있습니다.
https://react-chartjs-2.js.org/examples/multiaxis-line-chart/

우리 예시를 보겠습니다.

scales: {
      x: {
        grid: {
          display: false,
        },
      },
      y: {
        grid: {
          color: "#E3E3E3",
        },
      },
    },

x축 y축 각각에 grid 속성을 설정해줬는데, grid가 무엇인지는 이미지로 설명하는 것이 좋겠습니다.
y축의 grid color를 빨간색으로 바꿔봤습니다.

x축은 디자인 요구 사항에서 보이지 않아야 했기 때문에 display: false을 통해 보이지 않게 해주었습니다.

참고 자료

profile
Sharing is Caring. 🪐

1개의 댓글

comment-user-thumbnail
2022년 4월 10일

나중에 차트 사용할 때 아주 유용한 글일 것 같아요 잘 보고 갑니다!

답글 달기