梦入琼楼寒有月,行过石树冻无烟

D3 柱形图

通常的情况下我们并不常见关于D3的柱形图,而是最为引人注目的”地图“以及”飞线“,在D3中,生成一个柱形图也非常的简单,而且在与之搭配坐标轴可显得非常的专业,又可体现出一种朴实无华的效果。

矩形与布局


在上图中,我们主要通过使用padding来进行定义画布边界之间的距离,其中left、bottom、top、right都为20,而最里面的矩形我们通过使用rectStep来设置其间距,rectWidth设置矩形的宽度等。

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
// 数据源
var databases = [20, 21, 34, 53, 60, 90, 110, 230, 340, 550];

/*
1. 选择 body 元素
2. 在 <body> 中添加 <svg> 元素
3. 通过 attr 来设置高度
|—— width @1400
|—— heigh t@700
*/
var width = 1400;
var height = 700;


var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)

/*
|—— 外边框设置 @padding
|————| top @20
|————| right @20
|————| bottom @20
|————| left @20
|—— 空白矩形占比宽度 @rectStep
|—— 实体站比宽度 @rectWidth
*/
var padding = {
top: 20,
right: 20,
bottom: 20,
left: 20
};
var rectStep = 60;
var rectWidth = 35;

矩形起始坐标


矩形位置的坐标确认可以通过使用padding.left +i * rectStep来计算出每个矩形的x坐标,之后使用height - padding.bottom - d 来求出每个矩形的y坐标,最后的出结果为 20,660,即矩形在画布中显示的位置。

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
/*
|—— 选择一个空集
|—— 使用 enter 补足元素
|—— 添加 rect 元素与数组绑定一致
|——————| 设置 颜色为 steelblue
|——————| 设置举行的 x 坐标中的空白矩形站比 为rectStep@35
|——————| 设置矩形的 y 坐标
|——————| 设置矩形的宽度
|——————| 设置矩形的高度

|—— 数组 databases 长度为 10,则对应十个数据
|————| 分别设置其颜色为 蓝色
|————| 其中 d,i 分别对应数据(datum,d)以及 索引号(index,i)
|——————| 数组: 20,21,34,53,60,90,110,230,340,550
|——————| 索引: 00,01,02,03,04,05,006,007,008,009

/- 以地一个数据 为例:
/————| height - padding.bottom - d;
/-—————| 20 - 0 × 60 = 20 (x)
/——————| 700 - 20 - 20 = 660 (y)
*/
var rect = svg.selectAll("rect")
.data(databases)
.enter()
.append("rect")
.attr("fill", "blue")
.attr("x", function (d, i) {
return padding.left + i * rectStep;
})
.attr("y", function (d) {
return height - padding.bottom - d;
})
.attr('width', rectWidth)
.attr("height", function (d) {
return d;
})

文字标注


在上图中的文字位置,首先通过获取柱形图的坐标后通过使用dx以及dy进行计算,计算之后的结果则为其最终的坐标,如dx计算的则是文字标注的x轴坐标,而dy则是直接来设置文字标注的y轴坐标。

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
/*
|—— 选择所有 text 元素
|————| 绑定 databases 数据
|————| 通过 enter 来补足足够数量的 <text> 元素
|————| 添加 text 元素并与其绑定数组长度一致
*/
var text = svg.selectAll("text")
.data(databases)
.enter()
.append("text")
.attr("fill", "grey")
.attr("font-size", "10px")
.attr("text-anchor", "middle")
.attr("x", function (d, i) {
return padding.left + i * rectStep;
})
.attr("y", function (d) {
return height - padding.bottom - d;
})

/*
|—— dx and dy
|————| x 轴平移时的大小
|————| y y轴平移时的大小
*/
.attr("dx", rectWidth / 2)
.attr("dy", "-1em")
.text(function (d) {
return d;
})

数据更新


下述 code 分别处理了矩形以及文字的Update、Enter、exit,当数据进行Update、enter、exit操作时,分别会重新进行计算矩形以及文字的坐标信息。

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
<script>
/*
|—— 数据集
|———— 20,10,34,53,60,90,110,230,340,550
|———— 00,01,02,03,04,05,006,007,008,009
*/
var databases = [20, 10, 34, 53, 60, 90, 110, 230, 340, 550];
/*
|—— 设置画布高度与宽度
|—— 设置矩形宽度与间隔
*/
var width = 1400;
var height = 700;


var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)

var padding = {
top: 20,
right: 20,
bottom: 20,
left: 20
};
var rectStep = 60;
var rectWidth = 35;

function draw() {
// 矩形的 update 处理方法
var updateRect = svg.selectAll("rect")
.data(databases)
var enterRect = updateRect.enter()
var exitRect = updateRect.exit()

updateRect.attr("fill","blue")
.attr("x",function(d,i) {
return padding.left + i * rectStep;
})
.attr("y",function(d) {
return height - padding.bottom - d;
})
.attr("width",rectWidth)
.attr("height",function(d) {
return d;
})

// 矩形的 enter 处理方法
enterRect.append("rect")
.attr("fill","blue")
.attr("x", function(d,i) {
return padding.left + i * rectStep;
})
.attr("y",function(d) {
return height - padding.bottom - d;
})
.attr("width",rectWidth)
.attr("height",function(d) {
return d;
})

// 矩形的 exit 处理方法
exitRect.remove()

// 文字的 Update 处理方法
var updateText = svg.selectAll("text")
.data(databases)
var enterText = updateText.enter()
var exitText = updateText.exit()

updateText.attr("fill","blue")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x", function(d,i) {
return padding.left + i * rectStep;
})
.attr("y", function(d) {
return height - padding-bottom - d
})
.attr("dx",rectWidth/2)
.attr("dx","-1em")
.text(function(d) {
return d;
})

// 文字的 enter 处理方法
enterText.append("text")
.attr("fill","blue")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x", function(d,i) {
return padding.left + i * rectStep;
})
.attr("y",function(d) {
return height - padding.bottom -d;
})
.attr("dx",rectWidth/2)
.attr("dy","-1em")
.text(function(d) {
return d
})

// 文字的 exit 处理方法
exitText.remove()
}

draw();
function mysort() {
databases.sort(d3.ascending);
draw()
}
</script>
<button type="submit" onclick="mysort()">Go</button>
⬅️ Go back