径向树也就是环状的树
1. 效果
2. 技术分解
2.1 定义树布局
指定布局大小和节点邻距
【司机提示】 树布局就是一个函数,用来对原始的层次状数据进行加工处理,而这个加工主要就是生成节点的坐标深度等数据。由这些数据结合对角线,圆等就可以绘制径向树了。
var tree = d3.layout.tree()
.size([360, 360])// 角度360度,半径360px
.separation(function(a, b) {
return (a.parent == b.parent ? 1 : 2) / a.depth; });// 父节点相同的节点邻距相等,不同的稍宽一点用来区分开
});
2.2 定义径向对角线生成器
【司机提示】 径向对角线生成器也是一个函数,主要用来生成用以绘制连线数据。
var diagonal = d3.svg.diagonal.radial()
.projection(function(d) {
return [d.y, d.x / 180 * Math.PI];// 半径d.y和角度d.x / 180 * Math.PI(转换成弧度制)
});
2.3 加载json数据
d3.json("tree.json", function(error, root) {
var nodes = tree.nodes(root),//返回值是一个数组,它代表所有节点计算的位置。每个节点上填充一些属性:
links = tree.links(nodes);//返回节点数组的连接数组
//...
});
2.4 为连线添加路径数据
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
2.5 节点转换位置
transform是变换,本例中用于平移
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
2.6 节点添加圆圈
node.append("circle")
.attr("r", 4.5);
2.7 节点添加文字
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })//小于180度的文字放在前面,否则放在后面
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
3. JSON文件
很简单就是{}表示对象。[]表示数组。可以无限嵌套,可以无限重复
{
"name": "AAA",
"children":
[
{ "name": "BBB",
"children":
[
{"name": "CCC",
"children":
[
{"name": "DDD",
"children":
[
{"name": "EEE", "size": 73},
{"name": "EEE", "size": 39},
{"name": "EEE", "size": 67},
{"name": "EEE", "size": 73},
{"name": "EEE", "size": 39},
{"name": "EEE", "size": 67},
{"name": "EEE", "size": 73},
{"name": "EEE", "size": 39},
{"name": "EEE", "size": 67},
{"name": "EEE", "size": 73},
{"name": "EEE", "size": 39},
{"name": "EEE", "size": 67},
{"name": "EEE", "size": 73},
{"name": "EEE", "size": 39},
{"name": "EEE", "size": 67},
{"name": "EEE", "size": 73}
]},
{"name": "DDD", "size": 73},
{"name": "DDD", "size": 39},
{"name": "DDD", "size": 67},
{"name": "DDD", "size": 73},
{"name": "DDD", "size": 39},
{"name": "DDD", "size": 67},
{"name": "DDD", "size": 73},
{"name": "DDD", "size": 39},
{"name": "DDD", "size": 67},
{"name": "DDD", "size": 73},
{"name": "DDD", "size": 39},
{"name": "DDD", "size": 67},
{"name": "DDD", "size": 73},
{"name": "DDD", "size": 39},
{"name": "DDD", "size": 67},
{"name": "DDD", "size": 73}
]},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73},
{"name": "CCC", "size": 39},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73},
{"name": "CCC", "size": 39},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73},
{"name": "CCC", "size": 39},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73},
{"name": "CCC", "size": 39},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73},
{"name": "CCC", "size": 39},
{"name": "CCC", "size": 67},
{"name": "CCC", "size": 73}
]
},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73},
{"name": "BBB", "size": 39},
{"name": "BBB", "size": 67},
{"name": "BBB", "size": 73}
]
}
4. 完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>testD3-24-Reingold–Tilford Tree.html</title>
<script type="text/javascript" src="d3.js"></script>
<style>
.node circle {
fill:yellow ;
stroke: red;
stroke-width: 1.5px;
}
.node {
font: 10px sans-serif ;
}
.link {
fill: green;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script type="text/javascript">
var diameter = 960;//直径
//(1)树指定径向布局大小和节点邻距
var tree = d3.layout.tree()
.size([360, 360])// 角度360度,半径360px
.separation(function(a, b) {
return (a.parent == b.parent ? 1 : 2) / a.depth;// 父节点相同的节点邻距相等,不同的稍宽一点用来区分开
});
var diagonal = d3.svg.diagonal.radial()//(2)指定为径向布局
.projection(function(d) {
return [d.y, d.x / 180 * Math.PI];// 半径d.y和角度d.x / 180 * Math.PI(转换成弧度制)
});
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter - 150)
.append("g")
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
//(3)加载json
d3.json("flare.json", function(error, root) {
var nodes = tree.nodes(root),//返回值是一个数组,每个节点上填充一些计算后的属性,例如深度,坐标等。
links = tree.links(nodes);//返回节点数组的连接数组
//(4)为链接添加路径
var link = svg.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
//(5)节点转换位置
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
//(6)节点添加圆圈
node.append("circle")
.attr("r", 4.5);
//(7)节点添加文字
node.append("text")
.attr("dy", ".31em")
.attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })//小于180度的文字放在前面,否则放在后面
.attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
.text(function(d) { return d.name; });
});