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)
xxxxxxxxxx
<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;
/* stroke-dasharray: 20,10,5,5,5,10 */
}
</style>
<body>
<p align="center"><b>Sample 2</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("Sample2fixednodes.json", function(error, json) {
if (error) throw error;
root = json;
root.children.forEach(click); // Hide grandchildren of the root.
update();
});
function update(d) {
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);
node.append("title")
.text(function(d) { return d.name; });
}
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>
https://d3js.org/d3.v3.min.js