Cris Benois February 2016

Please could someone explain how data is handled in this 3D piechart?

I'm trying to grasp how the functions in Donut3D.js -> http://plnkr.co/edit/g5kgAPCHMlFWKjljUc3j?p=preview handle the inserted data:

Above all, where is it set that the data's startAngle is set at 0 degrees? I want to change it to 45º, then to 135º, 225º and 315º (look at the image above).

enter image description here

I've located this function:

        Donut3D.draw = function(id, data, x /*center x*/, y/*center y*/, 
                rx/*radius x*/, ry/*radius y*/, h/*height*/, ir/*inner radius*/){

            var _data = d3.layout.pie().sort(null).value(function(d) {return d.value;})(data);

            var slices = d3.select("#"+id).append("g").attr("transform", "translate(" + x + "," + y + ")")
                .attr("class", "slices");              

            slices.selectAll(".innerSlice").data(_data).enter().append("path").attr("class", "innerSlice")
                .style("fill", function(d) { 
                    return d3.hsl(d.data.color).darker(0.7); })
                .attr("d",function(d){ 
                    return pieInner(d, rx+0.5,ry+0.5, h, ir);})
                .each(function(d){this._current=d;});

            slices.selectAll(".topSlice").data(_data).enter().append("path").attr("class", "topSlice")
                .style("fill", function(d) { 
                    return d.data.color; })
                .style("stroke", function(d) { 
                    return d.data.color; })
                .attr("d",function(d){ 
                    return pieTop(d, rx, ry, ir);})
                .each(function(d){this._current=d;});

            slices.selectAll(".outerSlice").data(_data).enter().append("path").attr("class", "outerSlice")
                .style("fill", function(d) { 
           

Answers


Mehdi El Fadil February 2016

Changing the default start angle

Donut3D users d3's pie layout function here, which has a default startAngle of 0.

If you want to change the start angle, you should modify donut3d.js.

In the first place, you should certainly avoid to use 3d pie/donut charts, if you care about usability and readability of your visualizations - explained here.

Fixing bottom corner layout

The endAngle you are using is not correct, causing the "light blue" slice to overlap the "blue" one. Should be 405 (i.e. 45 + 360) instead of 415.

var _data = d3.layout.pie()
  .startAngle(45*Math.PI/180)
  .endAngle(405*Math.PI/180)

Then, the "pieOuter" angles calculation should be updated to behave correctly. The arc which doesn't work is the one where endAngle > 2 * PI, and the angle computation should be updated for it.

This does the trick (don't ask me why):

// fix right-side outer shape
if (d.endAngle > 2 * Math.PI) {
  startAngle = Math.PI / 120
  endAngle = Math.PI/4
}

demo: http://plnkr.co/edit/wmPnS9XVyQcrNu4WLa0D?p=preview


Mark February 2016

Here's a corrected function which allows rotation.

First, modify function signature to include rotate variable:

Donut3D.draw = function(id, data, x /*center x*/ , y /*center y*/ ,
        rx /*radius x*/ , ry /*radius y*/ , h /*height*/ , ir /*inner radius*/, rotate /* start angle for first slice IN DEGREES */ ) {

In the draw function, modify angles. Instead of screwing with pie angles, I'd do it to the data directly:

_data.forEach(function(d,i){
  d.startAngle += rotate * Math.PI/180; //<-- convert to radians
  d.endAngle += rotate * Math.PI/180;
});

Then you need to correct the pieOuter function to fix the drawing artifacts:

function pieOuter(d, rx, ry, h) {

    var startAngle = d.startAngle,
        endAngle = d.endAngle;

    var sx = rx * Math.cos(startAngle),
      sy = ry * Math.sin(startAngle),
      ex = rx * Math.cos(endAngle),
      ey = ry * Math.sin(endAngle);

    // both the start and end y values are above
    // the middle of the pie, don't bother drawing anything
    if (ey < 0 && sy < 0)
      return "M0,0";

    // the end is above the pie, fix the points
    if (ey < 0){
      ey = 0;
      ex = -rx;
    }
    // the beginning is above the pie, fix the points.
    if (sy < 0){
      sy = 0;
      sx = rx;
    }

    var ret = [];
    ret.push("M", sx, h + sy, "A", rx, ry, "0 0 1", ex, h + ey, "L", ex, ey, "A", rx, ry, "0 0 0", sx, sy, "z");
    return ret.join(" ");

}

Here's the full code

Post Status

Asked in February 2016
Viewed 1,923 times
Voted 5
Answered 2 times

Search




Leave an answer