1 前沿
最近项目上有个小需求需要用到类似思维导图附带实现折叠效果。于是网上扒拉扒拉大多数还是d3.js,但是浏览 d3.js后发现配置太多太繁琐就放弃了。后来就在我大金网上看到了antv (默默的心里说一句安ant六批啊...)
2 技巧/思路
首先实现思路最主要的就是实现点击隐藏再次点击时显示所以我们需要一个函数暂定为toggle
function toggle(d) {
}
然后我们在看antv给我们的示例代码:
G6.registerNode('treeNode', {
anchor: [[0, 0.5], [1, 0.5]]
});
G6.registerEdge('smooth', {
getPath: function getPath(item) {
var points = item.getPoints();
var start = points[0];
var end = points[points.length - 1];
var hgap = Math.abs(end.x - start.x);
if (end.x > start.x) {
return [['M', start.x, start.y], ['C', start.x hgap / 4, start.y, end.x - hgap / 2, end.y, end.x, end.y]];
}
return [['M', start.x, start.y], ['C', start.x - hgap / 4, start.y, end.x hgap / 2, end.y, end.x, end.y]];
}
});
var layout = new G6.Layouts.CompactBoxTree({
//direction: 'LR', // 方向(LR/RL/H/TB/BT/V)
getHGap: function getHGap() /* d */ {
// 横向间距
return 100;
},
getVGap: function getVGap() /* d */ {
// 竖向间距
return 10;
}
});
var tree = new G6.Tree({
renderer: 'svg',
id: 'mountNode', // 容器ID
height: window.innerHeight, // 画布高
layout: layout,
model: ['mouseEnterFillRed'],
fitView: 'autoZoom' // 自动缩放
});
tree.node({
shape: 'treeNode',
size: 8,
label: function label(model) {
if (model.children && model.children.length > 0) {
return {
text: model.name,
textAlign: 'right',
color: "#0F0"
};
}
return {
text: model.name,
textAlign: 'left',
color: "#F00"
};
},
labelOffsetX: function labelOffsetX(model) {
if (model.children && model.children.length > 0) {
return -10;
}
return 10;
}
})
tree.edge({
shape: 'smooth'
});
tree.read({
roots: [data]
});
tree.read()方法告诉我们填入渲染数据,然后造一点假数据
const data = {
"id": "17",
"name": "proName",
"children": [
{
"id": "18",
"name": "前期准备阶段",
"warning": "true",
"layer": "1",
"children": [
{"id": "19", "name": "前期调研",href: "dyurl","layer": "2"},
{"id": "20", "name": "指标设计",href: "zburl", "layer": "2"},
{"id": "23", "name": "问卷设计",href: "wjurl", "layer": "2"},
{"id": "24", "name": "方案撰写",href: "faurl", "layer": "2"},
]
},
{
"id": "28",
"name": "指标评价阶段",
"layer": "1",
"children": [
{"id": "21", "name": "初步评价阶段"},
{"id": "22", "name": "专家评分"},
{"id": "30", "name": "问卷分析"}
]
},
{
"id": "29",
"name": "结果报告阶段",
"children": [
{"id": "31", "name": "指标评分"},
{"id": "32", "name": "报告撰写"},
]
}
]
}
其余的方法如registerEdge registerNode等 文档写的还是比较全的。然后运行代码预览:
![](http://www.mk2048.com/web_upload/blog_imgs/5/https___user-gold-cdn-xitu-io_2018_10_19_1668b507992976a8_w-906_h-574_f-png_s-81921.gif)
下一步为节点添加事件:参考文档 自定义交互 代码如下:
// 注册节点事件
tree.on('node:click', (ev)=> {
//注册点击事件后调用toggle函数
console.log('-->', ev)
toggle(ev.item.model)
})
//toggle函数
function toggle(d) {
// 判断节点数据是否存在children 存在就将数据保存在_children下
if(d.children !== null) {
d._children = d.children
d.children = null
}else {
d.children = d._children
d._children = null
}
}
现在toggle函数已经写好了,点击后节点数据也发生改变。最后要做的就是将改变的数据更新到视图中。查询相关文档找到 ***graph.update(item, model)***。tree又继承于graph 于是有如下:
function toggle(d) {
if(d.children !== null) {
d._children = d.children
d.children = null
}else {
d.children = d._children
d._children = null
}
tree.update(tree.find(d.id), {
//节点是否折叠 collapsed
collapsed: d.children?false:true
})
}
至此树状图实现点击隐藏的功能完成。 完整代码如下:
componentDidMount() {
const data = {
"id": "17",
"name": "proName",
"layer": "10",
"current": "true",
"children": [
{
"id": "18",
"name": "前期准备阶段",
"warning": "true",
"layer": "1",
"children": [
{"id": "19", "name": "前期调研",href: "dyurl","layer": "2"},
{"id": "20", "name": "指标设计",href: "zburl", "layer": "2"},
{"id": "23", "name": "问卷设计",href: "wjurl", "layer": "2"},
{"id": "24", "name": "方案撰写",href: "faurl", "layer": "2"},
]},
{"id": "28", "name": "指标评价阶段", "layer": "1", "children": [
{"id": "21", "name": "初步评价阶段",href: "cpurl", "layer": "2"},
{"id": "22", "name": "专家评分",href: "zjurl", "layer": "2"},
{"id": "30", "name": "问卷分析",href: "fxurl", "layer": "2"},
]},
{"id": "29", "name": "结果报告阶段","layer": "1", "children": [
{"id": "31", "name": "指标评分",href: "zbpfurl", "layer": "2"},
{"id": "32", "name": "报告撰写",href: "bgurl", "layer": "2"},
]
}
]
}
G6.registerNode('treeNode', {
anchor: [[0, 0.5], [1, 0.5]]
});
G6.registerEdge('smooth', {
getPath: function getPath(item) {
var points = item.getPoints();
var start = points[0];
var end = points[points.length - 1];
var hgap = Math.abs(end.x - start.x);
if (end.x > start.x) {
return [['M', start.x, start.y], ['C', start.x hgap / 4, start.y, end.x - hgap / 2, end.y, end.x, end.y]];
}
return [['M', start.x, start.y], ['C', start.x - hgap / 4, start.y, end.x hgap / 2, end.y, end.x, end.y]];
}
});
var layout = new G6.Layouts.CompactBoxTree({
//direction: 'LR', // 方向(LR/RL/H/TB/BT/V)
getHGap: function getHGap() /* d */ {
// 横向间距
return 100;
},
getVGap: function getVGap() /* d */ {
// 竖向间距
return 10;
},
nodeSep: function() {
// 节点间距
},
nodeSize: ()=> {
//节点大小
},
subTreeSep: ()=> {
// 子树间隔
}
});
var tree = new G6.Tree({
renderer: 'svg',
id: 'mountNode', // 容器ID
height: window.innerHeight, // 画布高
layout: layout,
model: ['mouseEnterFillRed'],
fitView: 'autoZoom' // 自动缩放
});
tree.node({
shape: 'treeNode',
size: 8,
label: function label(model) {
if (model.children && model.children.length > 0) {
return {
text: model.name,
textAlign: 'right',
color: "#0F0"
};
}
return {
text: model.name,
textAlign: 'left',
color: "#F00"
};
},
labelOffsetX: function labelOffsetX(model) {
if (model.children && model.children.length > 0) {
return -10;
}
return 10;
}
})
tree.edge({
shape: 'smooth'
});
tree.read({
roots: [data]
});
// 注册节点事件
tree.on('node:click', (ev)=> {
console.log('ononono===>', ev.item.getModel().collapsed)
toggle(ev.item.model)
})
// 数据筛选
function toggle(d) {
if(d.children !== null) {
d._children = d.children
d.children = null
}else {
d.children = d._children
d._children = null
}
tree.update(tree.find(d.id), {
collapsed: d.children?false:true
})
}
}
render() {
return(
<div>
<div id="mountNode" ></div>
</div>
)
}
效果图:
![](http://www.mk2048.com/web_upload/blog_imgs/5/https___user-gold-cdn-xitu-io_2018_10_19_1668b7e400d369f1_w-932_h-620_f-gif_s-788763.gif)