Skip to content

Instantly share code, notes, and snippets.

@Francismb
Last active April 17, 2019 09:15
Show Gist options
  • Save Francismb/9d0c834e5c99e1da9481ea6c922cf9ca to your computer and use it in GitHub Desktop.
Save Francismb/9d0c834e5c99e1da9481ea6c922cf9ca to your computer and use it in GitHub Desktop.
fresh block
license: mit
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment