var width = 300, height = 300, margin = { top: 50, left: 50, bottom: 50, right: 50 }; var g = d3.select("body") .append("svg") .attr({ width: width + margin.left + margin.right, height: height + margin.top + margin.bottom }) .style({ "margin-left": 200 }) .append("g") .attr({ transform: "translate(" + [margin.left, margin.top] + ")" }); var hierarchyA = { name: "a", children: [ { name: "b", children: [ {name: "e"} ] }, { name: "c", children: [ {name: "f"}, {name: "g"}, {name: "h"} ] } ] }; var hierarchyB = { name: "a", children: [ { name: "b", children: [ {name: "d"}, {name: "e"} ] }, { name: "c", children: [ {name: "f"}, {name: "g"} ] }, { name: "i", children: [ {name: "j"} ], foo: 234234 } ] }; var hierarchy = hierarchyA; var tree = d3.layout.tree() .size([ width, height ]) .children(function(d) { return d.children; }); var linkG = g.append("g").classed("links", true); var nodeG = g.append("g").classed("nodes", true); function update() { var nodes = tree(hierarchy); var links = tree.links(nodes); ////////////// // Links ////////////// var link = linkG.selectAll("g.link") .data(links, function(d) { return d.source.name + d.target.name; }); link.select("line") .transition().duration(1000) .attr({ x1: function(d) { return d.source.x; }, x2: function(d) { return d.target.x; }, y1: function(d) { return d.source.y; }, y2: function(d) { return d.target.y; } }); link.enter().append("g").classed("link", true) .append("line") .attr({ x1: function(d) { return d.source.x; }, x2: function(d) { return d.target.x; }, y1: function(d) { return d.source.y; }, y2: function(d) { return d.target.y; } }) .style({ stroke: "#444", "stroke-opacity": 0 }) .transition().duration(1000) .style({ "stroke-opacity": 1 }); link.exit() .transition().duration(1000) .call(function(t) { t.select("line") .style({ "stroke-opacity": 0 }); }) .remove(); ////////////// // Nodes ////////////// // DATA JOIN var node = nodeG.selectAll("g.node") .data(nodes, function(d) { return d.name; }); // UPDATE node.transition().duration(1000) .attr({ transform: function(d) { return "translate(" + [d.x, d.y] + ")"; } }); // EXIT node.exit() .transition().duration(1000) .call(function(t) { t.select("circle") .style({ fill: "#f00" }) .attr({ r: 0 }); }) .remove(); // ENTER node.enter().append("g").classed("node", true) .attr({ transform: function(d) { return "translate(" + [d.x, d.y] + ")"; } }) .append("circle") .style({ fill: "#0f0", "stroke": "#333" }) .attr({ r: 0 }) .transition().duration(1000) .attr({ r: 10 }) .style({ fill: "#ddd" }); // TODO: Grow radius on enter // UPDATE + ENTER // .... } update(); window.setInterval(switchData, 2000); function switchData() { hierarchy = (hierarchy == hierarchyA) ? hierarchyB : hierarchyA; update(); }