[Chart.js] 차트를 그려보자 - 바닐라, React, Vue에서 Chart.js로 차트그리기

권준혁·2021년 1월 15일
3

chart

목록 보기
1/1
post-thumbnail

Chart.js 는 유용한 자바스크립트 차트 라이브러리다.
바닐라 자바스크립트로도 차트를 그릴 수 있고, 프레임워크들과의 통합도 쉽다.
그리고 크로스 브라우징이 가능하다.
다양한 형태의 차트들도 제공하고 있다.

Vue에서 Chart.js를 사용하는 방법을 간단히 포스팅하겠다.
Chart.js가 쉬운 이유는 단순히 canvas를 이용해 노드에 그림을 그린다는 점이다.
렌더할 노드와 옵션만 선택하면 된다.


기본사용법

간단한 사용방법은 이렇다.

  • canvas DOM node 만든다.
  • 선택한 canvas 노드에 getContext('2d')를 이용해 context를 변수에담는다.
  • Chart.js 메서드를 이용해 차트를 생성한다. context변수와 옵션이 인자로 전달된다.

먼저 chart.js를 설치한다.
공식문서 : 설치

yarn add chart.js

주의점

대략적인 사용방법은 이렇다.
바닐라나 JQuery처럼 돔을 직접 조작하는 형태에서는 라이프사이클을 신경쓰지 않아도 되지만,
Vue나 React처럼 가상돔을 이용하는 경우, 라이프사이클에 따라 DOM노드에 접근하지 못할 수도 있다.

가상돔에대해 간단히 말하자면, 메모리에 가상의 DOM을 두고 실제 DOM과 비교해 변경점만을 업데이트 하는 방식인데, Vue와 React에서 실제 돔요소에 직접 접근하는 API인 ref가 있다.
그리고 이 ref로 접근할 때 라이프사이클에 따라 접근하려는 돔 요소가 없을 수 있다는 것이다.

Chart.js의 메서드에서 canvas돔 요소의 context가 필요하다고 했다.
결론은
Vue에서는 mounted 이 후에 돔요소에 접근해 context를 가져와야 하고
React에서는 componentDidMount 또는 함수형 컴포넌트의 useEffect에서 mounted된 시점에 context를 가져와야 한다.

만약 외부 API를 이용해 데이터를 가져오고 화면에 차트를 그려야 하는 상황이라면,
Vue에서는 created 시점에 데이터를 가져와 mounted시점에 chart를 그리고,
React에서는 undefined를 객체처럼 사용(마운트 이전에 돔요소 접근 등)해 에러가 발생하지 않도록 비동기적으로 코드를 작성해야겠다.


Vue에서 사용하기

1. chart.js가져오기

import Chart from "chart.js";

export default {
   data() {
    return {
      Chart,
    };
  }, 
}

2. DOM요소

먼저 템플릿 태그 내부에 canvas요소를 작성한다.
width와 height도 디렉티브를 이용해 동적으로 입력되도록 변경해도 된다.

<canvas class="statistics-charts-line" ref="lineChart" width="500" height="400"></canvas>

3. 라이프사이클

  async created() {
    // 필요 시 데이터 가져오는 로직
    // 차트생성에 사용할 옵션과 데이터가 결정될 것이다.
  },
  async mounted() {
    // 마운트 된 두 ref에 접근할 수 있으므로 마운트 뒤 차트를 그린다.
    await this.drawChart();
  },
  methods: {
    drawChart() {
      const chartCtx = this.$refs.lineChart.getContext("2d");
      console.log(chartCtx, "chartCtx?");
      // context와 Chart.js객체, 데이터가 결정됐으니  그리기만 하면된다.
    },
  }

4. 차트그리기

공식문서 를 참고해 차트를 그리자.
링크의 기본 데이터를 이용해봤다.

잘 그려지는걸 확인했다.
애니메이션에 대한 설정, 범례, 데이터추가, 색상 등 다양한 디테일한 요소들은 공식문서의 API를 이용해 변경하면 되겠다.


React에서 차트그리기

라이프사이클은 마찬가지지만 코드가 다르다.

1. chart.js 가져오기

import Chart from 'chart.js';

2. DOM요소 렌더 및 ref 설정

function App() {
  const chartRef = React.useRef(null);

  return (
    <>
    <GlobalStyle />
    <Container>
      <ChartWrapper>
        <canvas ref={chartRef} />
      </ChartWrapper>
    </Container>
    </>
  );
}

3. 라이프사이클

함수형으로 작성했다.
컴포넌트가 마운트 된 뒤 접근하도록 useEffect를 추가한다.
비동기적으로 chartData를 가져와 해당데이터를 이용해 차트를 그린다.

  React.useEffect(() => {
    const drawChart = async () => {
      const ctx = chartRef.current.getContext('2d');
      const {chartData} = await import("./chartData");
      await new Chart(ctx, chartData);
    }
    drawChart();
  }, []);

4. 차트그리기

영역을 가득 채워주기 때문에 ChartWrapper컴포넌트의 크기를 조절해주면된다.

5. 리액트 전체코드

import React from 'react';
import reset from "styled-reset";
import styled, {createGlobalStyle} from 'styled-components';
import Chart from 'chart.js';

const Container = styled.div`
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: white;
`;
const ChartWrapper = styled.div`
  width: 600px;
  height: 500px;
`;
const GlobalStyle = createGlobalStyle`
    ${reset}
`;

function App() {
  const chartRef = React.useRef(null);

  React.useEffect(() => {
    const drawChart = async () => {
      const ctx = chartRef.current.getContext('2d');
      const {chartData} = await import("./chartData");
      await new Chart(ctx, chartData);
    }
    drawChart();
  }, []);

  return (
    <>
    <GlobalStyle />
    <Container>
      <ChartWrapper>
        <canvas ref={chartRef} />
      </ChartWrapper>
    </Container>
    </>
  );
}
export default App;

profile
웹 프론트엔드, RN앱 개발자입니다.

0개의 댓글