Drawing Arcs and Pie Slices with SVG

In this article I will demonstrate how to draw an arc, or section of the circumference of a circle, with SVG, and then go on to draw a "pie slice" or circular sector to give it its correct name. Finally I'll draw a number of circular sectors to create a pie chart.

Overview of SVG Arcs

Perhaps surprisingly there is no specific SVG arc shape as with, for example, lines, rectangles and circles. However, we can easily create an arc using a path. This actually gives us more flexibility as we can combine one or more arcs with other path types to create complex shapes such as sectors which I will demonstrate here.

In this article I'll first show how to draw a simple arc, and then create a path consisting of an arc and two lines which together form a sector. Finally I'll draw a number of sectors to form a pie chart.

This project consists of the following files:

  • svgarcandpieslice.html

  • svgarcandpieslice.js

  • app.js

The files can be downloaded as a zip from the Downloads page, or you can clone/download the Github repository if you prefer.

Source Code Links

ZIP File
GitHub

The HTML

The HTML file is very simple, and basically contains an empty SVG element for us to draw in, and the two JavaScript files.

svgarcandpieslice.html

<!doctype html>

<html>

<head>
    <meta charset="utf-8"/>
    <title>SVG Arc and Pie Slice</title>
</head>

</body>

    <div>
        <svg height="512" width="512" id="svg"></svg>
    </div>

    <script src="svgarcandpieslice.js"></script>
    <script src="app.js"></script>

</body>

</html>

Functions to Draw Arcs and Pie Slices

The svgarcandpieslice.js file contains two functions, one to draw a plain arc and the other to draw a pie slice.

svgarcandpieslice.js

"use strict"


function drawArc(settings)
{
    let d = "";

    const firstCircumferenceX = settings.centreX + settings.radius * Math.cos(settings.startAngleRadians);
    const firstCircumferenceY = settings.centreY + settings.radius * Math.sin(settings.startAngleRadians);
    const secondCircumferenceX = settings.centreX + settings.radius * Math.cos(settings.startAngleRadians + settings.sweepAngleRadians);
    const secondCircumferenceY = settings.centreY + settings.radius * Math.sin(settings.startAngleRadians + settings.sweepAngleRadians);

    // move to first point
    d += "M" + firstCircumferenceX + "," + firstCircumferenceY + " ";

    // arc
    // Radius X, Radius Y, X Axis Rotation, Large Arc Flag, Sweep Flag, End X, End Y
    d += "A" + settings.radius + "," + settings.radius + " 0 0,1 " + secondCircumferenceX + "," + secondCircumferenceY;

    const arc = document.createElementNS("http://www.w3.org/2000/svg", "path");

    arc.setAttributeNS(null, "d", d);
    arc.setAttributeNS(null, "fill", settings.fillColor);
    arc.setAttributeNS(null, "fill-opacity", settings.fillOpacity);
    arc.setAttributeNS(null, "style", "stroke:" + settings.strokeColour + ";");

    document.getElementById(settings.id).appendChild(arc);
}


function drawPieSlice(settings)
{
    let d = "";

    const firstCircumferenceX = settings.centreX + settings.radius * Math.cos(settings.startAngleRadians);
    const firstCircumferenceY = settings.centreY + settings.radius * Math.sin(settings.startAngleRadians);
    const secondCircumferenceX = settings.centreX + settings.radius * Math.cos(settings.startAngleRadians + settings.sweepAngleRadians);
    const secondCircumferenceY = settings.centreY + settings.radius * Math.sin(settings.startAngleRadians + settings.sweepAngleRadians);

    // move to centre
    d += "M" + settings.centreX + "," + settings.centreY + " ";
    // line to first edge
    d += "L" + firstCircumferenceX + "," + firstCircumferenceY + " ";
    // arc
    // Radius X, Radius Y, X Axis Rotation, Large Arc Flag, Sweep Flag, End X, End Y

    d += "A" + settings.radius + "," + settings.radius + " 0 0,1 " + secondCircumferenceX + "," + secondCircumferenceY + " ";
    // close path
    d += "Z";

    const arc = document.createElementNS("http://www.w3.org/2000/svg", "path");

    arc.setAttributeNS(null, "d", d);
    arc.setAttributeNS(null, "fill", settings.fillColour);
    arc.setAttributeNS(null, "style", "stroke:" + settings.strokeColour + ";");

    document.getElementById(settings.id).appendChild(arc);
}

drawArc

The settings argument is an object with the following properties:

  • id - the ID of the SVG element to draw in

  • centreX and centreY - the centre of the circle which we are drawing an arc of

  • startAngleRadian - starting at the "3 o'clock" position

  • sweepAngleRadians - the angular size of the arc

  • radius - the radius of the circle which we are drawing an arc of

  • fillColor, fillOpacity and strokeColour - we'll see why fillOpacity is important later

Within the function we need to create a string representation of the path which we can append to the SVG element; for this I have created an empty string called d. Firstly we calculate the x and y coordinates of the start and end points of the arc, and then add an "M" (move) to the path with the first pair of coordinates. We then add an "A" (arc) with the radius and second coordinate pair.

So far this should be straightforward and self-explanatory but there are three more values which need further explanation.

  • X Axis Rotation - the rotation of an ellipse, not relevant here as we are drawing the arc of a circle

  • Large Arc Flag - if set to 1 the longer of the arcs between the two points will be drawn. If 0 (which I have used) the shorter of the two arcs will be drawn.

  • Sweep Flag - if 1 (as here) the angles progress in a positive direction from the first to the second point. If 0 they progress in a negative direction.

(You probably noticed I have used a single value for both the horizontal and vertical radii. You can use different values to draw an arc of an ellipse and I'll do just that in an upcoming article on planetary orbits.)

Finally we create a path const called arc, set the necessary attributes and append it to the SVG element.

drawPieSlice

This function extends on the previous one and uses the same settings except that we do not have a fillOpacity property.

The only other differences are that we first move to the centre of the circle and draw a line to the edge, and then after the arc has been added we close the path with a "Z". The first line, arc and second line therefore enclose the sector.

Trying it Out

So now we have a couple of functions let's try them out.

app.js

"use strict"


window.onload = function()
{
    arc();

    // pieSlice();

    // pieChart();

}


function arc()
{
    drawArc({ id: "svg", centreX: 256, centreY: 256, startAngleRadians: 0, sweepAngleRadians: Math.PI / 2, radius: 192, fillColor: "#0000FF", fillOpacity: 0.0, strokeColour: "#000000" } );
}


function pieSlice()
{
    drawPieSlice({ id: "svg", centreX: 256, centreY: 256, startAngleRadians: 0, sweepAngleRadians: Math.PI / 4, radius: 192, fillColour: "#FF8000", strokeColour: "#000000" } );
}


function pieChart()
{
    const colours = ["red", "green", "blue", "yellow", "orange", "purple"];
    const data = [26, 16, 36, 10, 20, 29];
    const total = data.reduce((a,b) => a + b); // = 137
    const radiansPerUnit = (2 * Math.PI) / total;

    let startAngleRadians = 0;
    let sweepAngleRadians = null;

    for(let i = 0, l = data.length; i < l; i++)
    {
        sweepAngleRadians = data[i] * radiansPerUnit;

        drawPieSlice({ id: "svg", centreX: 256, centreY: 256, startAngleRadians: startAngleRadians, sweepAngleRadians: sweepAngleRadians, radius: 192, fillColour: colours[i], strokeColour: "#000000" } );

        startAngleRadians += sweepAngleRadians;
    }
}

In window.onload we have three function calls which you can comment/uncomnment to try out the three other functions.

The first is arc: if you open svgarcandpieslice.html in your browser you'll see this. (It's very boring. Sorry!)

arc draw with SVG

In the arc function I set fillOpacity to 0.0. If you set it to some other value, say 0.5, you'll get this, which probably isn't what you want.

arc draw with SVG

In pieSlice we call drawPieSlice, so comment out arc(); in window.onload, uncomment pieSlice(); and refresh the page. A not-quite-so-boring orange pie slice or circular sector.

pie slice drawn with SVG

Finally let's run the pieChart function. Firstly I have created a couple of arrays, one for colours and one for data, and then totalled them and calculated the angle in radians which represents each unit of data.

Next we need a couple of angle variables, one for the start angle (as I mentioned earlier 0 is "three o'clock") and one for the sweep angle for the current data value.

Finally we iterate the data. I have used a for loop here as we need the current index for the colour array. Within the loop we calculate the sweep angle for the current data item, call drawPieSlice, and then add sweepAngleRadians to startAngleRadians so the next pie slice starts where the previous one finished.

This is the end result.

pie chart drawn with SVG

Of course it isn't a full production-ready pie chart: there are no labels, colour keys or other bells 'n' whistles, but the purpose is just to demonstrate drawing pie slices in SVG using JavaScript.