# 树图
## 需求
主要是展示分层结构形数据,例如展示中国部分城市:
上海,西安,宝鸡,北京,杭州,温州
## 分析
首先建议阅读[树图-中文](https://github.com/xswei/d3-hierarchy)
首先分析城市的层级,比如北京属于直辖,西安属于陕西。
``` javascript
var data = {
"name": "中国",
"children": [
{"name": "北京"},
{"name": "陕西",
"children": [
{"name": "宝鸡"},
{"name": "西安"}
]
},
{"name": "上海"},
{"name": "浙江",
"children": [
{"name": "杭州"},
{"name": "温州"}
]
},
]
}
```
为此我们可以得到这样的数据结构。
我们简要回顾饼图制作,饼图绘制需要使用d3.pie将数据转化为利于绘制,之后使用d3.arc绘制。
层次类图的绘制思路是相似的:
1. 将数据进行层次化,简单来说就是为每个节点加入更多属性:
* node .data - 为构造函数指定的关联数据。
* node .depth - 根节点为零,每个后代生成增加1。
* node .height - 叶节点为零,与内部节点的任何后代叶的最大距离。
* node .parent - 父节点,或根节点为null。
* node .children - 子节点数组(如果有); 未定义叶节点。
* node .value - 节点及其后代的总和值; 可选的,见节点的.sum和节点 .Count之间。
2. 将层次化好的数据,通过如d3.tree等进行布局。简单来说:就是通过设定当前绘制区域的大小,然后计算各节点的位置,大小等用于绘制的数据。
3. 通过绘制节点连线即可。
## 绘制
``` javascript
//创建svg
var svg = d3.select('#root')
.append('svg')
.attr('width', 600)
.attr('height', 600)
.style("background-color","rgb(142, 137, 137)");
var margin=[100,100,100,100]
var color = d3.scaleOrdinal(d3.schemeCategory20)
//模拟数据:
var data = {
"name": "中国",
"children": [
{"name": "北京"},
{"name": "陕西",
"children": [
{"name": "宝鸡"},
{"name": "西安"}
]
},
{"name": "上海"},
{"name": "浙江",
"children": [
{"name": "杭州"},
{"name": "温州"}
]
},
]
}
//将数据进行层次化
var dataSet = d3.hierarchy(data)
console.log(dataSet)
//创建树布局
var tree = d3.tree()
.size([400,400])
//所有的节点
var node =tree(dataSet)
console.log(node)
//拿到所有节点
var nodes = node.descendants()
//可以拿到所有的连线点
var links = node.links()
//此处注意得到所有位置点是从上到下的
//而我们经常使用的是从左到右
//所以我们应该在绘制时颠倒x和y值
//分组
var nodeG = svg.append('g')
.attr('transform','translate(100,100)')
var linksG = svg.append('g')
.attr('transform','translate(100,100)')
// 绘制节点
nodeG.selectAll('circle').data(nodes)
.enter()
.append('circle')
.attr('cx',function(d){return d.x})
.attr('cy',function(d){return d.y})
.attr('r',20)
.attr('fill',function(d,i){color(i)})
//绘制连线
var line = d3.linkHorizontal()
.x(function (d) {console.log(d); return d.x })
.y(function (d) { return d.y })
linksG.selectAll('path')
.data(links)
.enter()
.append('path')
.attr('d',line)
.attr('fill','none')
.attr('stroke','#eee')
```
细节提示:
1. 在设置图表垂直向下,或者水平向右的控制上没有相关函数处理,但我们可以在绘制时调换xy,在调换xy处,需要同时调换d3.tree设置的宽高。
2. 绘制线条时应考虑:
* d3.linkVertical - 创建一个新的垂直 link 生成器.
* d3.linkHorizontal - 创建一个新的水平的 link 生成器.
3. 绘制连线是注意path应该将fill属性设置为none。并设置stroke值。
4. 如图实例tree0,注意层级关系,应该将link放置在node前绘制。
## 实例
[tree0](https://doter1995.github.io/d3-start-course/tree/tree-0.html)
![](https://box.kancloud.cn/b6aea40c1ebbd998c6e2b598f6083448_449x532.png)
[tree1](https://doter1995.github.io/d3-start-course/tree/tree-1.html)
![](https://box.kancloud.cn/3147351ee63c4de44ff6978f66b8bde9_518x409.png)