D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
mwang102
Full window
Github gist
D3js Binary Tree
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <link rel="stylesheet" href="/styles.css"> <script src="//d3js.org/d3.v3.min.js"></script> <script type ="text/javascript" src="./binarytree.js"></script> <title>Binary Tree</title> </head> <style> .node { } .node circle { fill: #fff; stroke: steelblue; stroke-width: 1.5px; } .node text { font: 10px sans-serif; } .link { fill: none; stroke: #ccc; stroke-width: 1.5px; } .container{ display:flex; flex-direction:column; } .addData{ display:flex; } </style> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div class="container"> <button onClick="logTree()"> Console Log Tree </button> <button onClick="search('in-order')"> Search In-Order</button> <button onClick="search('pre-order')"> Search Pre-Order</button> <button onClick="search('post-order')"> Search Post-Order</button> <div class="addData"> <button onClick="addData()"> Add Data </button> <input id="value" value="65"></input> </div> </div> <script> var margin = {top: 20, right: 120, bottom: 20, left: 120}, width = 960 - margin.right - margin.left, height = 800 - margin.top - margin.bottom; var i = 0, duration = 750, root; var tree = d3.layout.tree() .size([height, width]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [d.y, d.x]; }); var 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 + ")"); // problem is that you cant set parent property with the // weird [empty, BST] i set up let newBST = new BST(50,50) newBST.insert(20,20) newBST.insert(60,60) newBST.insert(70,70) newBST.insert(80,80) newBST.insert(10,10) newBST.insert(15,15) newBST.insert(5,5) newBST.insert(1,1) newBST.insert(100,100) root = newBST; root.x0 = height / 2; root.y0 = 0; update(root); d3.select(self.frameElement).style("height", "800px"); function newTree(){ let value = parseInt(document.getElementById('treeValue').value), newBST = new BST(value,value) update(newBST) } function update(source) { // Compute the new tree layout. var nodes = tree.nodes(root).reverse().sort((a,b)=> { return a.depth - b.depth}).filter((d)=>{ return d.value != null}), links = tree.links(nodes).filter((d)=>{ return d.target.value != null}); // Normalize for fixed-depth. nodes.forEach(function(d,i) { if(nodes[i].parent){ if(nodes[i].parent.value >= nodes[i].value){ nodes[i].x = nodes[i].parent.x + 50 }else if(nodes[i].parent.value < nodes[i].value){ nodes[i].x = nodes[i].parent.x - 50 } } d.y = d.depth * 100; }); // Update the nodes… var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }); // Enter any new nodes 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 + ")"; }) nodeEnter.append("circle") .attr("r", 1e-6) .attr('id', (d,i)=>{ return 'circle' + nodes[i].id }) .style("fill", function(d,i) { return d._children ? "lightsteelblue" : "#fff"; }); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -20 : 20; }) .attr("dy", ".35em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.name; }) .style("fill-opacity", 1e-6) .style("font-size", "20px"); // Transition nodes to their new position. var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); nodeUpdate.select("circle") .attr("r", (d,i)=>{ return 12 }) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); // Update the links… var link = svg.selectAll("path.link") .data(links, function(d) { return d.target.id; }); // Enter any new links at the parent's previous position. link.enter().insert("path", "g") .attr("class", "link") .attr("d", function(d,i) { var o = {x: source.x0, y: source.y0}; return diagonal({source: o, target: o}); }); // Transition links to their new position. link.transition() .duration(duration) .attr("d", diagonal); } function addData(){ let value = parseInt(document.getElementById('value').value) newBST.insert(value,value) update(newBST) } function logTree(d){ console.log(root) } function search(order){ let queue = newBST.depthFirstTraversal(order).reverse(), interval = setInterval(highlight, 700) function highlight(id){ let popped = queue.pop() currentNode = '#circle' + popped svg.selectAll(currentNode) .transition() // First fade to green. .style("fill", "green") .transition() // Then red. .style("fill", "red") .transition() // Wait one second. Then brown, and remove. .delay(1000) .style("fill", "white") if(queue.length == 0 ){ clearInterval(interval) } } } </script> </body> </html>
https://d3js.org/d3.v3.min.js