본문 바로가기
SPA/React

[React] Nivo 차트 사용하기

by J4J 2022. 6. 4.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 Nivo 차트 사용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

반응형

 

 

Nivo 차트란?

 

Nivo 차트는 리액트를 이용하여 개발할 때 사용할 수 있는 차트 라이브러리 중 하나입니다.

 

대표적으로 많이 사용되는 Bar, Pie 차트 등을 기본으로 제공하며 그 외에도 Line과 Github 잔디밭을 만들 수 있게 도와주는 Calendar 차트까지도 제공을 해줍니다.

 

 

 

 

Nivo 차트 선택 이유

 

최근 회사에서 프로젝트를 하면서 차트를 사용해야 된다는 얘기를 전달받았습니다.

 

지금까지 리액트를 사용하면서 차트를 사용해본적이 없기 때문에 리액트에서 많이 사용된다는 여러 가지 차트들을 확인했고 결국 저의 선택은 Nivo 차트였습니다.

 

 

 

Nivo 차트를 선택한 첫 번째 이유는 리액트스럽게 개발하고 싶었기 때문입니다.

 

여기서 제가 말한 리액트스럽다는 것은 많은 컴포넌트들로 구성되어 있는 것을 뜻하며, 결국 차트를 가져와 사용할 때도 컴포넌트의 형태로 가져와 사용하는 것을 선호했습니다.

 

차트 라이브러리는 이전부터 정말 많이 사용되고 있었기에 리액트에 최적화 되어 있지 않고 바닐라 스크립트를 기준으로만 만들어진 차트들이 많이 보였습니다. (제가 잘못 찾아본 것일 수도 있습니다. ㅠㅠ)

 

그중 대표적인 게 chartjs가 있었습니다.

 

만약 리액트에 chartjs를 가져와 사용한다고 가정한다면 script 태그를 이용해 라이브러리를 가져오고 생성자를 이용하여 JS기반의 코드를 작성해야 했습니다.

 

이런 방식은 리액트를 개발할 때 변종(?) 같은 느낌을 개인적으로 느끼기에 어쩔 수 없는 상황이 아니면 코드 통일을 위하여 컴포넌트로 사용될 수 있는 차트를 채택하고자 했습니다.

 

해당 이유로 많은 차트 라이브러리들 중 Nivo, Recharts, React ChartJS 2 등으로 선택지가 좁혀졌었습니다.

 

 

 

두 번째이자 마지막 이유는 공식 문서가 친절한가? 였습니다.

 

예전에는 다른 사람들이 작성해둔 블로그 글들을 많이 참고하면서 개발했지만 요즘 공식 문서의 소중함(?)을 많이 느끼고 있기 때문에 공식 문서가 친절한지는 제가 무언가를 사용할 때 고려하는 요소로 자리 잡았습니다.

 

첫 번째 이유에서 필터 된 차트들의 공식문서들을 확인했을 때 제일 눈에 띄었던 것은 Nivo 였습니다.

 

Nivo Bar Chart 공식 문서와 같은 곳을 들어가 보면 다른 곳과 유사하게 차트의 형태가 보이며 해당 차트를 그려내기 위해서 필요한 코드가 무엇인지를 볼 수 있습니다.

 

하지만 가장 영향을 미쳤던 부분은 Nivo를 사용할 때 설정할 수 있는 속성 값들을 공식 문서에서 직접 바꿔서 모두 테스트해볼 수 있었고 또한 변경된 속성 값에 맞게 차트의 형태와 필요한 코드가 모두 변경되는 것입니다.

 

라이브러리를 가져와 사용할 때는 이와 같은 정보들을 정말 소중하게 생각하기 때문에 결국 다른 차트 라이브러리들보다 더 많은 공식 문서 친절함을 가지는 Nivo를 선택하여 사용하기로 결정했습니다.

 

 

 

 

Nivo의 단점

 

단점인지는 정확히 모르겠지만 하나를 말하자면 Nivo를 사용하기 위해 설치해야 할 라이브러리가 무엇인지를 찾기가 힘들었습니다.

 

당연히 공식 문서에서 보일 주 알았는데 저는 찾지 못했고 시간을 투자한 끝에 공식 문서 우측 상단에 Nivo Github에 들어갔더니 다음과 같이 설치 방법이 설명되어 있는 것을 찾을 수 있었습니다.

 

설치 방법

 

 

 

다른 하나는 단순한 차트만 사용할 수 있다는 것입니다.

 

3차원 모양의 차트를 제공한다든지 아니면 Bar와 Line이 같이 표현되어 나오는 혼합된 차트를 제공하는 등의 기능들이 보이지 않습니다.

 

저는 이번에 단순한 차트만 사용할 것이기 때문에 이 부분은 저에게 영향을 미치는 부분은 없었지만 사용을 고려하시는 분들 중 단순한 차트만 사용할 것이 아니면 Nivo는 사용할 리스트에서 제외해주시는 것이 좋을 것 같습니다.

 

 

 

 

사용 방법

 

[ 1. 패키지 설치 ]

 

npm install @nivo/core // 기본적으로 설치

npm install @nivo/bar // bar 차트 사용
npm install @nivo/pie // pie 차트 사용
// 그 외 공식 문서 확인

 

 

 

[ 2. bar 차트 예시 코드 ]

 

import * as React from 'react';
import { ResponsiveBar } from '@nivo/bar';

const Barchart = () => {
    const handle = {
        barClick: (data: any) => {
            console.log(data);
        },

        legendClick: (data: any) => {
            console.log(data);
        },
    };

    return (
        // chart height이 100%이기 때문이 chart를 덮는 마크업 요소에 height 설정
        <div style={{ width: '800px', height: '500px', margin: '0 auto' }}>
            <ResponsiveBar
                /**
                 * chart에 사용될 데이터
                 */
                data={[
                    { bottle: '365ml', cola: 1200, cidar: 1000, fanta: 1100 },
                    { bottle: '500ml', cola: 2200, cidar: 2000, fanta: 2100 },
                    { bottle: '1000ml', cola: 3200, cidar: 3000, fanta: 3100 },
                ]}
                /**
                 * chart에 보여질 데이터 key (측정되는 값)
                 */
                keys={['cola', 'cidar', 'fanta']}
                /**
                 * keys들을 그룹화하는 index key (분류하는 값)
                 */
                indexBy="bottle"
                /**
                 * chart margin
                 */
                margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
                /**
                 * chart padding (bar간 간격)
                 */
                padding={0.3}
                /**
                 * chart 색상
                 */
                colors={['olive', 'brown', 'orange']} // 커스터하여 사용할 때
                // colors={{ scheme: 'nivo' }} // nivo에서 제공해주는 색상 조합 사용할 때
                /**
                 * color 적용 방식
                 */
                colorBy="id" // 색상을 keys 요소들에 각각 적용
                // colorBy="indexValue" // indexBy로 묵인 인덱스별로 각각 적용
                theme={{
                    /**
                     * label style (bar에 표현되는 글씨)
                     */
                    labels: {
                        text: {
                            fontSize: 14,
                            fill: '#000000',
                        },
                    },
                    /**
                     * legend style (default로 우측 하단에 있는 색상별 key 표시)
                     */
                    legends: {
                        text: {
                            fontSize: 12,
                            fill: '#000000',
                        },
                    },
                    axis: {
                        /**
                         * axis legend style (bottom, left에 있는 글씨)
                         */
                        legend: {
                            text: {
                                fontSize: 20,
                                fill: '#000000',
                            },
                        },
                        /**
                         * axis ticks style (bottom, left에 있는 값)
                         */
                        ticks: {
                            text: {
                                fontSize: 16,
                                fill: '#000000',
                            },
                        },
                    },
                }}
                /**
                 * axis bottom 설정
                 */
                axisBottom={{
                    tickSize: 5, // 값 설명하기 위해 튀어나오는 점 크기
                    tickPadding: 5, // tick padding
                    tickRotation: 0, // tick 기울기
                    legend: 'bottle', // bottom 글씨
                    legendPosition: 'middle', // 글씨 위치
                    legendOffset: 40, // 글씨와 chart간 간격
                }}
                /**
                 * axis left 설정
                 */
                axisLeft={{
                    tickSize: 5, // 값 설명하기 위해 튀어나오는 점 크기
                    tickPadding: 5, // tick padding
                    tickRotation: 0, // tick 기울기
                    legend: 'price', // left 글씨
                    legendPosition: 'middle', // 글씨 위치
                    legendOffset: -60, // 글씨와 chart간 간격
                }}
                /**
                 * label 안보이게 할 기준 width
                 */
                labelSkipWidth={36}
                /**
                 * label 안보이게 할 기준 height
                 */
                labelSkipHeight={12}
                /**
                 * bar 클릭 이벤트
                 */
                onClick={handle.barClick}
                /**
                 * legend 설정 (default로 우측 하단에 있는 색상별 key 표시)
                 */
                legends={[
                    {
                        dataFrom: 'keys', // 보일 데이터 형태
                        anchor: 'bottom-right', // 위치
                        direction: 'column', // item 그려지는 방향
                        justify: false, // 글씨, 색상간 간격 justify 적용 여부
                        translateX: 120, // chart와 X 간격
                        translateY: 0, // chart와 Y 간격
                        itemsSpacing: 2, // item간 간격
                        itemWidth: 100, // item width
                        itemHeight: 20, // item height
                        itemDirection: 'left-to-right', // item 내부에 그려지는 방향
                        itemOpacity: 0.85, // item opacity
                        symbolSize: 20, // symbol (색상 표기) 크기
                        effects: [
                            {
                                // 추가 효과 설정 (hover하면 item opacity 1로 변경)
                                on: 'hover',
                                style: {
                                    itemOpacity: 1,
                                },
                            },
                        ],
                        onClick: handle.legendClick, // legend 클릭 이벤트
                    },
                ]}
            />
        </div>
    );
};

