I have a diagram very similar to circle packing
At some point, a user wants to see some different data. Obviously, a different diagram can be displayed immediately, but transition would be much better from perception and cognition point of view. NOTE: The hierarchical structure remains the same, there is no new or deleted nodes, just underlying values that determine circle size change.
What would be the good way to implement such smooth transition between two circle pack graphs of the same structure but different values?
(Of course, during transition, that lets say lasts 10 sec, there is no need to keep relation between circles like in original graph, circles can intersect and pass one over another)
I know there is similar solution for treemaps. However, it can't be applied on circle packing at all. Treemaps even have a special function sticky() that helps in such cases.
EDIT: I am attaching new version of jsfiddle.
Some functionality now started working. Transitions driven with random data are beautiful.
I have two concerns at this moment:
- I don't know how to update tooltips. This is important, user should be able to identify data points via tooltips. On teh other hand, good thing is they don't need to be interpolated during transition, abrupt change is sufficient, but I don't know how to do it.
- I really don't understand the code. Coding was mostly trial/error process. I would appreciate if somebody verifies the code is good, or maybe not good, or it could be different.
EDIT 2: I resolved problems, and attached jsfiddle in the answer if somebody needs the code. Everybody is still welcome to comment on solution.
Most critical part of the code, it seems is:
function updateVis() {
// change pack value
if (updateMethod == 0)
pack.value(function(d) { return d.size; });
if (updateMethod == 1)
pack.value(function(d) { return 100; });
if (updateMethod == 2)
pack.value(function(d) { return 1 + Math.floor(Math.random()*101); });
var data1 = pack.nodes(data);
// titles = ?????
circles.transition()
.duration(2000)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.r; });
return;
};
Thanks in advance for any help or hint.
It looks that I finally resolved all issues. jsfiddle is here.
Here is the whole code (except data definition and button creation) that handles smooth circle pack layout transition:
var diameter = 500,
format = d3.format(",d"),
dataSource = 2;
var pack = d3.layout.pack()
.size([diameter - 4, diameter - 4])
.value(function(d) { return d.size; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter);
var data = getData();
var vis = svg.datum(data).selectAll(".node")
.data(pack.nodes)
.enter()
.append("g");
var titles = vis.append("title")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text(function(d) { return d.name +
(d.children ? "" : ": " + format(d.value)); });
var circles = vis.append("circle")
.attr("stroke", "black")
.style("fill", function(d) { return !d.children ? "tan" : "beige"; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.r; });
updateVis();
function updateVis() {
if (dataSource == 0)
pack.value(function(d) { return d.size; });
if (dataSource == 1)
pack.value(function(d) { return 100; });
if (dataSource == 2)
pack.value(function(d) { return 1 +
Math.floor(Math.random()*301); });
var data1 = pack.nodes(data);
titles.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text(function(d) { return d.name +
(d.children ? "" : ": " + format(d.value)); });
circles.transition()
.duration(5000)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.r; });
};
来源:https://stackoverflow.com/questions/20814073/circle-packing-diagram-transition-between-two-set-of-values