Built with blockbuilder.org
forked from frazboyz's block: fresh block
| license: mit |
Built with blockbuilder.org
forked from frazboyz's block: fresh block
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v5.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| let data = { | |
| id: 1, | |
| firstName: 'tom', | |
| children: [ | |
| { | |
| id: 2, | |
| firstName: 'Tei', | |
| children: [ | |
| { | |
| id: 3, | |
| firstName: 'Sam', | |
| } | |
| ], | |
| }, | |
| { | |
| id: 4, | |
| firstName: 'Hm', | |
| children: [ | |
| { | |
| id: 5, | |
| firstName: 'Tom', | |
| children: [ | |
| { | |
| id: 6, | |
| firstName: 'Hmmm', | |
| children: [ | |
| { | |
| id: 9, | |
| firstName: 'Lil' | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| id: 7, | |
| firstName: 'Hmmmmm', | |
| children: [ | |
| { | |
| id: 8, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 9, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 10, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 11, | |
| firstName: 'Tommy', | |
| children: [ | |
| { | |
| id: 12, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 13, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 14, | |
| firstName: 'Tommy' | |
| }, | |
| { | |
| id: 15, | |
| firstName: 'Tommy', | |
| children: [ | |
| ] | |
| }, | |
| ] | |
| }, | |
| ] | |
| } | |
| ] | |
| } | |
| // Feel free to change or delete any of the code you see in this editor! | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", 960) | |
| .attr("height", 470); | |
| var base = svg | |
| .append('g') | |
| .attr('transform', `translate(${960 / 2}, 20)`); | |
| var tree = d3.tree() | |
| .nodeSize([100 + 70, 200 + 50]); | |
| var root = d3.hierarchy(data); | |
| root.x0 = 0; | |
| root.y0 = 470 / 2 | |
| function onZoom() { | |
| base.attr('transform', d3.event.transform); | |
| } | |
| var zoom = d3.zoom() | |
| .scaleExtent([-5, 40]) | |
| .translateExtent([[-50000, -50000], [50000, 50000]]) | |
| .on('zoom', onZoom); | |
| svg.call(zoom) | |
| update(root); | |
| function update(source) { | |
| var treeData = tree(root); | |
| var nodes = treeData.descendants(); | |
| var node = base.selectAll('g.node') | |
| .data(nodes, (n) => n.data.id); | |
| var nodeEnter = node.enter() | |
| .append('g') | |
| .attr('class', 'node') | |
| .attr('fill', '#000') | |
| .attr('width', 200 + 50) | |
| .attr('height', 100 + 70) | |
| .attr('transform', () => `translate(${source.y}, ${source.x})`); | |
| nodeEnter.append('rect') | |
| .attr('width', 200) | |
| .attr('height', 100) | |
| .attr('fill', '#000') | |
| .attr('rx', 5) | |
| .attr('ry', 5) | |
| .attr('transform', `translate(0, -${100 / 2})`); | |
| node.exit().remove(); | |
| var nodeUpdate = nodeEnter.merge(node); | |
| nodeUpdate.transition() | |
| .duration(200) | |
| .attr('transform', (n) => `translate(${n.y}, ${n.x})`) | |
| function elbow(d) { | |
| const parts = [ | |
| `M${d.source.y + 200}, ${d.source.x}`, | |
| `H${d.target.y - (50 / 4)}`, | |
| `V${d.target.x}`, | |
| `M${d.target.y - (50 / 4)}, ${d.target.x}`, | |
| `H${d.target.y}`, | |
| ]; | |
| return parts.join(); | |
| } | |
| // Draw the paths between nodes | |
| const link = base.selectAll('path.link') | |
| .data(treeData.links(nodes), (n) => `${n.source.data.id}:${n.target.data.id}`); | |
| const linkEnter = link.enter() | |
| .append('path') | |
| .attr('class', 'link') | |
| .attr('fill', 'none') | |
| .attr('stroke', '#adadad') | |
| .attr('d', elbow); | |
| const linkUpdate = linkEnter.merge(link); | |
| linkUpdate.transition() | |
| .attr('d', elbow); | |
| link.exit().remove(); | |
| } | |
| function changeToLineage() { | |
| // Find the targets path with dfs | |
| const stack = []; | |
| let target = null; | |
| stack.push(root); | |
| while (stack.length) { | |
| const current = stack.pop(); | |
| if (current.data.id === 13) { // hard coded 7 | |
| target = current; | |
| break; | |
| } | |
| if (current.children || current.hiddenChildren) { | |
| (current.children || current.hiddenChildren || []).forEach(child => stack.push(child)); | |
| } | |
| } | |
| if (target) { | |
| let top = target; | |
| let previousTop = null; | |
| while (top) { | |
| top.hiddenChildren = top.children; | |
| if (previousTop) { | |
| top.children = [previousTop]; | |
| } else { | |
| top.children = null; | |
| } | |
| previousTop = top; | |
| top = top.parent; | |
| } | |
| console.log(root); | |
| update(root); | |
| } | |
| } | |
| </script> | |
| <button onclick="changeToLineage()">Change to lineage</button> | |
| </body> |