export default Barchart;

 

 

 

 

[ 3. pie 차트 예시 코드 ]

 

import * as React from 'react';
import { ResponsivePie } from '@nivo/pie';

const Piechart = () => {
    const handle = {
        padClick: (data: any) => {
            console.log(data);
        },

        legendClick: (data: any) => {
            console.log(data);
        },
    };

    return (
        // chart height이 100%이기 때문이 chart를 덮는 마크업 요소에 height 설정
        <div style={{ width: '800px', height: '500px', margin: '0 auto' }}>
            <ResponsivePie
                /**
                 * chart에 사용될 데이터
                 */
                data={[
                    { id: 'cola', value: 324 },
                    { id: 'cidar', value: 88 },
                    { id: 'fanta', value: 221 },
                ]}
                /**
                 * chart margin
                 */
                margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
                /**
                 * chart 중간 빈공간 반지름
                 */
                innerRadius={0.5}
                /**
                 * pad 간격
                 */
                padAngle={1.8}
                /**
                 * pad radius 설정 (pad별 간격이 있을 시 보임)
                 */
                cornerRadius={8}
                /**
                 * chart 색상
                 */
                colors={['olive', 'brown', 'orange']} // 커스터하여 사용할 때
                // colors={{ scheme: 'nivo' }} // nivo에서 제공해주는 색상 조합 사용할 때
                /**
                 * pad border 두께 설정
                 */
                borderWidth={2}
                /**
                 * link label skip할 기준 각도
                 */
                arcLinkLabelsSkipAngle={0}
                /**
                 * link label 색상
                 */
                arcLinkLabelsTextColor="#000000"
                /**
                 * link label 연결되는 선 두께
                 */
                arcLinkLabelsThickness={2}
                /**
                 * link label 연결되는 선 색상
                 */
                arcLinkLabelsColor={{ from: 'color' }} // pad 색상에 따라감
                /**
                 * label (pad에 표현되는 글씨) skip할 기준 각도
                 */
                arcLabelsSkipAngle={10}
                theme={{
                    /**
                     * label style (pad에 표현되는 글씨)
                     */
                    labels: {
                        text: {
                            fontSize: 14,
                            fill: '#000000',
                        },
                    },
                    /**
                     * legend style (default로 하단에 있는 색상별 key 표시)
                     */
                    legends: {
                        text: {
                            fontSize: 12,
                            fill: '#000000',
                        },
                    },
                }}
                /**
                 * pad 클릭 이벤트
                 */
                onClick={handle.padClick}
                /**
                 * legend 설정 (default로 하단에 있는 색상별 key 표시)
                 */
                legends={[
                    {
                        anchor: 'bottom', // 위치
                        direction: 'row', // item 그려지는 방향
                        justify: false, // 글씨, 색상간 간격 justify 적용 여부
                        translateX: 0, // chart와 X 간격
                        translateY: 56, // chart와 Y 간격
                        itemsSpacing: 0, // item간 간격
                        itemWidth: 100, // item width
                        itemHeight: 18, // item height
                        itemDirection: 'left-to-right', // item 내부에 그려지는 방향
                        itemOpacity: 1, // item opacity
                        symbolSize: 18, // symbol (색상 표기) 크기
                        symbolShape: 'circle', // symbol (색상 표기) 모양
                        effects: [
                            {
                                // 추가 효과 설정 (hover하면 textColor를 olive로 변경)
                                on: 'hover',
                                style: {
                                    itemTextColor: 'olive',
                                },
                            },
                        ],
                        onClick: handle.legendClick, // legend 클릭 이벤트
                    },
                ]}
            />
        </div>
    );
};

export default Piechart;

 

 

 

[ 4. 테스트 ]

 

위와 같이 작성한 chart들을 App.tsx에 다음과 같이 사용해보겠습니다.

 

import * as React from 'react';
import Barchart from './barchart';
import Piechart from './piechart';

const App = () => {
    return (
        <div>
            <Barchart />
            <Piechart />
        </div>
    );
};

export default App;

 

 

 

그리고 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.

 

실행 결과

 

 

 

 

pros-types 에러 발생 case

 

혹시 nivo 를 사용하시는 분들 중 다음과 같은 에러가 발생하시는 분들이 계실수도 있습니다.

 

props-types 에러

 

 

 

해당 문제가 발생하면 다음과 같이 패키지 하나 설치해주시면 에러가 해결될 수 있습니다.

 

$ npm install prop-types

 

 

 

 

 

 

 

이상으로 Nivo 차트 사용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

 

 

 

728x90
반응형

댓글