代码片段 //添加一个新节点(作为子节点)到选中的节点(代码片段)var newNode = {类型:'节点类型',名称:新日期().getTime(),孩子们: []};//使用 d3.hierarchy(.) 从 newNode 对象创建一个节点var newNode = d3.hierarchy(newNode);//后来给Node添加了一些属性,比如child,parent,depthnewNode.depth = selected.depth + 1;newNode.height = selected.height - 1;newNode.parent = 选中;newNode.id = Date.now();//Selected 是一个节点,我们将新节点作为子节点添加到该节点//如果没有子数组,则创建一个空数组如果(!selected.children){selected.children = [];selected.data.children = [];}//推送到parent.children数组selected.children.push(newNode);selected.data.children.push(newNode.data);//更新树更新(选择);小提琴//### 数据模型开始变量数据 = {类型:'动作',名称:'1',属性: [],孩子们: [{类型:儿童",名称:'2',属性: [{源类型属性值":街灯"}],孩子们: [{类型:'父母',名称:'3',属性: [{源类型属性值":电缆"}],孩子们: [{类型:'资源删除',名称:'4',属性: [],孩子们: []}]}, {类型:儿童",名称:'5',属性: [{源类型属性值":灯笼"}],孩子们: []}]}]};//### 数据模型结束//设置图表的尺寸和边距var margin = {top: 20, right: 90, bottom: 30, left: 90},宽度 = 960 - margin.left - margin.right,高度 = 500 - margin.top - margin.bottom;//将 svg 对象附加到页面主体//将一个 'group' 元素附加到 'svg'//将 'group' 元素移动到左上角var svg = d3.select("body").追加(svg").attr("width", width + margin.right + margin.left).attr("height", height + margin.top + margin.bottom).追加(g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");var i = 0,持续时间 = 750,根;//声明一个树布局并分配大小var treemap = d3.tree().size([height, width]);//分配父级、子级、高度、深度root = d3.hierarchy(数据,函数(d){返回 d. 儿童;});root.x0 = 高度/2;根.y0 = 0;更新(根);var 选择 = null;功能更新(来源){//为节点分配 x 和 y 位置var treeData = treemap(root);//计算新的树布局.var 节点 = treeData.descendants(),链接 = treeData.descendants().slice(1);//标准化固定深度.节点.forEach(函数(d){d.y = d.depth * 180});//### 链接//更新链接...var link = svg.selectAll('line.link').数据(链接,功能(d){返回 d.id;});//在父级之前的位置输入任何新链接.var linkEnter = link.enter().追加('行').attr(类",链接").attr("笔画宽度", 2).attr(中风",黑色").attr('x1', 函数(d) {返回源.y0;}).attr('y1', 函数(d) {返回源.x0;}).attr('x2', 函数(d) {返回源.y0;}).attr('y2', 函数(d) {返回源.x0;});var linkUpdate = linkEnter.merge(link);linkUpdate.transition().持续时间(持续时间).attr('x1', 函数(d) {返回 d.parent.y;}).attr('y1', 函数(d) {返回 d.parent.x;}).attr('x2', 函数(d) {返回 d.y;}).attr('y2', 函数(d) {返回 d.x;});//过渡回父元素位置linkUpdate.transition().持续时间(持续时间).attr('x1', 函数(d) {返回 d.parent.y;}).attr('y1', 函数(d) {返回 d.parent.x;}).attr('x2', 函数(d) {返回 d.y;}).attr('y2', 函数(d) {返回 d.x;});//删除所有现有链接var linkExit = link.exit().过渡().持续时间(持续时间).attr('x1', 函数(d) {返回源.x;}).attr('y1', 函数(d) {返回源.y;}).attr('x2', 函数(d) {返回源.x;}).attr('y2', 函数(d) {返回源.y;}).消除();//### 圆圈//更新节点...var node = svg.selectAll('g.node').data(节点,函数(d){返回 d.id ||(d.id = ++i);});//在父级之前的位置输入任何新模式.var nodeEnter = node.enter().追加('g').属性('类','节点').attr(转换",函数(d){return "translate(" + source.y0 + "," + source.x0 + ")";}).on('点击', 点击);//为节点添加圆nodeEnter.append('circle').属性('类','节点').attr('r', 25).样式(填充",函数(d){返回#0e4677";});//更新var nodeUpdate = nodeEnter.merge(node);//过渡到节点的正确位置nodeUpdate.transition().持续时间(持续时间).attr(转换",函数(d){返回 "translate(" + d.y + "," + d.x + ")";});//更新节点属性和样式nodeUpdate.select('circle.node').attr('r', 25).样式(填充",函数(d){返回#0e4677";}).attr('光标', '指针');//删除所有存在的节点var nodeExit = node.exit().过渡().持续时间(持续时间).attr(转换",函数(d){return "translate(" + source.y + "," + source.x + ")";}).消除();//在退出时将节点圆圈大小减少到 0nodeExit.select('circle').attr('r', 0);//存储用于转换的旧位置.节点.forEach(函数(d){d.x0 = d.x;d.y0 = d.y;});//点击时切换子项.功能点击(d){选择 = d;document.getElementById('add-child').disabled = false;document.getElementById('remove').disabled = false;更新);}}document.getElementById('add-child').onclick = function() {//创建新对象var newNodeObj = {类型:'资源删除',名称:新日期().getTime(),属性: [],孩子们: []};//创建新节点var newNode = d3.hierarchy(newNodeObj);newNode.depth = selected.depth + 1;newNode.height = selected.height - 1;newNode.parent = 选中;newNode.id = Date.now();如果(!selected.children){selected.children = [];selected.data.children = [];}selected.children.push(newNode);selected.data.children.push(newNode.data);更新(选择);};<script src="https://d3js.org/d3.v4.min.js"></script><button id="add-child" disabled="disabled">添加子项</button>I am using D3 v4 to build a tree.Fiddle:https://jsfiddle.net/a6pLqpxw/I am now trying to add support for dynamically adding (and removing) children from a selected node.However I cannot get the chart to redraw without having to perform a complete redraw. I have modified the code from the collapsible tree diagram code at: https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecdSpecifically the following block does not perform a recalculation of the layout for its children.document.getElementById('add-child').onclick = function() { console.log(selected); selected.children.push({ type: 'resource-delete', name: new Date().getTime(), attributes: [], children: [] }); update(selected);};Does anyone have any good examples of dynamically adding/removing nodes to tree's in D3.js v4? 解决方案 I came up with this solution for Adding new Node dynamically to D3 Tree v4. .D3 v4 tree requires Nodes.Create Nodes from your tree data (json) using d3.hierarchy(..) and pushed it into it's parent.children array and update the tree.Code Snippet //Adding a new node (as a child) to selected Node (code snippet)var newNode = { type: 'node-type', name: new Date().getTime(), children: [] }; //Creates a Node from newNode object using d3.hierarchy(.) var newNode = d3.hierarchy(newNode); //later added some properties to Node like child,parent,depth newNode.depth = selected.depth + 1; newNode.height = selected.height - 1; newNode.parent = selected; newNode.id = Date.now(); //Selected is a node, to which we are adding the new node as a child //If no child array, create an empty array if(!selected.children){ selected.children = []; selected.data.children = []; } //Push it to parent.children array selected.children.push(newNode); selected.data.children.push(newNode.data); //Update tree update(selected);Fiddle// ### DATA MODEL STARTvar data = {type: 'action', name: '1', attributes: [], children: [{ type: 'children', name: '2', attributes: [{ 'source-type-property-value': 'streetlight' }], children: [{ type: 'parents', name: '3', attributes: [{ 'source-type-property-value': 'cable' }], children: [{ type: 'resource-delete', name: '4', attributes: [], children: [] }] }, { type: 'children', name: '5', attributes: [{ 'source-type-property-value': 'lantern' }], children: [] }] }]};// ### DATA MODEL END// Set the dimensions and margins of the diagramvar margin = {top: 20, right: 90, bottom: 30, left: 90},width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom;// append the svg object to the body of the page// appends a 'group' element to 'svg'// moves the 'group' element to the top left marginvar svg = d3.select("body").append("svg"). attr("width", width + margin.right + margin.left). attr("height", height + margin.top + margin.bottom). append("g"). attr("transform", "translate(" + margin.left + "," + margin.top + ")");var i = 0, duration = 750, root;// declares a tree layout and assigns the sizevar treemap = d3.tree().size([height, width]);// Assigns parent, children, height, depthroot = d3.hierarchy(data, function(d) {return d.children;});root.x0 = height / 2;root.y0 = 0;update(root);var selected = null;function update(source) { // Assigns the x and y position for the nodes var treeData = treemap(root); // Compute the new tree layout. var nodes = treeData.descendants(), links = treeData.descendants().slice(1); // Normalize for fixed-depth. nodes.forEach(function(d){ d.y = d.depth * 180 }); // ### LINKS // Update the links... var link = svg.selectAll('line.link'). data(links, function(d) { return d.id; }); // Enter any new links at the parent's previous position. var linkEnter = link.enter(). append('line'). attr("class", "link"). attr("stroke-width", 2). attr("stroke", 'black'). attr('x1', function(d) { return source.y0; }). attr('y1', function(d) { return source.x0; }). attr('x2', function(d) { return source.y0; }). attr('y2', function(d) { return source.x0; }); var linkUpdate = linkEnter.merge(link); linkUpdate.transition(). duration(duration). attr('x1', function(d) { return d.parent.y; }). attr('y1', function(d) { return d.parent.x; }). attr('x2', function(d) { return d.y; }). attr('y2', function(d) { return d.x; }); // Transition back to the parent element position linkUpdate.transition(). duration(duration). attr('x1', function(d) { return d.parent.y; }). attr('y1', function(d) { return d.parent.x; }). attr('x2', function(d) { return d.y; }). attr('y2', function(d) { return d.x; }); // Remove any exiting links var linkExit = link.exit(). transition(). duration(duration). attr('x1', function(d) { return source.x; }). attr('y1', function(d) { return source.y; }). attr('x2', function(d) { return source.x; }). attr('y2', function(d) { return source.y; }). remove();// ### CIRCLES // Update the nodes... var node = svg.selectAll('g.node') .data(nodes, function(d) { return d.id || (d.id = ++i); }); // Enter any new modes at the parent's previous position. var nodeEnter = node.enter(). append('g'). attr('class', 'node'). attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }). on('click', click); // Add Circle for the nodes nodeEnter.append('circle'). attr('class', 'node'). attr('r', 25). style("fill", function(d) { return "#0e4677"; }); // Update var nodeUpdate = nodeEnter.merge(node); // Transition to the proper position for the node nodeUpdate.transition(). duration(duration). attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); // Update the node attributes and style nodeUpdate.select('circle.node'). attr('r', 25). style("fill", function(d) { return "#0e4677"; }). attr('cursor', 'pointer'); // Remove any exiting nodes var nodeExit = node.exit(). transition(). duration(duration). attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }). remove(); // On exit reduce the node circles size to 0 nodeExit.select('circle').attr('r', 0); // Store the old positions for transition. nodes.forEach(function(d){ d.x0 = d.x; d.y0 = d.y; }); // Toggle children on click. function click(d) { selected = d; document.getElementById('add-child').disabled = false; document.getElementById('remove').disabled = false; update(d); }}document.getElementById('add-child').onclick = function() { //creates New OBJECT var newNodeObj = { type: 'resource-delete', name: new Date().getTime(), attributes: [], children: [] }; //Creates new Node var newNode = d3.hierarchy(newNodeObj); newNode.depth = selected.depth + 1; newNode.height = selected.height - 1; newNode.parent = selected; newNode.id = Date.now(); if(!selected.children){ selected.children = []; selected.data.children = []; } selected.children.push(newNode); selected.data.children.push(newNode.data); update(selected);};<script src="https://d3js.org/d3.v4.min.js"></script><button id="add-child" disabled="disabled">Add Child</button> 这篇关于将节点添加到 D3 树 v4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!