Antv關於G6樹狀圖實現摺疊
最近專案上有個小需求需要用到類似思維導圖附帶實現摺疊效果。於是網上扒拉扒拉大多數還是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等 文件寫的還是比較全的。然後執行程式碼預覽:

下一步為節點新增事件:參考文件自定義互動 程式碼如下:
// 註冊節點事件 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> ) } 複製程式碼
效果圖:

第一次寫文章做得不好的地方希望大佬多多見諒...