Skip to content

Instantly share code, notes, and snippets.

@veltman
Last active June 27, 2017 17:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veltman/bd8d6a2f57dd8729da3437492fb9debd to your computer and use it in GitHub Desktop.
Save veltman/bd8d6a2f57dd8729da3437492fb9debd to your computer and use it in GitHub Desktop.
Sunburst to icicle #2

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.

<!DOCTYPE html>
<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment