Explanation
오늘은 원 그래프 예제 코드를 보면서 D3.js와 API들을 알아보려 합니다.
설명 부분이 저번 글과 겹치는 부분은 생략하려 합니다, 이해가 안되시는 분은 이전 글을 먼저 살짝 보시고 오는게 좋을거 같아요.
[이전글]
D3.js 를 사용하여 데이터 시각화하기 #1 Line Charts
D3.js 를 사용하여 데이터 시각화하기 #2 Bar Charts
아직 초보이기 때문에 글에는 수많은 추측과 오류를 담고 있습니다.
1. 코드
예제 코드 출처
https://beta.observablehq.com/@mbostock/d3-pie-chart
아래의 코드는 위 예제 코드를 아주 조금 수정한 내용입니다.
이번 글도 역시 바로 코드에 주석으로 이야기를 적도록 하겠습니다.
<!doctype html>
<html lang="ko">
<head>
<title>D3 bar chart example</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script src="pie-chart.js"></script>
</body>
</html>
// pie-chart.js
const width = 500;
const height = 500;
const data = [
{name: 'A', value: 1000, color: '#efa86b'},
{name: 'B', value: 1500, color: '#c1484f'},
{name: 'C', value: 1300, color: '#d35d50'},
{name: 'D', value: 900, color: '#f4c17c'},
{name: 'E', value: 400, color: '#fae8a4'},
{name: 'F', value: 1200, color: '#df7454'},
{name: 'G', value: 1100, color: '#e88d5d'},
{name: 'H', value: 600, color: '#f8d690'}
];
const arc = d3.arc().innerRadius(150).outerRadius(Math.min(width, height) / 2);
// .arc() 새로운 기본값의 아치(호) 생성
// .innerRadius() 안쪽 반지름 값, 0이면 완전한 원이되고 값이 있으면 도넛 형태가 됩니다.
// .outerRadius() 바깥쪽 반지름값
const arcLabel = (() => {
const radius = Math.min(width, height) / 2 * 0.8;
return d3.arc().innerRadius(radius).outerRadius(radius);
})();
// 라벨이 위치할 반지름 값을 설정합니다.
const pie = d3.pie()
// 새로운 기본값의 파이 모양의 생성
.sort((a, b) => b.value - a.value)
// data의 value 큰값 > 작은값 순으로 정렬합니다. ex. 반대 순서는 a.value - b.value
.value(d => d.value);
const arcs = pie(data);
const svg = d3.select('body').append('svg').style('width', width).style('height', height)
.attr('text-anchor', 'middle')
// text-anchor 텍스트의 정렬을 설정합니다 ( start | middle | end | inherit )
.style('font-size', '12px sans-serif');
const g = svg.append('g')
.attr('transform', `translate(${width/2}, ${height/2})`);
// 우선 차트를 그릴 그룹 엘리먼트를 추가합니다.
// 위치값을 각각 2로 나누는건 반지름 값을 기준으로 한바퀴 돌며 path를 그리기 때문인거 같습니다.
g.selectAll('path')
.data(arcs)
.enter().append('path')
// 이전과 동일하게 가상 path 요소를 만들고 그래프 데이터와 매핑하여 엘리먼트를 추가합니다.
.attr('fill', d => d.data.color)
// 다른 그래프와 다르게 .data 라는 객체가 추가되어 있는데, 위에 arcs 변수를 선언할때
// .pie(data)가 {data, value, index, startAngle, endAngle, padAngle} 의 값을 가지고 있습니다.
.attr('stroke', 'white')
.attr('d', arc)
.append('title')
.text(d => `${d.data.name}: ${d.data.value}`);
// 각각 페스의 자식으로 title의 엘리먼트에 텍스트로 출력합니다.
// 실제로 뷰에 출력되지는 않지만 시멘틱하게 각각의 요소의 설명 문자열을 제공합니다.
const text = g.selectAll('text')
.data(arcs)
.enter().append('text')
.attr('transform', d => `translate(${arcLabel.centroid(d)})`)
.attr('dy', '0.35em');
// 라벨을 취가하기 위한 text 엘리먼트를 만들고 위치를 지정합니다.
text.append('tspan')
.attr('x', 0)
.attr('y', '-0.7em')
.style('font-weight', 'bold')
.text(d => d.data.name)
// 해당 데이터 항목의 이름을 두꺼운 글씨로 출력합니다. ex. A
text.filter(d => (d.endAngle - d.startAngle > 0.25)).append('tspan')
.attr('x', 0)
.attr('y', '0.7em')
.attr('fill-opacity', 0.7)
.text(d => d.data.value);
// 해당 데이터의 수치값을 투명도를 주어 출력합니다. ex. 1000
svg.node();
2. 마치며
이렇게 그래프 3대장의 예제를 모두 살펴보았습니다! 아직 이해하지 못한 부분도 많지만 마치 이젠 뭐든 만들 수 있을 것만 같은 자신감이 생긴 듯 합니다!



