In one of my recent projects I had to create a simple pie chart kind of structure in SVG (Scalable Vector Graphics) based on values given in an array. So if the array has five values in it then the pie chart will have five slices, each slice representing a value. Here is how it looks,
Calculating angles swiped by each slice
Alright, so we need the angles that are swiped or covered by a each of the pie slices. The values are supplied by an array
var pieData = [113,100,50,28,27];
Each value will cover some angle in the circular space. Let us find the angle covered by the first value in the array i.e 113. One thing to note is that the 5 values (the array) together, will cover the circular space which is a complete 360 degrees. So 113 + 100 + 50 + 28 + 27 = 318 is making a 360 degrees or a circle. So 113 will cover (113 * 360 degrees)/318 which is approximately 128 degrees. So, similarly by looping the array you can calculate the angles swiped by each value and store them in a new array for later use.
The critical part is to generate a circular arc (a pie slice in this case) in SVG. For that I am using the SVG path element. SVG path has an option for generating elliptical arcs and that is what we need. I will not go into the details of the SVG shape elements and paths. You can have a look at them here. The important part is to determine the data string that needs to be defined for the SVG path.
var dataString = "M200,200 L380,200 A180,180 0 0,1 89,341 z"; var arc = paper.path(dataString);
Here dataString is holding a string value which might baffle you. Quickly going over it lets see what each term means.
Mx,y – Move to: move your pencil or drawing point to x,y position in the co-ordinate space. Remember no line is drawn.
Lx,y – Line to : draw a straight line till x,y. So your line will be drawn from the co-ordinates you specified with Move to.
Arx,ry x-axis-rotation large-arch-flag,sweepflag x,y – Arc to: Draws an elliptical arch from the current point to the point x,y. rx and ry are the elliptical radius in x and y direction. The x-rotation determines how much the arch is to be rotated around the x-axis. It only seems to have an effect when rx and ry have different values. The large-arch-flag doesn’t seem to be used (can be either 0 or 1). Neither value (0 or 1) changes the arch. The sweep-flag determines the direction to draw the arch in, it can be either 0 or 1. I have used 1 which means clockwise direction. 0 is for anticlockwise rotation.
z- Closes the path. A line is drawn from the last point to the first.
I have specified the values in the data string. My drawing starts from x=200 and y=200, so this will be the center point. From there I am drawing a line to a point in the circumference of the circle (138,369) which we will calculate. 180,180 specified with A means that my arc will be a part of a circular ellipse of x-radius = 180 and y-radius=180. 89,341 is the point till which the arc will be drawn. Again we will calculate it. And then z closes the path. See the figure for an understanding.
Start Angle, End Angle, Finding points on the circumference of the circle
Now, how to calculate the coordinates on the circumference, the points that the arc will be drawn with (380,200 to 89,341). A little bit of trigonometry will help us here. Since I am using clockwise direction to draw the arcs so I am considering all the angles from the x-axis. Lets look at the equations below,
x1 = 200 + 180*Math.cos(Math.PI*startAngle/180); //for eg. 380 y1 = 200 + 180*Math.sin(Math.PI*startAngle/180); //for eg. 200 x2 = 200 + 180*Math.cos(Math.PI*endAngle/180); //for eg. 89 y2 = 200 + 180*Math.sin(Math.PI*endAngle/180); //for eg. 341
One thing to note is that cos and sin takes angles in radians. Till now we have calculated the angles in degrees. So wee need to convert this to radians. You can do it this way,
angle in radians = Math.PI*(your angle in degrees)/180
To calculate points of the circumaference I have used trigonometric equations for a point on a circle which is pretty straight,
x = rx + radius * cos(theta) and y = ry + radius * sin(theta)
where rx is the x-coordinate of center and ry is the y-coordinate of the center of the circle. As you can see the x1,y1 and x2,y2 points follow this pattern. To calculate startAngle and endAngle I have used these equations,
startAngle = 0; endAngle = startAngle + angleSwipedByASlice;
To start with my startAngle is zero since I am starting to draw from the x-axis. And then calculate the endAngle by adding the start angle and the angle swiped by that arc or slice. These equations are used inside a loop so I am adding the previous angle to get new value of angle. The figure will make things clear.
Have a look at the full code. This will make things clear.
You can make this simple chart into something much more interactive….
1) You can add interactivity to the chart, say on clicking a pie slice it shows some relevant data.
2) You can use the code to generate some cool dashboard kind of application
3) You can use animations as well to move out the slice clicked on.
In fact Raphael has methods for all these. You can try it out.
Hope it helps…