-->

How to position labels on dc.js pie chart?

2019-05-05 03:28发布

问题:

I'd like to show labels for tiny slices (chart.minAngleForLabel(0.05)) avoiding text overlap.

I added a renderlet that shifts labels toward outer edge:

  .on('renderlet', function(chart) {
      chart.selectAll('text').attr('transform', function(d, i) {
          var old = this.getAttribute('transform');
          if (d.endAngle-d.startAngle > 0.3) { return old; }
          var xy = old.slice(10,-1).split(',');
          var m = 1.25 + (i%3) * 0.25;
          return 'translate(' + (+xy[0]*m) + ',' + (+xy[1]*m) + ')';
      })
     })

and i'm rather happy with it (the second image is after renderlet):

but it makes annoying transitions -- labels move toward centroid and then jump back. Is there a workaround for this?

回答1:

My solution is a bit excessive, but I wanted to know if it's now possible to replaced transitioned positions, now that we have the pretransition event in dc.js 2.0 beta 11.

In fact, it is. The impractical part is that your code relies on already having the final positions, which we're not going to have if we replace the transitions. Instead, we have to calculate the positions from scratch, which means copying a bunch of code out of the pie chart.

I wasn't able to get your code to work, so I'm just testing this by offsetting all label positions by -25, -25. But it's the same idea, we use the original code to get the centroid, and then modify that position:

// copied from pieChart
function buildArcs(chart) {
    return d3.svg.arc().outerRadius(chart.radius()).innerRadius(chart.innerRadius());
}

function labelPosition(d, arc) {
    var centroid = arc.centroid(d);
    if (isNaN(centroid[0]) || isNaN(centroid[1])) {
        return [0,0];
    } else {
        return centroid;
    }
}
//
        .on('pretransition', function(chart) {
            chart.selectAll('text.pie-slice').transition().duration(chart.transitionDuration())
                .attr('transform', function(d, i) {
                    var arc = buildArcs(chart);
                    var xy = labelPosition(d, arc);
                    return 'translate(' + (+xy[0] - 25) + ',' + (+xy[1] - 25) + ')';
            })
        });

The big idea here is that if you specify a new transition for an element, it will replace the transition that was already active. So we are completely removing the original position and transition, and replacing it with our own. No "jump"!



回答2:

Not really solving your problem, but might look better with a transition on the position?

chart.selectAll('text')
  .transition()
  .delay(800)
  .attr("transform", ...


回答3:

I have a solution for this problem. Try this once , this will works to avoid overlapping of label names in pie charts.

function buildArcs(chart) {
return 
d3.svg.arc().outerRadius(chart.radius()).innerRadius(chart.innerRadius());
}

function labelPosition(d, arc) {
var centroid = arc.centroid(d);
if (isNaN(centroid[0]) || isNaN(centroid[1])) {
    return [0,0];
} else {
    return centroid;
}
}


.on('pretransition', function(chart) {            
chart.selectAll('text.pieslice').transition()
.duration(chart.transitionDuration())
         .attr('transform', function(d, i) {
           var j = 0;
           var arc = buildArcs(chart);
           var xy = labelPosition(d, arc);
           if (xy[1] < 0) {
             j = -(10 * (i + 1));
           }
           else {
             j = 10 * (i + 1);
           }
           return 'translate(' + (+xy[0] - 25) + ',' + (j) + ')';
        })
    });


标签: dc.js