Recharts 라이브러리를 사용해서 이렇게 생긴 라인 차트를 만들어보자.
Recharts 로 라인 차트 뿐만 아니라 Bar, Area, Composed, Pie 등 다양한 차트를 만들 수 있으니 해당 부분은 공식 문서를 참고하자.
이 포스트에서는 Line Chart 와 위 차트를 구현하는데 필요한 컴포넌트 및 props의 API만 정리할 예정이다.
라인 차트를 커스텀 해보자. 전체 props는 Docs에서 확인할 수 있다.
<LineChart data={someData}></LineChart>
차트를 그릴 데이터를 지정한다.
<LineChart width={800} height={400}></LineChart>
차트의 너비와 높이를 지정한다. 단, 부모 컴포넌트 <ResponsiveContainer>
로 width와 height를 지정한다면, 라인 차트의 너비와 높이는 지정하지 않는다.
<LineChart margin={{ top: 5, right: 5, bottom: 5, left: 5 }}></LineChart>
차트의 margin을 커스텀한다.
const mouseEnterHandler = () => {
setIsEntered(true);
};
<LineChart onMouseEnter={mouseEnterHandler}></LineChart>
각 이벤트가 발생할 때 실행할 핸들러 함수를 지정한다.
LineChart의 자식 컴포넌트는 다음과 같다.
component | 역할 |
---|---|
<XAxis /> | X축 |
<YAxis /> | Y축 |
<ReferenceArea /> | 특정 영역 강조 표시 |
<ReferenceDot /> | 특정 값 강조 표시 (점) |
<ReferenceLine /> | 특정 값 강조 표시 (선) |
<Brush /> | X값 중 일부 영역의 데이터만 보여주기 (이동 가능) |
<CartesianGrid /> | 그래프 그리드 보조선 |
<Legend /> | 그래프 범례 |
<Tooltip /> | 커서 가져가면 보여지는 네모 박스 |
<Line /> | 그래프 직선 |
<Customized /> |
이 중 필요한 컴포넌트만 다음과 같이 구성했다.
<ResponsiveContainer>
<LineChart>
<XAxis />
<YAxis />
<Tooltip />
<ReferenceLine />
<Line />
</LineChart>
</ResponsiveContainer>
x축을 커스텀 해보자. 전체 내용은 Docs에서 확인할 수 있다. y축도 비슷한 props 를 가지므로 한꺼번에 정리하자.
<XAxis dataKey='createdAt' />
LineChart
에서 지정했던 데이터 중 축이 될 데이터의 키를 지정한다.
<XAxis type='category' />
'category' 혹은 'number' 로 축의 타입을 지정한다. 'category' 의 경우 범주형, 'number' 의 경우 연속형 데이터를 의미한다.
<XAxis type="number" domain={['dataMin', 'dataMax']} />
<XAxis type="number" domain={[0, 'dataMax']} />
<XAxis type="number" domain={['auto', 'auto']} />
<XAxis type="number" domain={[0, 'dataMax + 1000']} />
<XAxis type="number" domain={['dataMin - 100', 'dataMax + 100']} />
<XAxis type="number" domain={[dataMin => (0 - Math.abs(dataMin)), dataMax => (dataMax * 2)]} />
<XAxis type="number" domain={([dataMin, dataMax]) => { const absMax = Math.max(Math.abs(dataMin), Math.abs(dataMax)); return [-absMax, absMax]; }} />
축의 범위를 지정한다. 최소부터 최대, 자동 지정, 최대 + 1000 등 다양한 도메인을 지정할 수 있다.
<XAxis tickLine={false} />
default 값은 true로 축에 tick line (눈금선)이 있다. 이를 없애고 싶으면 false로 설정한다.
<XAxis stroke='#eee' />
x축/y축의 색상을 지정한다.
<XAxis padding={{ left: '8px', right: '8px' }} />
<YAxis padding={{ top: '4px', bottom: '8px' }} />
x축/y축의 padding을 지정한다. 단 x축은 left와 right만 지정할 수 있고, y축은 top과 bottom만 지정할 수 있다.
축에 표시되는 숫자 (혹은 글자) 형태를 지정할 수 있다.
예를 들어, 다음과 같은 데이터가 있다고 하자. 여기서 x축을 date로 하고, y축을 price로 한다고 가정하자.
const data = [
{
id: 1,
price: 10000,
createdAt: '20231103',
},
{
id: 2,
price: 12000,
createdAt: '20231104'
},
];
이 때 x축에 표시되는 문자는 20231103 과 20231104 이고, y축에 표시되는 문자는 10000, 12000 이다. 이를 커스텀하기 위해 tickFormatter
를 사용한다. 예를 들어 '00월 00일', '00,000원' 과 같은 형태로 커스텀 할 수 있다.
formatter 함수 정의
const formatXAxis = (xTick: string) => {
return `${xTick.substring(4, 6)}월 ${xTick.substring(6, 8)}일`;
};
const formatYAxis = (yTick: number) => {
return `${yTick.toLocaleString()}원`;
};
formatter 적용
<XAxis tickFormatter={formatXAxis} />
<YAxis tickFormatter={formatYAxis} />
<YAxis hide />
<YAxis hide={windowWidth.innerWidth.current < 767} />
hide를 사용할 경우 해당 축이 사라진다. 화면의 너비 등을 기준으로 하여 축을 보여줄 경우와 숨길 경우를 정할 수 있다.
라인 차트의 선을 커스텀 해보자. 전체 내용은 Docs에서 확인할 수 있다.
<Line dataKey='price' />
그래프의 y값이 될 데이터의 key를 지정한다.
<Line type='linear' />
라인 차트의 타입을 지정한다. 다음과 같이 다양한 타입이 있다.
'basis' | 'basisClosed' | 'basisOpen' | 'bumpX' | 'bumpY' | 'bump' | 'linear' | 'linearClosed' | 'natural' | 'monotoneX' | 'monotoneY' | 'monotone' | 'step' | 'stepBefore' | 'stepAfter'
<Line dataKey="value" dot={false} />
<Line dataKey="value" dot={{ stroke: 'red', strokeWidth: 2 }} />
<Line dataKey="value" dot={<CustomizedDot />} />
<Line dataKey="value" dot={renderDot} />
라인 차트의 점을 커스텀할 수 있다. dot의 타입은 boolean, 객체, 함수, ReactElement 이다.
activeDot은 마우스 커서와 가까운 점 (= active 상태인 점)을 커스텀 할 수 있다. dot과 동일하게 boolean, 객체, 함수, ReactElement 타입을 가진다.
예를 들어, 기본 점은 검은색이고, active 상태의 점은 빨간색으로 지정하고 싶다면 다음과 같이 구현할 수 있다.
<Line
dataKey="value"
dot={{ fill: 'black', stroke: 'black' }}
activeDot={{ fill: 'red', stroke: 'red' }}
/>
<Line stroke='black' />
라인 차트의 선 색상을 지정한다.
<Line strokeWidth={2} />
라인 차트의 선 굵기를 지정한다.
라인 차트에 보조선을 추가해보자. 전체 내용은 Recharts API - ReferenceLine에서 확인할 수 있다.
보조선의 값을 지정할 수 있다. 예를 들어, y=30, x='monday' 인 보조선을 추가하고 싶다면 다음과 같이 할 수 있다.
<ReferenceLine y={30} />
<ReferenceLine x='monday' />
단, 여기서 y축은 type='number'
x축은 type='category'
이다. 타입이 카테고리인 경우 반드시 카테고리 중 하나의 값을 지정해줘야 한다.
<ReferenceLine stroke='#eee' />
보조선의 색상을 지정할 수 있다.
<ReferenceLine label='Max' />
보조선에 이름을 표시할 수 있다.
<ReferenceLine strokeDasharray="3 3" />
보조선을 dash 형태로 나타낼 수 있다.
마우스 커서를 가까이 했을 때 생기는 네모 박스 Tooltip 을 커스텀 해보자.
name과 value 사이를 구분짓는 구분자 커스텀. 기본 값은 :
이다.
ex) 가격 - 10000
<Tooltip separator='-' />
Tooltip content 형태를 지정한다.
ex) 가격 - 10,000원
// fromatter 정의
const formatTooltip = (value: number) => {
return `${value.toLocaleString()}원`;
};
// formatter 적용
<Tooltip formatter={formatTooltip} />
Tooltip의 label (제목) 형태를 지정한다.
ex)
11월 03일 가격 정보
가격 - 10,000원
// formatter 정의
const formatTooltipLabel = (value: string) => {
return `${value.substring(4, 6)}월 ${value.substring(6, 8)}일 가격 정보`;
};
};
// formatter 적용
<Tooltip labelFormatter={formatTooltipLabel} />
<Tooltip wrapperStyle={{ padding: '8px', textAlign: 'left' }} />
Tooltip 컨테이너의 스타일을 지정한다.
<Tooltip contentStyle={{ fontWeight: 700, color: '#333' }} />
Tooltip content (내용) 의 폰트 사이즈, 폰트 굵기, 색상, 마진 등 스타일을 지정한다.
<Tooltip
labelStyle={{
fontSize: '12px',
marginBottom: '8px',
fontWeight: 700,
color: '#555',
}}
/>
Tooltip label (제목) 의 폰트 사이즈, 폰트 굵기, 색상, 마진 등 스타일을 지정한다.
<Tooltip cursor={{ stroke: '#eee', strkeWidth: 1 }} />
마우스를 가져갔을 때 생기는 세로줄 (커서) 의 스타일을 지정한다.
위 내용을 하나의 커스텀 컴포넌트로 만드는 방법이다. dataKey로 설정한 key가 아니어도 payload를 통해 접근할 수 있다.
예를 들어, <LineChart data={data} />
로 데이터를 지정했을 때, data의 형태가 다음과 같고, Line과 XAxis의 dataKey가 각각 price와 createdAt라 하자.
interface data {
price: number;
createdAt: string;
diff: number;
}[]
이 때 우리는 payload[0].payload
를 사용하여 각 데이터에 접근할 수 있다.
const CustomTooltip = ({ active, payload }) => {
// ...
const { price, createdAt, diff } = payload[0].payload;
// ...
}
커스텀 컴포넌트 만들기
다음과 같은 Tooltip을 만들어보자.
/** @jsxImportSource @emotion/react */
import { TooltipProps } from 'recharts';
import * as styles from './CustomTooltip.styles';
export type DiffType = 'increment' | 'decrement' | 'same';
const CustomTooltip: React.FC<TooltipProps<number, string>> = ({
active,
payload,
}) => {
if (active && payload && payload.length) {
// 각 데이터 정보 가져오기
const { price, createdAt, diff } = payload[0].payload;
// Tooltip 제목 설정
const title = `
${createdAt.substring(4, 6)}월
${createdAt.substring(6, 8)}일
가격 정보
`;
// Tooltip 내용 (가격) 설정
const priceText = `${price.toLocaleString()}원`;
// Tooltip 내용 (diff) 설정
let diffText = '';
let diffType: DiffType = 'same';
if (diff > 0) {
diffText = `▲ ${diff.toLocaleString()}원`;
diffType = 'increment';
} else if (diff < 0) {
diffText = `▼ ${(-diff).toLocaleString()}원`;
diffType = 'decrement';
} else {
diffText = '( -- )';
}
return (
<div css={styles.customTooltip}>
<h3 css={styles.tooltipTitle}>{title}</h3>
<div css={styles.tooltipContent}>
<div css={styles.price}>{priceText}</div>
<div css={styles.priceInfo(diffType)}>{diffText}</div>
</div>
</div>
);
} else {
return null;
}
};
export default CustomTooltip;
각 스타일은 emotion으로 지정해주었다. 또한 diffType에 따라 동적으로 스타일링을 구성하였다.
커스텀 컴포넌트 적용하기
<Tooltip content={<CustomTooltip />} />