SVG를 이용한 라인 그래프 만들기
계산 방식
- 데이터들 중 최솟값과 최댓값을 찾는다.
- 최댓값 - 최솟값을 하여 변화량(delta)을 구한다.
- y값을 계산하기 위해 데이터값에 최솟값을 빼주고 (svg 높이 / delta) 값을 곱해준다.
- ex) max=10, min=-10, svgHeight=100, data=0일 경우
- y = (0 - (-10)) * (100 / 20) = 50
- x값은 index * 컬럼 너비 + 컬럼 너비 / 2로 설정하여 각 컬럼의 중간에 기준점을 표시하도록 하였다.
- 데이터가 최솟값이거나 최댓값일 경우 svg로 표시할 경우 잘리는 경우가 발생할 수 있어 y에 offset을 더해주었다.
- y: (value - minValue) * (svgHeight / delta) + offset
코드
export default function LineGraph(props) {
const offset = 10;
let {
data: { columns },
axisMax,
axisMin,
height,
graphColor,
columnWidth
} = props;
let arr = columns.reduce((prev, next) => prev.concat(next)); // 2차원 목록 columns를 1차원으로 변환
let maxValue = axisMax ? Math.max(axisMax, ...arr) : Math.max(...arr); // axisMax와 데이터들 중 가장 큰 값을 찾음
let minValue = axisMin ? Math.min(axisMin, ...arr) : Math.min(...arr); // axisMin과 데이터들 중 가장 작은 값을 찾음
let maxLength = columns.reduce(
(prev, next) => (prev > next.length ? prev : next.length),
-1
); // columns의 데이터들 중 가장 긴 길이를 찾음
let svgWidth = columnWidth * maxLength; // 컬럼의 기본 길이에 maxLength를 곱하여 svg의 너비를 계산
let svgHeight = height ? height : 100;
let delta = maxValue - minValue;
// x값, y값 계산
let polylines = columns.map((column) =>
column.map((value, index) => {
const point = {
x: index * columnWidth + columnWidth / 2,
y: (value - minValue) * (svgHeight / delta) + offset
};
return point;
})
);
return (
<div className="line_graph_area">
<svg
width={svgWidth}
height={svgHeight + offset * 2}
viewBox={`0 0 ${svgWidth} ${svgHeight + offset * 2}`}
style={{ transform: "scaleY(-1)" }}
>
{polylines.map((polyline, index) => {
const points = polyline.reduce((acc, point) => {
acc += `${point.x}, ${point.y} `;
return acc;
}, "");
return (
<polyline
stroke={graphColor[index]}
strokeWidth="2"
fill="none"
points={points}
/>
);
})}
{polylines.map((polyline, index) =>
polyline.map((dot, dotIndex) => (
<circle
key={dotIndex}
r="2.5"
cx={dot.x}
cy={dot.y}
stroke={graphColor[index]}
stroke-width="2"
fill={"#fff"}
></circle>
))
)}
</svg>
</div>
);
}
사용 예
import LineGraph from "./LineGraph";
import "./styles.css";
export default function App() {
return (
<>
<LineGraph
data={{
columns: [
[5, 8, 8, 5, 8, 8],
[2, 8, 8, 9, 9, 9, 9],
[8.5, 8.5, 8.5],
[1, 1, 1],
[3, 2, 1],
[1, 1, 3]
]
}}
graphColor={[
"#74bfff",
"#ff7d7d",
"#badc58",
"#e056fd",
"#fab1a0",
"#ffeaa7"
]}
height={250}
columnWidth={100}
/>
<LineGraph
data={{
columns: [[5, 8, 8, 5, 8, 8]]
}}
graphColor={[
"#74bfff",
"#ff7d7d",
"#badc58",
"#e056fd",
"#fab1a0",
"#ffeaa7"
]}
height={250}
columnWidth={100}
/>
</>
);
}
결과 화면

'개발 > React' 카테고리의 다른 글
| [정리] Thinking in React (0) | 2019.08.20 |
|---|