简体   繁体   中英

Add a Toggle function to d3 tree chart v4

i'm new to d3 and i'm trying to render this d3 tree chart with left and right nodes. the initial tree render is working fine and i have added a toggle function that will make the children null and call the render method, but it's not working. please help.

 var data = { "name": "Root", "children": [{ "name": "Branch 1" }, { "name": "Branch 2", "children": [{ "name": "Branch 2.1" }, { "name": "Branch 2.2", "children": [{ "name": "Branch 2.2.1" }, { "name": "Branch 2.2.2" }] }] }, { "name": "Branch 3" }, { "name": "Branch 4", "children": [{ "name": "Branch 4.1" }, { "name": "Branch 4.2" }] }, { "name": "Branch 5" }, { "name": "Branch 6" }, { "name": "Branch 7", "children": [{ "name": "Branch 7.1" }, { "name": "Branch 7.2", "children": [{ "name": "Branch 7.2.1" }, { "name": "Branch 7.2.2" }] }] }, { "name": "Branch 8" }, { "name": "Branch 9", "children": [{ "name": "Branch 9.1" }, { "name": "Branch 9.2" }] }, { "name": "Branch 10" } ] }; var split_index = Math.round(data.children.length / 2) // Left data var data1 = { "name": data.name, "children": JSON.parse(JSON.stringify(data.children.slice(0, split_index))) }; // Right data var data2 = { "name": data.name, "children": JSON.parse(JSON.stringify(data.children.slice(split_index))) }; // Create d3 hierarchies var right = d3.hierarchy(data1); var left = d3.hierarchy(data2); // Render both trees drawTree(right, "right") drawTree(left, "left") // draw single tree function drawTree(root, pos) { var SWITCH_CONST = 1; if (pos === "left") { SWITCH_CONST = -1; } var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height") // Shift the entire tree by half it's width var g = svg.append("g").attr("transform", "translate(" + width / 2 + ",0)"); // Create new default tree layout var tree = d3.tree() // Set the size // Remember the tree is rotated // so the height is used as the width // and the width as the height .size([height, SWITCH_CONST * (width - 150) / 2]); tree(root) var nodes = root.descendants(); var links = root.links(); // Set both root nodes to be dead center vertically nodes[0].x = height / 2 // Create links var link = g.selectAll(".link") .data(links) .enter() link.append("path") .attr("class", "link") .attr("d", function(d) { return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x; }); // Create nodes var node = g.selectAll(".node") .data(nodes) .enter() .append("g") .attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); }) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }).on("click", function(e, d) { toggle(d, pos); }) node.append("circle") .attr("r", function(d, i) { return 2.5 }); node.append("text") .attr("y", -10) .style("text-anchor", "middle") .text(function(d) { return d.data.name }); } function toggle(d, pos) { console.log(d, pos); if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } this.drawTree(d, pos); }
 .node circle { fill: #999; } .node text { font: 12px sans-serif; } .node--internal circle { fill: #555; } .link { fill: none; stroke: #555; stroke-opacity: 0.4; stroke-width: 1.5px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script> <svg width="900" height="600"></svg>

You only appended new nodes, you never removed them. That way, the old nodes would stay there after a click. You can fix that by using .join() .

Also, you used the clicked node as the new root of the tree, but that's invalid. Instead, pass the true root and just redraw that part of the tree entirely. Otherwise, the rest of the tree is completely forgotten.

 var data = { "name": "Root", "children": [{ "name": "Branch 1" }, { "name": "Branch 2", "children": [{ "name": "Branch 2.1" }, { "name": "Branch 2.2", "children": [{ "name": "Branch 2.2.1" }, { "name": "Branch 2.2.2" }] }] }, { "name": "Branch 3" }, { "name": "Branch 4", "children": [{ "name": "Branch 4.1" }, { "name": "Branch 4.2" }] }, { "name": "Branch 5" }, { "name": "Branch 6" }, { "name": "Branch 7", "children": [{ "name": "Branch 7.1" }, { "name": "Branch 7.2", "children": [{ "name": "Branch 7.2.1" }, { "name": "Branch 7.2.2" }] }] }, { "name": "Branch 8" }, { "name": "Branch 9", "children": [{ "name": "Branch 9.1" }, { "name": "Branch 9.2" }] }, { "name": "Branch 10" } ] }; var split_index = Math.round(data.children.length / 2) // Left data var data1 = { "name": data.name, "children": JSON.parse(JSON.stringify(data.children.slice(0, split_index))) }; // Right data var data2 = { "name": data.name, "children": JSON.parse(JSON.stringify(data.children.slice(split_index))) }; // Create d3 hierarchies var right = d3.hierarchy(data1); var left = d3.hierarchy(data2); var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); // Shift the entire tree by half it's width var g = svg.append("g") .attr("transform", "translate(" + width / 2 + ",0)"); // Render both trees drawTree(right, "right") drawTree(left, "left") // draw single tree function drawTree(root, pos) { var SWITCH_CONST = 1; if (pos === "left") { SWITCH_CONST = -1; } // Create new default tree layout var tree = d3.tree() // Set the size // Remember the tree is rotated // so the height is used as the width // and the width as the height .size([height, SWITCH_CONST * (width - 150) / 2]); tree(root) var nodes = root.descendants(); var links = root.links(); // Set both root nodes to be dead center vertically nodes[0].x = height / 2 // Create links var link = g.selectAll(".link." + pos) .data(links) .join( enter => enter.append("path"), update => update, exit => exit.remove() ) .attr("class", "link " + pos) .attr("d", function(d) { return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x; }); // Create nodes var node = g.selectAll(".node." + pos) .data(nodes) .join( enter => { const n = enter .append("g") .on("click", (e, d) => toggle(d, pos, pos === "left" ? left : right)); n.append("circle").attr("r", 2.5); n.append("text").attr("y", -10).style("text-anchor", "middle"); return n; }, update => update, exit => exit.remove() ) .attr("class", function(d) { return "node " + pos + (d.children ? " node--internal" : " node--leaf"); }) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }) .select("text") .text(function(d) { return d.data.name }); } function toggle(d, pos, root) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } this.drawTree(root, pos); }
 .node circle { fill: #999; } .node text { font: 12px sans-serif; } .node--internal circle { fill: #555; } .link { fill: none; stroke: #555; stroke-opacity: 0.4; stroke-width: 1.5px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script> <svg width="900" height="600"></svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM