React에서 차트 그리기 위해 Victory 라이브러리를 사용했습니다.
npm i victory
# or
yarn add victory
공식문서에 있는 퍼센트 막대 차트 예제입니다.
const myDataset = [
[
{ x: 'a', y: 1 },
{ x: 'b', y: 2 },
{ x: 'c', y: 3 },
{ x: 'd', y: 2 },
{ x: 'e', y: 1 },
],
[
{ x: 'a', y: 2 },
{ x: 'b', y: 3 },
{ x: 'c', y: 4 },
{ x: 'd', y: 5 },
{ x: 'e', y: 5 },
],
[
{ x: 'a', y: 1 },
{ x: 'b', y: 2 },
{ x: 'c', y: 3 },
{ x: 'd', y: 4 },
{ x: 'e', y: 4 },
],
]
const transformData = (dataset) => {
const totals = dataset[0].map((data, i) => {
return dataset.reduce((memo, curr) => {
return memo + curr[i].y
}, 0)
})
return dataset.map((data) => {
return data.map((datum, i) => {
return { x: datum.x, y: (datum.y / totals[i]) * 100 }
})
})
}
function Chart(){
const dataset = transformData(myDataset)
return (
<div>
<VictoryChart height={400} width={400} domainPadding={{ x: 30, y: 20 }}>
<VictoryStack colorScale={['black', 'blue', 'tomato']}>
{dataset.map((data, i) => {
return <VictoryBar data={data} key={i} />
})}
</VictoryStack>
<VictoryAxis dependentAxis tickFormat={(tick) => `${tick}%`} />
<VictoryAxis tickFormat={['a', 'b', 'c', 'd', 'e']} />
</VictoryChart>
</div>
)
}
먼저, 차트에 데이터를 x축, y축 데이터 형태로 전달해야 합니다. 그리고 퍼센트 막대 차트라서 퍼센트 데이터로 되어 있어야 합니다. transformData()가 퍼센트 막대 차트에 맞는 데이터로 가공해서 반환합니다.
여기서 사용하는 Victory 컴포넌트에 간단히 소개하겠습니다.

위 차트는 결과물입니다.
프로젝트 코드는 여기서 확인할 수 있습니다. 아래는 그 결과물입니다.

공식문서에서 여러 옵션들 예제를 참고해 구현했습니다. 차트 범례는 VictoryLegend를 사용하지 않고 div태그로 따로 만들어서 사용했습니다. VictoryLegend로 구현했을 때 제가 원하는 위치로 이동이 자유롭지 않아서 직접 구현했습니다. 여기서 제일 고민했던 것은 어떻게 가독성 있게 원본 데이터를 차트에 맞는 데이터로 가공할 수 있을까였습니다. 함수형 프로그래밍을 사용했습니다. lodash에서 chain을 이용해 선언적으로 함수들을 사용했습니다. 그 결과는 프로젝트 코드를 제공하는 링크에서 transformData()를 보시면 됩니다.