Steewieg
Steewieg

Reputation: 33

dc.js pieChart slice move

I would like to move dc.js pieChart slices outward when they are selected.

I want to do basically this when a pie slice is selected:

var arcOver = d3.svg.arc()
    .outerRadius(outerRadius + 10)
    .innerRadius(innerRadius + 10);

I would like to have that as default behaviour in dc.js.

Any idea which function in dc.js to change to get the desired effect?

Upvotes: 3

Views: 217

Answers (1)

Gordon
Gordon

Reputation: 20120

This is actually pretty annoying to get right, for a couple of reasons:

  1. You have to fight against dc.js's built-in transitions.
  2. None of the internal calculations of radius or arc are exposed.

It's one of those places where it's possible to change the behavior externally, but it might be simpler in practice to just change the library.

I'll share a partial solution, but it's a bit awkward, because it only solves the second problem. Somewhere on SO I did find a way to override both the start and end states of a pie chart transition, just to prove I could do it.

Instead, this just applies the change after all transitions. So it jumps back and forth a bit.

We need to copy some arc generation code out of dc's pieChart:

function arcGen(chart, offset) {
    var maxRadius =  d3.min([chart.width(), chart.height()]) / 2;
    var givenRadius = chart.radius();
    var radius = givenRadius && givenRadius < maxRadius ? givenRadius : maxRadius;
    return d3.svg.arc()
        .outerRadius(radius - chart.externalRadiusPadding() + offset)
        .innerRadius(chart.innerRadius() + offset);
}

The first few lines are a paraphrase of how the pie chart determines the radius. Then we build the arc generator, and optionally offset it from what the pie chart would naturally use.

Now we can apply a "renderlet" (an event handler for the event after all transitions have completed) to change all selected arcs to the larger radius. We also need to restore any unselected arcs to the smaller radius:

chart.on('renderlet', function(chart) {
    var regArc = arcGen(chart, 0), bigArc = arcGen(chart, 40);
    chart.selectAll('g.pie-slice path')
        .attr('d', function(d, i) {
            return d3.select(this.parentNode).classed('selected') ? bigArc(d, i) : regArc(d, i);
        });
});

And here's a demo: https://jsfiddle.net/1z2ckx87/6/

GIF showing the jumpy behavior: enter image description here

If you're committed to this approach, and don't otherwise care about transitions, you could turn them off to get rid of the jumpiness:

chart
  .transitionDuration(0)

Upvotes: 1

Related Questions