結果預覽
vue 和 d3 的角色
畫圖可分為兩步:
- 元素座標計算
- 資料繫結
座標計算只需要一些 api,本文使用 d3。
資料繫結既可以藉助 d3,也可以使用 vue。d3 通過操作 dom 實現,有點像 jQuery,d3 針對資料和 dom 的狀態提出了三個概念:Update、Enter、Exit,感興趣的可以看官網。本文使用 vue 做資料繫結
總結:使用 d3 提供的 api 計算元素座標,使用 vue 進行資料繫結
座標計算
一棵樹由節點和連線構成,只需要計算出這兩種元素的座標即可
畫一棵樹常見的有兩種資料結構,一種是巢狀的,一種是扁平的。如下:
// 巢狀的
var treeData = {
name: `中國`,
children: [{
name: `北京`,
children: [{
name: `海淀`
}, {
name: `朝陽`
}]
}, {
name: `上海`
}]
};
// 扁平的
var flattenData = [{
name: `中國`,
parent: ``
}, {
name: `北京`,
parent: `中國`
}, {
name: `上海`,
parent: `中國`
}, {
name: `海淀`,
parent: `北京`
}, {
name: `朝陽`,
parent: `北京`
}]
複製程式碼
對於巢狀的資料,使用 d3.hierarchy() 計算座標,對於扁平的,使用 d3.stratify()。得到的結構如下(列舉根節點):
var hierarchyNode = {
depth: 0
height: 2
parent: null
x: 60
y: 0,
data: {
name: "中國",
children: []
},
children: []
};
複製程式碼
得到根節點後使用 descendants() 獲取所有節點資訊,links() 獲取所有連線資訊。節點的結構如上述,連線結構如下:
var link = {
source: Node,
target: Node
}
複製程式碼
至此,已獲取到所有元素的座標
資料繫結
使用 svg
樹的節點就是 rect + text,如下:
<g :transform="rootTransform">
<rect :width="nodeWidth" :height="nodeHeight" :fill="nodeFill"></rect>
<text :fill="nodeTextColor" text-anchor="middle" dominant-baseline="middle"
:y="nodeHeight / 2" :x="nodeWidth / 2">{{node.data.name}}</text>
</g>
複製程式碼
連線就是 path,如下:
<g>
<path :d="getLinkPath(link)" :stroke="linkStroke" fill="none" :stroke-width="linkStrokeWidth"></path>
</g>
複製程式碼
code
talk is cheap show me the code