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

D3 矩阵布局


矩阵布局(Treemap)是一个层级布局或分层布局扩展,最早由Ben Shneiderman1991进行提出,可以通过对一块举行进行切分,并达到层级演示的效果。会通过使用将一块类似于近正矩形并进行切块,之后将数据根据矩形树图算法进行计算。

ID DA FA
d3.layout.treemap() 创建矩阵数布局
treemap.nodes(root) 根据root进行计算,并获取节点数据
treemap.links(nodes) 根据 nodes 进行计算,获取连线数组
treemap.children([children]) 设置或获取子节点访问器(默认情况下子节点对象是children
treemap.sort([comparator]) 设置或获取布局的节点排序数据
treemap.value([value]) 设置或获取值访问器
treemap.size([size]) 设置或获取布局尺寸,(有两个参数分别为 表示以及
treemap.padding([padding]) 设置或获取矩阵单元之间的间隔(单位为像素)
treemap.round([round]) 设置或获取是否对计算结果是否进行四舍五路
treemap.sticky([sticky]) 设置或获取矩阵树图是否有粘性,粘性属性布局将保留整个过度中节点的相对排序
treemap.ratio([ratio]) 设置或获取矩阵树图是否有粘性
treemap.mode([mode]) 设置矩阵布局模式,不同算法之间的有很大的差异

确定数据

下述我们通过计算出广州省、吉林省、河南省的人口迁移数据,通过新建json文件来进行写入:

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
{
"name": "中国",
"children":
[
{
"name": "广州省",
"children": [
{"name": "佛山市", "ratio": 25.82},
{"name": "东莞市", "ratio": 10.26},
{"name": "深圳市", "ratio": 8.53},
{"name": "清远市", "ratio": 5.22},
{"name": "中山市", "ratio": 3.56},
{"name": "惠州市", "ratio": 3.49},
{"name": "肇庆市", "ratio": 2.85},
{"name": "江门市", "ratio": 2.52},
{"name": "珠海市", "ratio": 1.92},
{"name": "湛江市", "ratio": 1.62}
]
},
{
"name": "吉林省",
"children":[
{"name": "辽阳市", "ratio": 11.82},
{"name": "哈尔滨市", "ratio": 10.55},
{"name": "北京市", "ratio": 6.56},
{"name": "铁岭市", "ratio": 5.77},
{"name": "通辽市", "ratio": 5.14},
{"name": "兴安盟", "ratio": 4.46},
{"name": "大连市", "ratio": 3.34},
{"name": "大庆市", "ratio": 2.86},
{"name": "天津市", "ratio": 2.27},
{"name": "齐齐哈尔市", "ratio": 1.88}
]
},
{
"name": "河南省",
"children": [
{"name": "辽阳市","ratio": 11.82},
{"name": "哈尔滨市","ratio": 10.55},
{"name": "北京市", "ratio": 6.56},
{"name": "铁岭市","ratio": 5.77},
{"name": "通辽市","ratio": 5.14},
{"name": "兴安盟","ratio": 4.46},
{"name": "大连市","ratio": 3.34},
{"name": "大庆市","ratio": 2.86},
{"name": "天津市","ratio": 2.27},
{"name": "齐齐哈尔市","ratio": 1.88}
]
}
]
}

布局运算


上述的 json 数据是无法直接被 d3.js所识别的,所以需要通过使用布局,将得到node以及links的连线关系并进行转换,上图我们以河南省数据为例,转换如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
转换数据 -> nodes(节点) -> links (连线关系)
*/
var treemap = d3.layout.treemap()
.size([padding.width,padding.height])
.value(function (d) {
return d.ratio
})


d3.json("treemap.json",function (error, root) {
var nodes = treemap.nodes(root)
var links = treemap.links(nodes)

console.log(nodes)
console.log(links)
})

绘制矩阵

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
var padding = {
width: 1000,
height: 800
}

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

/*
转换数据 -> nodes(节点) -> links (连线关系)
*/
var treemap = d3.layout.treemap()
.size([padding.width,padding.height])
.value(function (d) {
return d.ratio
})


d3.json("treemap.json",function (error, root) {
var nodes = treemap.nodes(root)
var links = treemap.links(nodes)

console.log(nodes)
console.log(links)

/* 选择颜色 */
var color = d3.scale.category20c()

/* <g> 组 */
var groups = svg.selectAll("g")
.data(nodes.filter(function (d) {
return !d.children
}))
.enter()
.append("g")

/* 矩形 */
var rects = groups.append("rect")
.attr("class","nodeRect")
.attr("x", function (d) {
return d.x
})
.attr("y", function (d) {
return d.y
})
.attr("width", function (d) {
return d.dx
})
.attr("height", function (d) {
return d.dy
})
.style("fill", function (d,i) {
return color(d.parent.name)
})

/* 文字 */
var text = groups.append("text")
.attr("class","nodeName")
.attr("x", function (d) {
return d.x
})
.attr("y", function (d) {
return d.y
})
.attr("dx", "0.5em")
.attr("dy", "1.5em")
.text(function (d) {
return d.name + "" + d.ratio
})
})

CSS

1
2
3
4
5
6
7
8
.nodeRect {
stroke: white;
}
.nodeName {
fill: white;
font-size: 12px;
font-weight: bold;
}
⬅️ Go back