Skip to content

Instantly share code, notes, and snippets.

@d3noob
Last active November 21, 2023 09:38
Show Gist options
  • Save d3noob/8375092 to your computer and use it in GitHub Desktop.
Save d3noob/8375092 to your computer and use it in GitHub Desktop.
Interactive d3.js tree diagram
license: mit

This is a d3.js tree diagram that incldes an interactive element as used as an example in the book D3 Tips and Tricks.

Any parent node can be clicked on to collapse the portion of the tree below it, on itself. Conversly, it can be clicked on again to regrow.

It is derived from the Mike Bostock Collapsible tree example but it is a slightly cut down version.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Tree Example</title>
<style>
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 3px;
}
.node text {
font: 12px sans-serif;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 2px;
}
</style>
</head>
<body>
<!-- load the d3.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script>
var treeData = [
{
"name": "Top Level",
"parent": "null",
"children": [
{
"name": "Level 2: A",
"parent": "Top Level",
"children": [
{
"name": "Son of A",
"parent": "Level 2: A"
},
{
"name": "Daughter of A",
"parent": "Level 2: A"
}
]
},
{
"name": "Level 2: B",
"parent": "Top Level"
}
]
}
];
// ************** Generate the tree diagram *****************
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 960 - margin.right - margin.left,
height = 500 - 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 + ")");
root = treeData[0];
root.x0 = height / 2;
root.y0 = 0;
update(root);
d3.select(self.frameElement).style("height", "500px");
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// 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 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -13 : 13; })
.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);
// 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", 10)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// 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) {
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);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
</script>
</body>
</html>
@d3noob
Copy link
Author

d3noob commented Nov 16, 2019

I haven't done this myself, but a bit of a google indicates that there are some ways of accomplishing it. Try this for a start https://stackoverflow.com/questions/24784302/wrapping-text-in-d3

@erapisardi
Copy link

Thank you for your reply! I tried the solution you suggested, but it did not work, probably because I did not insert the code in the right line.

@d3noob
Copy link
Author

d3noob commented Nov 17, 2019

Okay, my second suggestion is to check out some of the examples in block builder for text wrapping and see if you can find one that matches the version of d3 you are using and the type of visualisation you are trying to implement. You can start here - https://blockbuilder.org/search?text=text+wrap&thumb=true
If that doesn't work, try raising a question in the d3 section on stack overflow here - https://stackoverflow.com/questions/tagged/d3.js
Best of luck.

@wujoho
Copy link

wujoho commented Jan 23, 2020

Hi, is it possible to make this project compatible with latest D3 version? I tried https://d3js.org/d3.v5.min.js and it didn't work.
Thanks

@d3noob
Copy link
Author

d3noob commented Jan 24, 2020

Hi, is it possible to make this project compatible with latest D3 version? I tried https://d3js.org/d3.v5.min.js and it didn't work.
Thanks

Funny you should ask. I recently updated all the examples from the book into v5. Check this example out.

@prashmalyala
Copy link

Hi, thanks for this great diagram! I was reading through the code + playing around with it on JSFiddle but am having trouble understanding how all the positioning is done. Is there a convenient way to rotate this visualization so I can represent a more hierarchical structure?

@d3noob
Copy link
Author

d3noob commented Jul 1, 2020

Hi, thanks for this great diagram! I was reading through the code + playing around with it on JSFiddle but am having trouble understanding how all the positioning is done. Is there a convenient way to rotate this visualization so I can represent a more hierarchical structure?

Sure! This example uses a pretty old version of d3. I reccomend changing to version 5 and you can find examples for a vertical layout from other examples here or you can get a full explanation of how the code works in the free book here

@prashmalyala
Copy link

Hi, thanks for this great diagram! I was reading through the code + playing around with it on JSFiddle but am having trouble understanding how all the positioning is done. Is there a convenient way to rotate this visualization so I can represent a more hierarchical structure?

Sure! This example uses a pretty old version of d3. I reccomend changing to version 5 and you can find examples for a vertical layout from other examples here or you can get a full explanation of how the code works in the free book here

The eBook helped lots; got it working. Thank you!

@SarahW91
Copy link

Hi! I would like to use a slightly modified version of this code in my larger project (released under AGPL 3.0). What kind of notice should I add to the file? Who does hold the Copyright for example? It's released unser MIT license, right?

@d3noob
Copy link
Author

d3noob commented Nov 13, 2020

Hi! I would like to use a slightly modified version of this code in my larger project (released under AGPL 3.0). What kind of notice should I add to the file? Who does hold the Copyright for example? It's released unser MIT license, right?

Hi Sarah, This example is released under the MIT licience. As such you are free to use it under that model. I make no copyright claim and really don't want to restrict anyone from using it as it is a derivative of Mike Bostocks original work and ultimately, it's there to be used and to make the World a better place, not to be hoarded :-). Please use it with my blessing and thanks.

@SarahW91
Copy link

Hi! I would like to use a slightly modified version of this code in my larger project (released under AGPL 3.0). What kind of notice should I add to the file? Who does hold the Copyright for example? It's released unser MIT license, right?

Hi Sarah, This example is released under the MIT licience. As such you are free to use it under that model. I make no copyright claim and really don't want to restrict anyone from using it as it is a derivative of Mike Bostocks original work and ultimately, it's there to be used and to make the World a better place, not to be hoarded :-). Please use it with my blessing and thanks.

Great, thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment