Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

raphael.js - converting pie graph to donut graph

I'm trying to use a raphael.js example located here:

http://raphaeljs.com/pie.html

but I want to convert the pie graph into a donut graph (have a hole in the middle of all the slices). Currently, each slice is being created with the following code:

function sector(cx, cy, r, startAngle, endAngle, params) {
        //console.log(params.fill);
        var x1 = cx + r * Math.cos(-startAngle * rad),
            x2 = cx + r * Math.cos(-endAngle * rad),
            y1 = cy + r * Math.sin(-startAngle * rad),
            y2 = cy + r * Math.sin(-endAngle * rad);
        return paper.path(["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(params);
    }

How would I modify this so that a hole of a fixed radius was removed from the overall pie? I saw this post here, which helps, but I can't quite tell how or where to apply it to my code above:

How to achieve 'donut holes' with paths in Raphael

like image 767
mheavers Avatar asked Dec 01 '22 07:12

mheavers


1 Answers

The way how one slice of the pie is created is like this:

  1. move to the center of the circle (cx,cy): "M", cx, cy
  2. draw a line until the edge, where the arc will start (x1,y1): "L", x1, y1
  3. draw an arc based on some mathematical calculations: "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2
  4. draw a line back to the middle of the circle: in this case "z" is used; it means move to origin(cx,cy)

and the slice(path) is ready.

In order to create the donut you need to modify how the path is composed. You need to have a path composed of 2 arcs(inside and outside) and 2 lines to complete it.

So first you need to find the starting point for the path, based on the radius of the imaginary empty circle that will be in the middle of the donut (with the radius rin). Lets call the coordinates of this point xx1 and yy1:

xx1 = cx + rin * Math.cos(-startAngle * rad)
yy1 = cy + rin * Math.sin(-startAngle * rad)

You start building the path from this point( "M", xx1, yy1 ); http://jsfiddle.net/EuMQ5/425/

Next step is to draw the line to the edge of the circle( "L", x1, y1 ). From there you will have to draw the outer arc( "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2 ) then one more line to the other edge of the inner arc( "L", xx2, yy2 ). To get the values for xx2 and yy2:

xx2 = cx + rin * Math.cos(-endAngle * rad)
yy2 = cy + rin * Math.sin(-endAngle * rad)  

and the last step is to complete the path by drawing the inner arc( "A", rin, rin, 0, +(endAngle - startAngle > 180), 1, xx1, yy1 ). And now you have a piece of a donut.

The fiddle is here.

**updated fiddle link

like image 79
Chris Ghenea Avatar answered Dec 11 '22 01:12

Chris Ghenea