Skip to content

Instantly share code, notes, and snippets.

@ajmistu
Last active August 2, 2017 04:44
Show Gist options
  • Select an option

  • Save ajmistu/3d84841c9faed61df77d1dceb12656e6 to your computer and use it in GitHub Desktop.

Select an option

Save ajmistu/3d84841c9faed61df77d1dceb12656e6 to your computer and use it in GitHub Desktop.
Sample 3 (Collapsible Force Layout w/ json file)
license: gpl-3.0

This example demonstrates how to create a force layout of a hierarchy whose internal nodes are collapsible. Leaf nodes are shown in orange, while internal nodes (packages) are shown in blue. Clicking on an internal node (without dragging) causes that node to expand or collapse, toggling the visibility of its descendant nodes.

forked from mbostock's block: Sample 4 (Collapsible Force Layout)

forked from AJ-Mengistu's block: Sample 3 (Collapsible Force Layout)

forked from AJ-Mengistu's block: Sample 3 (Collapsible Force Layout w/ json file)

{
"name": "1",
"children": [
{
"name": "omelet",
"size": 16302
},
{
"name": "tostada",
"size": 16302
},
{
"name": "burrito",
"size": 16302
},
{
"name": "2",
"children": [
{
"name": "hummus",
"size": 16540
},
{
"name": "3",
"children": [
{
"name": "fondue",
"size": 16302
},
{
"name": "4",
"children": [
{
"name": "sugar",
"size": 16540
},
{
"name": "5",
"children": [
{
"name": "lemonade",
"size": 16540
},
{
"name": "6",
"children": [
{
"name": "screwdriver",
"size": 16540
},
{
"name": "champagne",
"size": 16540
},
{
"name": "7",
"children": [
{
"name": "martini",
"size": 16540
},
{
"name": "8",
"children": [
{
"name": "egg yolk",
"size": 16540
}]}
]}
]}
]}
]
}
]
}
]
}
]
}
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node circle {
cursor: pointer;
stroke: #3182bd;
stroke-width: 1.5px;
}
.node text {
font: 14x sans-serif;
pointer-events: none;
text-anchor: left;
}
line.link {
fill: none;
stroke: #9ecae1;
stroke-width: 1.5px;
}
button#start {
margin-top: 20px;
width: 50px;
height: 20px;
float: left;
}
</style>
<body>
<button id="Reset" title="Start Layout to Beginning" onclick="window.location.reload()">
<b>Reset</b>
</button>
<p align="center"><b>Sample 3</b></p>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 1216,
height = 900,
root;
var force = d3.layout.force()
.linkDistance(50)
.charge(-630)
.gravity(.05)
.size([width, height])
.on("tick", tick);
//---Insert-------
var node_drag = d3.behavior.drag()
.on("dragstart", dragstart)
.on("drag", dragmove)
.on("dragend", dragend);
function dragstart(d, i) {
force.stop() // stops the force auto positioning before you start dragging
}
function dragmove(d, i) {
d.px += d3.event.dx;
d.py += d3.event.dy;
d.x += d3.event.dx;
d.y += d3.event.dy;
}
function dragend(d, i) {
d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
force.resume();
}
function releasenode(d) {
d.fixed = false; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
//force.resume();
}
//---End Insert------
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
d3.json("Sample3.json", function(error, json) {
if (error) throw error;
root = json;
update();
});
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update links.
link = link.data(links, function(d) { return d.target.id; });
link.exit().remove();
link.enter().insert("line", ".node")
.attr("class", "link");
// Update nodes.
node = node.data(nodes, function(d) { return d.id; });
node.exit().remove();
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("click", click)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; });
// label nodes and bubbles
nodeEnter.append("text")
.attr("dy", "0.35em")
.attr("dx", "1em")
.text(function(d) { return d.name; });
node.select("circle")
.style("fill", color);
}
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
function color(d) {
return d._children ? "#3182bd" // collapsed package
: d.children ? "#c6dbef" // expanded package
: "#fd8d3c"; // leaf node
}
// Toggle children on click.
function click(d) {
if (d3.event.defaultPrevented) return; // ignore drag
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [], i = 0;
function recurse(node) {
if (node.children) node.children.forEach(recurse);
if (!node.id) node.id = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
</script>
{
"name": "1",
"x": 100,
"y": 100,
"fixed": true,
"class": "node",
"children": [
{
"name": "omelet",
"size": 16302
},
{
"name": "tostada",
"size": 16302
},
{
"name": "burrito",
"size": 16302
},
{
"name": "2",
"x": 150,
"y": 150,
"fixed": true,
"class": "node",
"children": [
{
"name": "hummus",
"size": 16540
},
{
"name": "3",
"x": 200,
"y": 200,
"fixed": true,
"class": "node",
"children": [
{
"name": "fondue",
"size": 16302
},
{
"name": "4",
"x": 280,
"y": 250,
"fixed": true,
"class": "node",
"children": [
{
"name": "sugar",
"size": 16540
},
{
"name": "5",
"x": 350,
"y": 300,
"fixed": true,
"class": "node",
"children": [
{
"name": "lemonade",
"size": 16540
},
{
"name": "6",
"x": 450,
"y": 330,
"fixed": true,
"class": "node",
"children": [
{
"name": "screwdriver",
"size": 16540
},
{
"name": "champagne",
"size": 16540
},
{
"name": "7",
"x": 540,
"y": 340,
"fixed": true,
"class": "node",
"children": [
{
"name": "martini",
"size": 16540
},
{
"name": "8",
"x": 620,
"y": 340,
"fixed": true,
"class": "node",
"children": [
{
"name": "egg yolk",
"size": 16540
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment