The idea in this article is solid, but there are a couple of minor issues with the math, thanks to commenters for pointing things out. I have since worked out a much better implementation and I’ll be posting a new article about all this soon 🙂 A post about area charts using pure SVG is also due soon 🙂

I’m in the process of creating the front-end of an app in React, which includes a product distribution pie chart. I wanted to create the whole thing in SVG – without jQuery or any other monstrous library. In this article, I’ll show you how to construct an SVG pie chart with Javascript that clocks in around 2KB. Beware: math is involved.

A pie chart showing the distribution of four products
A product distribution SVG pie chart in Javascript

If you’re into Javascript- and you’d rather read the code than the whole explanation – feel free to take a look at the pastebin demo I’ve put together.

Drawing An SVG Pie Chart – The Plan

A pie chart consists of one or more circle sectors. A circle sector is the portion of a disk enclosed by two radii and an arc. In other words: it’s a triangle with an arc instead of a straight line for a side.

The algorithm to draw a circle sector with SVG is the following. Start out with a square canvas. Imagine a circle that fills the whole canvas. The diameter is equal to the width of the canvas, its radius is half that value.

  1. Go to the center of the circle
  2. Draw a line straight up to the edge of the circle
  3. Draw an arc to some other point along the perimeter of the circle
  4. Draw a straight line back to the center of the circle
Steps for drawing a circle sector with SVG You can draw a circle sector in four steps using SVG. Go to center, draw a line up, create the arc and go back to the center. 1. Go to center 3. Arc to another point on the perimeter 4. Back to center 2. Line to the perimeter
The steps required to draw a circle segment

Most of this is trivial to calculate. The only tricky part is figuring out the end coordinates of the arc. Let’s say our SVG graphic is 200px wide and 200px high. Our circle fills the available space making the diameter 200px, and the radius is 100px (always half the diameter).

Whatever sector we decide to draw, the middle coordinates will always be 100,100 – the center of the circle. Next, we draw a line straight up to the perimeter. This is always the same as well: 100,0. Our third coordinate is the one we need to calculate (see below) – the end point of the arc. The fourth point is middle of the circle again: 100,100.

The end point of the arc is a factor of two elements: the radius of our circle and the angle that the two radii create. The angle dictates the size of our sector. If we’d like to create a sector representing 25% of the whole the angle will be 20% of 360° which is 72°.

The Math Behind Circle Sectors

I think it’s best to understand the underlying math because it will allow us to make better charts. Let’s draw up a sector with an added triangle and mark some points of interest.

The Mathematics Of A Circle Sector A circle sector with an additional triangle drawn inside 115 45 ° 115 x z y 115,0 115,115 X,Y
A circle sector with additional guides

The sector is a part of a circle with a radius of 115. Therefore, we know that the two straight sides of the sector are both 115 long. I’ve exaggerated the arc here to make sure we can see what’s what. We’re creating a sector that represents 12.5% of the whole which translates to a 45° angle (0.125 × 360°)

We also know some of the coordinates we’ll need. The center of the circle is at 115,115 and the top of the segment is at 115,0. The only thing we’ll need is the unknown set of coordinates marked with a captial X and Y. To get them we’ll need to calculate the length of side z, x and y (marked in blue). Let’s bust out all that trigonometry we learned in high school, three rules in particular:

  • The cosine rule
    b2 = a2 + b2 – 2ac cos(θ)
  • The sine rule simplified for right angle triangles
    sin(θ) = opposite/hypotenuse
  • Pythagoras’ theorem
    a2 + b2 = c2

Based on the cosine rule we can easily calculate the length of side z.

// Calculate side z with the cosine rule
z2 = 1152 + 1152 – 2×115×115 cos(45)
z = 88.0172

// Calculate side x using the sine rule
sin(45) = x/115
x = 81,3173

// Calculate side y using Mr. Pythagoras’ theorem
81,31732 + y2 = 88.01722
y = 33.6827

We now have sides x and y which is great, because we can calculate the final coordinates with their help. The first coordinate of the arc’s end point (X) will be 115 + x because we need to move on the horizontal axis away from the center of the circle by x. The center of the circle is at 115, so we add x to this value to arrive at 196.317.

We need to move down y from the top of our circle which is at 0, so our Y coordinate will be y itself: 33.6827.

Circle Sector Variations

There are four types of sectors that can occur, depending on their angles. Take a look at the diagram below for a visual representation of each.

The Sector Types Four circle sectors with different angles 115 45 ° 115 x z y 115,0 115,115 X,Y 45 ° 315 ° 115 115 x z y 115,0 115,115 X,Y 115 135 ° 225 ° 115 x z y 115,0 115,115 X,Y 115 135 ° 115 x z y 115,0 115,115 X,Y
The four types of sectors

