何大小成

D3 · 一个饼状图

See the Pen OvbwYR by 何大小成 (@hopkinson) on CodePen.

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title></title>
<style media="screen">
text {
text-anchor: middle;
}

line {
stroke: black;
}

.tooltip {
position: absolute;
border: 1px solid;
border-radius: 3px;
border:1px solid white;
padding: 3px;
}
</style>
</head>

<body>
<script src="https://cdn.bootcss.com/d3/4.13.0/d3.min.js"></script>
<script>
const data = [{
"number": 14,
"name": "Locke"
},
{
"number": 18,
"name": "Reyes"
},
{
"number": 15,
"name": "Ford"
},
{
"number": 16,
"name": "Jarrah"
},
{
"number": 23,
"name": "Shephard"
},
{
"number": 42,
"name": "Kwon"
}
];
const width = 500
const height = 900
// 颜色
const color = d3.scaleOrdinal(d3.schemeCategory10)
// toiltip
let tooltip = d3.select('body').append('div').attr('class', 'tooltip').style('opacity', 0)
let pie = d3.pie()
.sort(null)
.value(d => d.number)
const svg = d3.select('body').append('svg').attr('width', width).attr('height', height)
// 内外半径
const innerRadius = 0
const outerRadius = width / 3
// 创建弧
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius)
// 添加数目对应的弧组
let arcs = svg.selectAll('g')
.data(pie(data))
.enter()
.append('g')
.attr('transform', `translate(${width/2},${height/2})`)
// 添加路径
arcs.append('path')
.attr('fill', (d, i) => color(i))
.attr('d', arc)
// 添加文字
arcs.append('text')
.attr('transform', d => {
let x = arc.centroid(d)[0] * 1.2
let y = arc.centroid(d)[1] * 1.2
return `translate(${x}, ${y})`
})
.text(d => {
let percent = Number(d.data.number) / d3.sum(data, d => d.number) * 100
return percent.toFixed(1) + '%'
})
// 添加弧外直线
arcs.append('line')
.attr('x1', d => arc.centroid(d)[0] * 2)
.attr('y1', d => arc.centroid(d)[1] * 2)
.attr('x2', d => arc.centroid(d)[0] * 2.2)
.attr('y2', d => arc.centroid(d)[1] * 2.2)
// 添加户外直线的文字
arcs.append('text')
.attr('transform', d => {
let x = arc.centroid(d)[0] * 2.5
let y = arc.centroid(d)[1] * 2.5
return `translate(${x}, ${y})`
})
.text(d => d.data.name)
// 事件监听器
arcs.on('mouseover', (d,i) => {
tooltip.html(`${d.data.name}的出货量为${d.data.number}`)
.style('opacity', 1)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.style('background-color', color(i))
}).
on('mousemove', d => {
tooltip.style('left', `${d3.event.pageX}px`)
.style('top', `${ d3.event.pageY + 20}px`)
}).
on('mouseout', d => {
tooltip.style('opacity', 0)
})
</script>
</body>
</html>