Skip to main content

D3를 안쓰고 Stack Bar Chart를 그려보자!

HighCharts, D3, Apache ECharts 등등 차트 라이브러리를 많은데 이런게 어려웠다.

  • 커스터마이징
  • 애니메이션으로 인한 브라우저 속도 저하 및 브라우저가 죽는 현상

그래서 방법을 찾고 있던 중, 직접 차트를 만들어보자 라는 생각이 들었다.

왜냐하면 D3를 사용하던, Apache Echarts를 사용하던, svg를 사용하기 때문이다.


SVG 태그로 직접 Stack Bar Chart를 만들어보자

import React, { MouseEvent, useState } from "react";

const data = [
[10, 20],
[30, 40],
[20, 10],
[40, 30],
[30, 20],
[20, 10],
[10, 20],
[30, 40],
[20, 10],
[40, 30],
];

interface StackBarChartProps<T> {
data: T;
}

const StackBarChart = <T extends number[][]>({
data,
}: StackBarChartProps<T>) => {
const height = 500;
const width = 500;
const barWidth = width / data.length;

const [tooltip, setTooltip] = useState<{
opacity: number;
top?: number;
left?: number;
data?: number;
}>({ opacity: 0 });

const handleMouseOver = (d: number, i: number, e: MouseEvent) => {
setTooltip({
opacity: 1,
top: e.clientY - 10,
left: e.clientX + 10,
data: d,
});
};

const handleMouseOut = () => {
setTooltip({ opacity: 0 });
};

return (
<div>
<svg width={width} height={height}>
{data.map((d, i) => (
<g key={i} transform={`translate(${i * barWidth}, 0)`}>
<rect
y={height - d[0]}
width={barWidth - 1}
height={d[0]}
fill="steelblue"
onMouseOver={(e) => handleMouseOver(d[0], i, e)}
onMouseOut={handleMouseOut}
/>
<rect
y={height - d[0] - d[1]}
width={barWidth - 1}
height={d[1]}
fill="orange"
onMouseOver={(e) => handleMouseOver(d[1], i, e)}
onMouseOut={handleMouseOut}
/>
</g>
))}
</svg>
<div
style={{
position: "fixed",
opacity: tooltip.opacity,
top: tooltip.top,
left: tooltip.left,
backgroundColor: "white",
border: "1px solid black",
padding: "5px",
}}
>
{tooltip.data && `Value: ${tooltip.data}`}
</div>
</div>
);
};

const HomePage = () => {
return (
<div>
<StackBarChart data={data} />
</div>
);
};

export default HomePage;

이렇게 짜면 다음과 같이 hover를 통한 tooltip도 구현할 수 있다

이렇게 직접 만들게 되면, 커스터마이징도 용이하고, 애니메이션의 종류 및 그 정도를 손수 커스터마이징할 수 있어서 좋았다.

1