SVG in Power BI – Part 5 – Creating a dial

Last modified date

Series

This post is the fifth in my series of exploring using SVG within Power BI to create visuals. Here are links to the complete series.

  1. Introduction to SVG
  2. KPI Shapes in Power BI
  3. Filling up with colour using SVG in Power BI
  4. Using Text in SVG
  5. Using SVG Rotate to create a dial in Power BI
  6. SVG Icons in Conditional Formatting
  7. Using a Theme to add SVG Icons
  8. Feb 2023 Update – 5 SVG Stars

In this post I will introduce the possibilities that SVG rotate gives. This post will walk through creating a dial.

This post will be done in 2 stages, first a simple dial and then add colours.

Simple Dial

We will start with a simple dial, made up of an arch with a line to indicate a percentage.

The arch is made using a path which combines 2 arcs to make an arch. The arch is then nested in a group <g> element that applies a fill.

Simple Dial = 
// svg essentials
    var svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 50'>"
    var svg_end = "</svg>"
// arch shape
    var svg_arch = "<path d='
        M 0 50 A 50 50 0 0 1 100 50
        L 80 50 A 30 30 0 0 0 20 50
        ' /> "
// light blue arch
    var svg_blue_arch = "<g fill='#42cbf4'>" & svg_arch & "</g>"
return
    svg_start & svg_blue_arch & svg_end
arch shape

We now need to add a line that will move based on a measure called Score. So I start by calculating the rotation angle and drawing a line that matches the bottom left of the arch and then rotate it centered on the center point of the arch.

The rotation will be 0 to 180 degrees and the measure Score is a percentage so the calculation is [Score] * 180.

The line is drawn from 0,50 to 20,50 and then a transform is applied of a rotate which has 3 parameters, angle to rotate, x and y for the centre of the rotation. So the bottom part of my measure becomes

// light blue arch
    var svg_blue_arch = "<g fill='#42cbf4'>" & svg_arch & "</g>"
// draw line and rotate
    var svg_rotate = [Score] * 180
    var svg_line = "<line x1='0' y1='50' x2='20' y2='50' stroke-width='1' stroke='black'
                    transform='rotate(" & svg_rotate & " 50 50)'/>"
return
    svg_start & svg_blue_arch & svg_line & svg_end
add line

Show the Value

To make it very obvious what value is shown I’m going to add the value of the Score measure. The centre of the arch is 50,50 so I’ll put the middle of the text at 50,40. I used the FORMAT function to apply a percentage, “0%”, format to the score. (See the previous post in this series to look at SVG text)

The bottom part of the measure now becomes

    var svg_line = "<line x1='0' y1='50' x2='20' y2='50' stroke-width='1' stroke='black'
                    transform='rotate(" & svg_rotate & " 50 50)'/>"
// Show Score value
    var svg_score = "<text x='50' y='45' text-anchor='middle'>"&FORMAT([Score],"0%")&"</text>"
return
    svg_start & svg_blue_arch & svg_line & svg_score & svg_end
add text

Adding Colours

For this I researched being able to draw parts of an arch. In order to do that I would need to calculate the end points of each arch, which was possible but involved way more mathematics than I was willing to re-learn. My days of using Cos, Sin and Tan have long gone.

So I the trick I used was to draw the arch upside down out of sight and rotate the arch around into view. Different coloured arches can rotated into view to show different colours.

To draw the arch up the other way I just changed 2 values in svg_arch variable. When drawing an arc in SVG the 5th number after the A specifies which way round the to reach the final point. So the svg_arch variable becomes.

// arch shape
    var svg_arch = "<path d='
        M 0 50 A 50 50 0 0 0 100 50
        L 80 50 A 30 30 0 0 1 20 50
        ' /> "

Then we add a coloured arch rotated for each part of the gauge. In my example I am going to show Green upto 100%, Amber starts at 75% and Red at 50%. So the complete measure code now is

Coloured Dial = 
// svg essentials
    var svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 50'>"
    var svg_end = "</svg>"
// arch shape
    var svg_arch = "<path d='
        M 0 50 A 50 50 0 0 0 100 50
        L 80 50 A 30 30 0 0 1 20 50
        ' /> "
// coloured arches
    var svg_green_arch = "<g fill='#22FF22' transform='rotate(180 50 50)'>" & svg_arch & "</g>"
    var svg_amber_arch = "<g fill='#FFBF00' transform='rotate(135 50 50)'>" & svg_arch & "</g>"
    var svg_red_arch = "<g fill='#ff2222' transform='rotate(90 50 50)'>" & svg_arch & "</g>"
// draw line and rotate
    var svg_rotate = [Score] * 180
    var svg_line = "<line x1='0' y1='50' x2='20' y2='50' stroke-width='1' stroke='black'
                    transform='rotate(" & svg_rotate & " 50 50)'/>"
// Show Score value
    var svg_score = "<text x='50' y='45' text-anchor='middle'>"&FORMAT([Score],"0%")&"</text>"
return
    svg_start & svg_green_arch & svg_amber_arch & svg_red_arch & svg_line & svg_score & svg_end
add colours

Conclusion

This post ended up being longer than I expected so my the series will expand to make use of a table to store the colour values in another post and drawing a clock into another post.

Over 20 year experience at being passionate about training, solving problems and loving a new challenge especially in the Microsoft's Power Platform suite.