I created this network click-expand-collapse - http://jsfiddle.net/5Lv8gkqv/
var width = 960, height = 500, root = { "name": "Chocolate", "tag":"class", "children": [ { "name": "Wafer", "tag":"subclass", "children": [ { "name": "Nestle", "tag":"company", "children": [ {"name": "KitKat", "tag":"product"} ] } ] }, { "name": "White", "tag":"subclass", "children": [ { "name": "Nestle", "tag":"company", "children": [ {"name": "Milkybar", "tag":"product"} ] } ] }, { "name": "Caramel", "tag":"subclass", "children": [ { "name": "Nestle", "tag":"company", "children": [ {"name": "BarOne", "tag":"product"} ] } ] }, { "name": "Milk", "tag":"subclass", "children": [ { "name": "Nestle", "tag":"company", "children": [ {"name": "Nestle Milk", "tag":"product"} ] }, { "name": "Cadbury", "tag":"company", "children": [ {"name": "Dairy Milk", "tag":"product"} ] } ] } ] }; var force = d3.layout.force() .linkDistance(150) .charge(-120) .gravity(.05) .size([width, height]) .on("tick", tick); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var link = svg.selectAll(".link"), node = svg.selectAll(".node"); flatten(root); //to set ids setParents(root, null); collapseAll(root); root.children = root._children; root._children = null; 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; }); nodeEnter.append("text") .attr("dy", ".35em") .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(" + dx + "," + dy + ")"; }); } 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) { collapseAll(d); } else { if (d._parent){ d._parent.children.forEach(function(e){ if (e != d){ collapseAll(e); } }); } d.children = d._children; d._children = null; } update(); } function collapseAll(d){ if (d.children){ d.children.forEach(collapseAll); d._children = d.children; d.children = null; } else if (d._childred){ d._children.forEach(collapseAll); } } // 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; } function setParents(d, p){ d._parent = p; if (d.children) { d.children.forEach(function(e){ setParents(e,d);}); } else if (d._children) { d._children.forEach(function(e){ setParents(e,d);}); } }
Now the thing is, I was wondering if it is possible to have a node-size proportional to the number of children. Thus, the parent node will be the largest circle, and the node sheet will be the smallest, and the intermediate size of the node will depend on the number of children that each one has.