D3로 pie chart 그리기

시작하기

d3 bar차트 포스트에서 다루었던 데이터를 토대로 pie차트를 만들어보겠습니다.

기본설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.js"></script>
</head>
<body>
<script>
const svgDimensions = {
width: 300,
height: 300,
};
const radius = Math.min(svgDimensions.width, svgDimensions.height) / 2;
const data = [420, 80, 130, 210, 510, 80];

const svg = d3
.select("body")
.append("svg")
.attr("width", svgDimensions.width)
.attr("height", svgDimensions.height)
.style("border", "1px solid rgba(0,0,0,0.1)");

const g = svg
.append("g")
.attr(
"transform",
`translate(${svgDimensions.width / 2}, ${svgDimensions.height / 2})`
);
const color = d3.scaleOrdinal([
"#ff9800",
"#ffa726",
"#ffb74d",
"#ffcc80",
"#ffe0b2",
"#fff3e0",
]);
</script>
</body>
</html>
  • color: 데이터 배열의 값 인덱스를 색상 스케일에 전달하면 해당 색상 값이 반환됩니다.
  • g: 생성 된 파이가 SVG의 경계에 맞도록 Math.min (width, height) / 2로 반경을 계산합니다

pie차트를 그릴 기본적인 색상 및 사이즈 규격을 정해주도록 합니다.

pie그리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.js"></script>
</head>
<body>
<script>
const svgDimensions = {
width: 300,
height: 300,
};
const radius = Math.min(svgDimensions.width, svgDimensions.height) / 2;
const data = [420, 80, 130, 210, 510, 80];

const svg = d3
.select("body")
.append("svg")
.attr("width", svgDimensions.width)
.attr("height", svgDimensions.height)
.style("border", "1px solid rgba(0,0,0,0.1)");

const g = svg
.append("g")
.attr(
"transform",
`translate(${svgDimensions.width / 2}, ${svgDimensions.height / 2})`
);
const color = d3.scaleOrdinal([
"#ff9800",
"#ffa726",
"#ffb74d",
"#ffcc80",
"#ffe0b2",
"#fff3e0",
]);

const pie = d3.pie();
const arc = d3.arc().innerRadius(0).outerRadius(radius);
const arcs = g
.selectAll("arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
arcs
.append("path")
.attr("fill", (d, i) => color(i))
.attr("d", arc);
</script>
</body>
</html>
  • pie: pie를 그린다고 선언을 합니다.

  • arc: innerRadiusouterRadius로 내부 반지름이 0이고 외부 반지름이 미리 계산된 반지름으로 호를 정의합니다.

  • arcs: 이제 각 데이터 값에 대한 그룹 요소를 만듭니다.

  • path: 앞서 생성 된 호를 제공하고 색상 스케일의 색상으로 채 웁니다.

    파이형
    고리형

추가 - hover했을때 transition과 text

텍스트 값을 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
//...
arcs
.append("text")
.attr("transform", (d) => `translate(${arc.centroid(d)})`)
.text((d) => d.value)
.attr("font-family", "sans-serif")
.attr("font-size", "18px")
.attr("font-weight", "bold")
.attr("fill", "#fff")
.attr("text-anchor", "middle")
.attr("display", "none");
//...

마우스 이벤트를 추가합니다.
마우스 hover되었을때와 나왔을때의 기능을 구현합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//...
const arcs = g
.selectAll("arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.on("mouseover", onMouseOver) // 이벤트 추가
.on("mouseout", onMouseOut); // 이벤트 추가

function onMouseOut(d, i) {
d3.select(this)
.select("path")
.transition()
.duration(200)
.style("fill", color(i));
d3.select(this).select("text").attr("display", "none");
}

function onMouseOver(d, i) {
d3.select(this)
.select("path")
.transition()
.duration(200)
.style("fill", "#e65100");
d3.select(this).select("text").attr("display", "block");
}

결과물

최종코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<html>
<meta charset="utf-8" />
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.js"></script>
</head>
<body>
<script>
const svgDimensions = {
width: 300,
height: 300,
};
const radius = Math.min(svgDimensions.width, svgDimensions.height) / 2;
const data = [420, 80, 130, 210, 510, 80];

const svg = d3
.select("body")
.append("svg")
.attr("width", svgDimensions.width)
.attr("height", svgDimensions.height)
.style("border", "1px solid rgba(0,0,0,0.1)");

const g = svg
.append("g")
.attr(
"transform",
`translate(${svgDimensions.width / 2}, ${svgDimensions.height / 2})`
);
const color = d3.scaleOrdinal([
"#ff9800",
"#ffa726",
"#ffb74d",
"#ffcc80",
"#ffe0b2",
"#fff3e0",
]);

const pie = d3.pie();
const arc = d3.arc().innerRadius(0).outerRadius(radius);
const arcs = g
.selectAll("arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc")
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut);

arcs
.append("path")
.attr("fill", (d, i) => color(i))
.attr("d", arc);

arcs
.append("text")
.attr("transform", (d) => `translate(${arc.centroid(d)})`)
.text((d) => d.value)
.attr("font-family", "sans-serif")
.attr("font-size", "18px")
.attr("font-weight", "bold")
.attr("fill", "#fff")
.attr("text-anchor", "middle")
.attr("display", "none");

function onMouseOut(d, i) {
d3.select(this)
.select("path")
.transition()
.duration(200)
.style("fill", color(i));
d3.select(this).select("text").attr("display", "none");
}

function onMouseOver(d, i) {
d3.select(this)
.select("path")
.transition()
.duration(200)
.style("fill", "#e65100");
d3.select(this).select("text").attr("display", "block");
}
</script>
</body>
</html>
Share