Skip to the content

Journal

Simple SVG pie charts

There's plenty of Javascript libraries available for graph generation but if you just need a simple pie chart, an svg and a bit of clever CSS can do the trick.

TLDR: see the demo on Codepen.

To start we need an svg element. For a pie chart with three sections we need three equal circles.

<svg viewBox="0 0 100 100" class="chart">
  <circle r="25" cx="50" cy="50" class="pie pie--value-one"/>
  <circle r="25" cx="50" cy="50" class="pie pie--value-two"/>
  <circle r="25" cx="50" cy="50" class="pie pie--value-one"/>
</svg>

To display the values we can use css variables. If your values come from a database we can render these inline in a style tag in the html.

<style>
  .pie {
    --value-one: 23;
    --value-two: 37;
    --value-three: 40;
  }
</style>

For now we added our values based on a total of 100%. But there's a small caveat with using these values in CSS.

To render the sections of a pie chart we use stroke-dasharray.

.pie--value-one {
  stroke-dasharray: var(--value-one) 158;
}

You might notice the magic 158 number. That's the total length of the gap in the stroke-dasharray. So we need to pass our value in relation to that gap.

We could calculate this in css with the calc() function but stroke-dasharray does not support calc(). So the easiest way to do this is to calculate these values in your backend and render the calculated values for the css variables.

<style>
  .pie {
    --value-one: 36.34; /* Original value 23% (20/100*158) */
    --value-two: 58.46; /* Original value 37% (30/100*158) */
    --value-three: 63.2; /* Original value 40% (50/100*158) */
  }
</style>

To complete our pie chart visualisation we need to offset the sections so they don't overlap. For this we can simply rotate the circles with the sum of the previous values.

.pie {
  transform: rotate(var(--offset)); /* We set the rotate variable in each section */
  transform-origin: center center;
}

.pie--value-one {
  /* nothing to rotate here as it's the first section */
  stroke-dasharray: var(--value-one) 158;
}

.pie--value-two {
  --offset: calc(((var(--value-one) / 158) * 360) * 1deg);
  stroke-dasharray: var(--value-two) 158;
}

.pie--value-three {
  --offset: calc((((var(--value-one) + var(--value-two)) / 158) * 360) * 1deg);
  stroke-dasharray: var(--value-two) 158;
}

You might notice that the first section doesn't start at the top. To fix that we rotate the pie chart 90deg counter clockwise.

.chart {
  transform: rotate(-90deg);
}

For the colors we set some color variables which we can then use for the sections and the chart legend.

:root {
  --value-one-color: green;
  --value-two-color: orange;
  --value-three-color: indigo;
}

.pie--value-one {
  stroke: var(--value-one-color);
}

.pie--value-two {
  --offset: calc(((var(--value-one) / 158) * 360) * 1deg);

  stroke: var(--value-two-color);
  stroke-dasharray: var(--value-two) 158;
}

.pie--value-three {
  --offset: calc((((var(--value-one) + var(--value-two)) / 158) * 360) * 1deg);

  stroke: var(--value-three-color);
  stroke-dasharray: var(--value-three) 158;
}

See the full result on Codepen.


Written on 

How to get started?

Uncertain about your next steps? Let's start a conversation: