var width = window.innerWidth * 0.5, height = window.innerHeight * 0.5, margin = { top: 50, left: 50, bottom: 50, right: 50 }; var rangeScale = d3.scale.pow() .exponent(10) .clamp(true) d3.select("body").append("input") .attr({ type: "range", value: 0, min: 0, max: 1, step: 0.01 }) .on("input", function() { mix = rangeScale(this.value); force.start(); }); var g = d3.select("body") .append("svg") .attr({ width: width + margin.left + margin.right, height: height + margin.top + margin.bottom }) .append("g") .attr({ transform: "translate(" + [margin.left, margin.top] + ")" }); var hierarchyA = function() { return { name: "a", children: [ { name: "b", children: [ {name: "d"}, {name: "e"} ] }, { name: "c", children: [ {name: "f", children: [ {name:"t"}, {name:"u"} ] }, {name: "g"}, {name: "h"} ] }, { name: "k", children: [ {name: "j", children: [ {name:"x", children: [{name:"y"}]} ]} ] } ] }; }; var hierarchyB = function() { return { name: "a", children: [ { name: "b", children: [ {name: "d"}, {name: "e"} ] }, { name: "c", children: [ {name: "f"}, {name: "g"} ] }, { name: "k", children: [ {name: "j"} ] }, { name: "n", children: [ {name: "m"}, {name: "q"} ] } ] }; }; var hierarchy = hierarchyA(); var force = d3.layout.force() .size([ width, height ]) .charge(-100) .linkDistance(40) .on("tick", draw); var tree = d3.layout.tree() .size([ width, height ]); var newNodes = tree(hierarchy); var node = g.selectAll(".node"); var toggle = true; function update() { toggle = !toggle; hierarchy = (toggle) ? hierarchyB() : hierarchyA(); var oldNodes = node.data(); var newNodes = tree(hierarchy) .map(function(d) { d.treeX = d.x; d.treeY = d.y; var i = oldNodes.map(function(d) { return d.name; }).indexOf(d.name); if (i == -1) { d.x = width / 2 + Math.random(); d.y = height / 2 + Math.random(); return d; } d.x = oldNodes[i].x; d.y = oldNodes[i].y; return d; }); node = g.selectAll(".node").data(newNodes, function(d) { return d.name; }); node.enter().append("g").classed("node", true) .append("circle").attr({ r: 1 }) .style({ fill: "#999", stroke: "#444" }) .transition().duration(1000) .attr({ r: 10 }); node.exit().remove(); node.call(force.drag); var newLinks = tree.links(newNodes); link = g.selectAll(".link").data(newLinks); link.enter().insert("g", "g.node").classed("link", true) .append("line").style({ stroke: "#444" }); link.exit().remove(); force.nodes(node.data()).links(link.data()).start(); } update(); window.setInterval(update, 2000); var mix = 0; function draw(event) { node.each(function(d) { d.x += (d.treeX - d.x) * mix * event.alpha; d.y += (d.treeY - d.y) * mix * event.alpha; }); node.attr({ transform: function(d) { return "translate(" + d.x + "," + d.y + ")"; } }); link.select("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; } }); }