It is important to distinguish between them because calculations differ slightly, and we need to move along the X axis differently for each. Note that there are numerous ways you could arrive at the end coordinates – you could draw different triangles than I have. I found this to be the easiest method since the value of the side y is always the amount we need to move on the axis, no need to add a length to it.

In all these cases we use Pythagoras’ theorem to arrive at y, but the we get to x and z differently, let’s see how:

  • When the angle is acute (less than 90°) we find x from the angle of the sector.
  • When the angle is obtuse (more than 90°) we find x from the complement angle of the sector (180° – angle)
  • When the angle is a reflex angle and smaller than 270° we use the angle - 180° to find x. We use 360° - angle to calculate z.
  • When the angle is a reflex angle and larger than 270° we use the 360° - angle to find x. We use 360° - angle to calculate z.

Surely there must be a way to simplify! Yes, there is! Let’s take all sectors above 180° (bottom two on the image above) and mirror them along the center line. This way the bottom left sector will transform into the top left sector, and the bottom right sector will transform into the top right sector. The Y value will always be the same; we just need to remember that if the original angle was above 180° we need to subtract x from the radius if it was below we need to add it to the radius.

Creating The Segment In SVG

Now that we know our arc coordinates we can finally start to draw our SVG pie chart. We’ll begin by focusing on a single sector. It’s extremely straightforward although SVG notation makes it a bit confusing. I’ll clarify right after the code.

<svg style="width: 230px; height: 230px;">
    <path fill="#61C0BF" d="M115,115 L115,0 A115,115 1 0,1 196.317, 33.6827 z"></path>
</svg>

The steps taken are exactly as I’ve described them above. M means move to, L means create a line, A means create an arc and z closes the path. Here’s a detailed breakdown of how the sector is drawn:

  1. Move to 115,115. This does not draw anything, it simply moves “the pencil” to those coordinates.
  2. Draw a line from your current location up to 115,0
  3. From the current point, draw an arc to 196.317,33.6827
  4. Close the path by drawing a line from the current point back to the starting point

Here’s how this would look in general form:

<svg style="width: <diameter>px; height: <diameter>px;">
    <path fill="#61C0BF" d="M<radius>,<radius> L<radius>,0 A<radius>,<radius> 1 0,1 <X>, <Y> z"></path>
</svg>

If we want to add more than one segment we have two options. Figure out each arc’s start and end point, or just draw all the arcs in the same position (starting from radius,0) and then rotate them. I vouch for the second one – it’s a lot easier. You just need to rotate the arc by the correct amount.

TheRotated SVG pie chart segments Three pie chart segments, each one-eight of a circle
Three rotated sectors for an SVG pie chart

The amount is the sum of arc angles before the current sector. Assume we have three sectors with 10°, 20° and 35° degree angles. The first one does not need to be rotated; it starts at 0°. The second should be rotated by 10° which would make it start from the end of the first sector. The third sector needs to start at the end of the second, so we rotate it by 30° – the sum of the two angles before it. You can execute the rotations using the transform property on the path.

The rotation needs three parameters. The first one is the degree of rotation. The second and third are the coordinates for the origin of the transformation. We want to rotate the sectors around the center point of the circle, which is 115,115

<svg style="width: 230px; height: 230px;">
    <path fill="#61C0BF" d="M115,115 L115,0 A115,115 1 0,1 196.317, 33.6827 z" transform="rotate(0, 115, 115)"></path>
    <path fill="#DA507A" d="M115,115 L115,0 A115,115 1 0,1 196.317, 33.6827 z" transform="rotate(45, 115, 115)"></path>
    <path fill="#BB3D49" d="M115,115 L115,0 A115,115 1 0,1 196.317, 33.6827 z" transform="rotate(90, 115, 115)"></path>
</svg>

Generating An SVG Pie Chart With Javascript

We know everything to create a neat little framework that will draw an SVG pie chart for us. Let’s lay the groundwork by defining a Javascript data object:

var data = {
    size: 230,
    sectors: [
        {
            percentage: 0.45,
            label: 'Thing 1'
        },
        {
            percentage: 0.21,
            label: "Thing Two"
        },
        {
            percentage: 0.11,
            label: "Another Thing"
        },
        {
            percentage: 0.23,
            label: "Pineapple"
        }
    ]
}

Now, let’s create a function that we’ll run our data array through to calculate the points for the sectors. This function translates our math above into Javascript.

function calculateSectors( data ) {
    var sectors = [];
    var colors = [
        "#61C0BF", "#DA507A", "#BB3D49", "#DB4547"
    ];

    var l = data.size / 2
    var a = 0 // Angle
    var aRad = 0 // Angle in Rad
    var z = 0 // Size z
    var x = 0 // Side x
    var y = 0 // Side y
    var X = 0 // SVG X coordinate
    var Y = 0 // SVG Y coordinate
    var R = 0 // Rotation

    data.sectors.map( function(item, key ) {
        a = 360 * item.percentage;
        aCalc = ( a > 180 ) ? 360 - a : a;
        aRad = aCalc * Math.PI / 180;
        z = Math.sqrt( 2*l*l - ( 2*l*l*Math.cos(aRad) ) );
        if( aCalc <= 90 ) {
            x = l*Math.sin(aRad);
        }
        else {
            x = l*Math.sin((180 - aCalc) * Math.PI/180 );
        }
        
        y = Math.sqrt( z*z - x*x );
        Y = y;

        if( a <= 180 ) {
            X = l + x;
            arcSweep = 0;
        }
        else {
            X = l - x;
            arcSweep = 1;
        }

        sectors.push({
            percentage: item.percentage,
            label: item.label,
            color: colors[key],
            arcSweep: arcSweep,
            L: l,
            X: X,
            Y: Y,
            R: R
        });

        R = R + a;
    })


    return sectors
}

The result of this function is an array of objects that represent each sector. The object contains the percentage, label, color, radius, X and Y coordinates and the rotation.

Note that I needed to create the aRad variable which is the angle in radians. Javascript calculates trigonometry functions in radians, so that’s what we need to feed it. You can convert a degree value to radians by multiplying by pi and dividing by 180.

Let’s see how this all works. I created aCalc which is the name I gave to the transformed angle. To get the transformed angle, we deduct it from 360° if it is above 180°.

Depending on the calculated angle we arrive at x slightly differently. Since we have x and z now, we can use Pythagoras’ theorem to calculate y. The length of side y will always be equal to amount we need to travel on the y axis so we have our Y coordinate.

The X coordinate depends on the original angle. If it was below 180° we need to add the length of side x to the radius. If it was above 180° we need to subtract the length of x from the radius, this arriving at our final X coordinate.

We also need to set an arcSweep value which is used in SVG (as the fourth number of the arc command). For angles below 180° we use 0, for angles above we use 1 to sure the arc is drawn in the correct place.

Lastly, we add all the data to an array and calculate the rotation for the next sector. We can now map over the sectors and add them to an SVG element to create our svg pie chart.

sectors = calculateSectors(data);
var newSVG = document.createElementNS( "http://www.w3.org/2000/svg","svg" );
newSVG.setAttributeNS(null, 'style', "width: "+data.size+"px; height: " + data.size+ "px");
document.getElementsByTagName("body")[0].appendChild(newSVG)


sectors.map( function(sector) {

    var newSector = document.createElementNS( "http://www.w3.org/2000/svg","path" );
    newSector.setAttributeNS(null, 'fill', sector.color);
    newSector.setAttributeNS(null, 'd', 'M' + sector.L + ',' + sector.L + ' L' + sector.L + ',0 A' + sector.L + ',' + sector.L + ' 1 0,1 ' + sector.X + ', ' + sector.Y + ' z');
    newSector.setAttributeNS(null, 'transform', 'rotate(' + sector.R + ', '+ sector.L+', '+ sector.L+')');

    newSVG.appendChild(newSector);
})

var midCircle = document.createElementNS( "http://www.w3.org/2000/svg","circle" );
midCircle.setAttributeNS(null, 'cx', data.size * 0.5 );
midCircle.setAttributeNS(null, 'cy', data.size * 0.5);
midCircle.setAttributeNS(null, 'r', data.size * 0.28 );
midCircle.setAttributeNS(null, 'fill', '#42495B' );

newSVG.appendChild(midCircle);

First, I created an SVG element with a style attribute and appended it to the body tag of the document. Then I map over the sectors array and create a new path for each member of the array. The path has a fill attribute and a d attribute which contains the points to draw the sector as discussed. I substitute the appropriate data from the sector’s information. Then I set the rotation and append the path to our SVG element.

Finally, I add a new circle which has its center point at the same location as our large circle but is only 28% the size with a blue fill – thus creating the blue circle that blocks out the middle of our SVG pie chart.

Complete SVG Pie Chart An svg pie chart generated with Javascript
Complete SVG Pie Chart

Final Thoughts

Recently I’ve learned to love SVG because it can be added inline which reduces requests, allows for smooth animations and can be manipulated a lot more easily than anything else. As you can see in this post, all images – except for the very first one – are SVG elements. It scales to any platform including retina screens, and it can be handled responsively just like any other image.

I’ve been creating some other UI elements using SVG as well, and it’s been a blast so far. I’m really enjoying how easy they are to create programmatically once you wrap your head around SVG. If you’d like to learn more can heartily recommend theSVG coordinate systems article by Sara Soueidan.

I’ve added the full code to a jsbin bin, feel free to play around with it!