react nivo 라이브러리 LineChart 커스텀하기

구구·2023년 1월 24일
1

🪴 그래프 라이브러리 커스텀

라이브러리는 nivo 사이트에서 LineChart 를 사용하였습니다.

라이브러리를 사용한 분들의 기록이 많이 없고, 각요소에 클래스명이 부여되지 않아서 커스텀하기가 까다로웠습니다.

시행착오를 겪고 있는 다른분들도 이 블로그를 보고 도움이 되었으면 좋겠습니다.

아래에 커스텀한 내용을 자세히 기록하였습니다.

// 그래프에 넣어줄 데이터 state값
const [tempData, setTempData] = useState([]);
const [humidityData, setHumidityData] = useState([]);
const [pressureData, setPressureData] = useState([]);
// 기온, 습도, 압력 그래프
// 원래는 데이터만 넘겨주면 되지만 커스텀하여 단위, 색, onClick 함수를 같이 넘겨줍니다.
<Graph data={tempData} unit={'Temperature (°C)'} color={'Lightcoral'} getTargetTime={getTargetTime} />
<Graph data={humidityData} unit={'Humidity (%)'} color={'Mediumaquamarine'} getTargetTime={getTargetTime} />
<Graph data={pressureData} unit={'Pressure (hPa)'} color={'Slateblue'} getTargetTime={getTargetTime} />
// 기존 라이브러리 코드
// 수정될 부분을 표시해두었습니다.
import { ResponsiveLine } from '@nivo/line'

const MyResponsiveLine = ({ data}) => (
    <ResponsiveLine
        // 여기에 colors, theme 속성이 추가됩니다.
        data={data}
        margin={{ top: 50, right: 110, bottom: 50, left: 60 }}
        xScale={{ type: 'point' }}
        yScale={{
            type: 'linear',
            min: 'auto',
            max: 'auto',
            stacked: true,
            reverse: false
        }}
        // 여기에 curve 속성이 추가됩니다.
        yFormat=" >-.2f"
        axisTop={null}
        axisRight={null}
        axisBottom={{
            orient: 'bottom',
            tickSize: 5,
            tickPadding: 5,
            tickRotation: 0, // tickRotation 값이 바뀝니다.
            legend: 'transportation',  // legend 값이 바뀝니다.
            legendOffset: 36,
            legendPosition: 'middle'
        }}
        axisLeft={{
            orient: 'left',
            tickSize: 5,
            tickPadding: 5,
            tickRotation: 0,
            legend: 'count',  // legend 값이 바뀝니다.
            legendOffset: -40,
            legendPosition: 'middle'
        }}
        pointSize={10}
        pointColor={{ theme: 'background' }}
        pointBorderWidth={2}
        pointBorderColor={{ from: 'serieColor' }}
        pointLabelYOffset={-12}
        useMesh={true}
        legends={[  // legends 값이 바뀝니다.
            {
                anchor: 'bottom-right',
                direction: 'column',
                justify: false,
                translateX: 100,
                translateY: 0,
                itemsSpacing: 0,
                itemDirection: 'left-to-right',
                itemWidth: 80,
                itemHeight: 20,
                itemOpacity: 0.75,
                symbolSize: 12,
                symbolShape: 'circle',
                symbolBorderColor: 'rgba(0, 0, 0, .5)',
                effects: [
                    {
                        on: 'hover',
                        style: {
                            itemBackground: 'rgba(0, 0, 0, .03)',
                            itemOpacity: 1
                        }
                    }
                ]
            }
        ]}
        // onClick 속성이 추가됩니다.
    />
)
// 커스텀한 코드
import styled from 'styled-components';
import { ResponsiveLine } from '@nivo/line';

const Graph = ({ data, unit, color, getTargetTime }) => {
  return (
    <GraphWrapper>
      <ResponsiveLine
        colors={color}  // color를 props로 받아서 설정해줍니다.
        theme={{  // theme에서 x, y축 글씨 색을 바꿔줍니다.
          textColor: blue,
        }}
        data={data}
        margin={{ top: 10, right: 10, bottom: 70, left: 70 }}
        xScale={{ type: 'point' }}
        yScale={{
          type: 'linear',
          min: 'auto',
          max: 'auto',
          stacked: true,
          reverse: false,
        }}
        yFormat='>-.2f'
        curve='catmullRom'  // 선 종류를 설정해줍니다. (라이브러리 문서 참고)
        axisTop={null}
        axisRight={null}
        axisBottom={{
          orient: 'bottom',
          tickSize: 5,
          tickPadding: 5,
          tickRotation: -90,  // x축 텍스트를 회전시켜줍니다. (세로)
          legend: 'Date',  // x 축 단위를 표시합니다.
          legendOffset: 60,
          legendPosition: 'middle',
        }}
        axisLeft={{
          orient: 'left',
          tickSize: 5,
          tickPadding: 5,
          tickRotation: 0,
          legend: unit,  // y축 왼쪽에 표시될 단위입니다.
          legendOffset: -55,
          legendPosition: 'middle',
        }}
        pointSize={5}
        pointColor={{ theme: 'background' }}
        pointBorderWidth={2}
        pointBorderColor={{ from: 'serieColor' }}
        pointLabelYOffset={-12}
        useMesh={true}
        legends={[]} // 그래프 오른쪽의 포인트를 지워줍니다.
        onClick={e => {  // 클릭시 해당 x 값을 부모 컴포넌트에서 가져갑니다.
          getTargetTime(e.data.x);
        }}
      />
    </GraphWrapper>
  );
};

export default Graph;

// 그래프 라이브러리에 높이 값을 주지 않으면 그래프가 나타나지 않습니다.
// 높이값을 꼭 주세요!
const GraphWrapper = styled.div`
  padding: 10px;
  
  @media screen and (min-width: 1024px) {
    height: 280px;
  }
  
  @media screen and (min-width: 768px) and (max-width: 1023px) {
    height: 260px;
  }

  @media screen and (min-width: 480px) and (max-width: 767px) {
    height: 240px;
  }
  
  @media screen and (max-width: 479px) {
    height: 220px;
  }
`;

0개의 댓글