Transitioning between a sunburst and an icicle chart while preserving the chart dimensions by interpolating the difference in perimeter between the inner section and outer section until the difference is near zero.
Chrome currently has a rendering bug once the arcs' radii get really extreme, so this stops at about an 8-pixel difference.
forked from veltman's block: Sunburst to icicle #2
xxxxxxxxxx
<meta charset="utf-8">
<body>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg").append("g"),
width = 960,
height = 500,
r = 150;
// Chrome rendering issue with arc radii above ~17,000
var perimeterDifference = d3.scaleLinear()
.range([r * 2 * Math.PI, 8]);
var radius = d3.scaleSqrt(),
angle = d3.scaleLinear(),
color = d3.scaleOrdinal(d3.schemeCategory20),
partition = d3.partition();
var arc = d3.arc()
.startAngle(d => angle(d.x0))
.endAngle(d => angle(d.x1))
.innerRadius(d => radius(d.y0))
.outerRadius(d => radius(d.y1));
d3.json("https://gist.githubusercontent.com/mbostock/4348373/raw/85f18ac90409caa5529b32156aa6e71cf985263f/flare.json", function(err, root) {
var hierarchy = d3.hierarchy(root).sum(d => d.size),
data = partition(hierarchy).descendants();
svg.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("stroke", "#fff")
.attr("fill", node => color((node.children ? node : node.parent).data.name))
.call(animate);
});
function animate(slices) {
d3.transition()
.delay(1000)
.duration(2000)
.tween("unroll", function(){
return function(t){
var diff = perimeterDifference(t),
innerRadius = r * r * 2 * Math.PI / diff - r,
wedgeAngle = diff / r;
svg.attr("transform", "translate(" + (width / 2) + " " + (height / 2 - innerRadius) + ")")
radius.range([innerRadius, innerRadius + r]);
angle.range([Math.PI + wedgeAngle / 2, Math.PI - wedgeAngle / 2]);
slices.attr("d", arc);
};
})
.on("end", function(){
perimeterDifference.range(perimeterDifference.range().reverse());
slices.call(animate);
});
}
</script>
https://d3js.org/d3.v4.min.js