Skip to main content

Re-scaling QtSvgDialGauge's Tachometer skin

· 4 min read
QtSvgDialGauge Tachometer

I've been experimenting with QtSvgDialGauge in a personal project, and so far, I like it a lot! :)

For those who don't know, QtSvgDialGauge is nice SVG-based dial/gauge widget, which is part of the Qt Embedded Widget demos. You can see it (and several other embedded widgets) in action in the Qt Embedded Widgets Catalog and Qt Patient Care Demo applications. And you can download the source for both applications here.

Now, the Qt Embedded Widget demos includes three SVG-based skins for the QtSvgDialGauge class: Tachometer, Thermometer, and Amperemeter. You can see examples of all three in the following Qt Embedded Widgets Catalog screenshot:

Qt Embedded Widgets Catalog screenshot

For my project, I wanted to use the Tachometer skin (the one on the left). However, if you look closely, you'll notice that the skin's range is labelled from 0 to 120, but I wanted it to scale from 0 to 100, to represent a percent scale. So, I set about modifying the background SVG file (skins/svgdialgauge/Tachometer/background.svg) accordingly.

According to comments embedded into the Tachometer background.svg file, it was originally generated using "Adobe Illustrator 13.0.2, SVG Export Plug-In". But since SVG files are simply specialised XML files, which is itself a text-based format, and I don't have any graphics SVG editing tools, I set about editing the SVG file using a plain text editor (Notepad++ to be specific). Adobe Illustrator (or rather it's SVG Export plug-in?) does not produce commented human-readable SVG files, so the first thing I did was add some blank lines and XML comments to aid readability. Then, I went ahead and replaced all of the digits and tick marks with my own scaled equivalents.

Here's an example rendering of both the original Tachometer (left), and my re-scaled version (right):

Original Tachometer Tachometer scaled to 100

As you can see, I've also re-scaled the inner green, yellow and orange bands - this part proved to be the most difficult by far (more on that later). I also made the minor tick marks slightly thinner than the major tick marks - which, while being quite subtle, adds a nice touch, in my opinion :)

Now the original background.svg file used absolute start / end coordinates for everything - including positioning of the text and the tick marks. This is fine for graphical editors (and is presumably easier for Adobe Illustrator to export), but is extremely tedious to edit manually, so I replaced all of the text and tick mark elements with versions that are rotated around the needle's center point instead - much easier to work with! :)

Now we come back to those inner color bands... it's pretty obvious how to describe the positioning of those bands using a center point, radius, and start / end angles. Unfortunately, SVG does not support this :( Specifically, the SVG path element only supports cubic Bézier, quadratic Bézier, and elliptical arc curves - none of which make use of a center point about which to draw the curves.

So, after plenty of investigation, including a number of failed attempts at using the the standard SVG curved path commands by trial and error, in the end I created a simple (well, maybe not that simple... depends on how you look at it) OpenOffice spreadsheet to convert arcs from center, radius, and start/end angles to SVG elliptical arc curve commands. Note, this spreadsheet does not work for all quadrants and/or ellipse variations (indeed, it only works for perfect circles, for example) but certainly does all that is needed for calculating the QtSvgDialGauge's inner color bands.

So, if you are ever wanting to customise the QtSvgDialGauge's Tachometer background skin using a text editor (as opposed to a graphical SVG editor), then I'd highly recommend you begin with my custom background.svg file instead of the original, since mine would be much easier to work with in most situations. You can find my custom background.svg file and arc spreadsheet both listed below.

Finally, I should mention that my re-scaled Tachometer background spreads the needle's range over a slightly smaller range than the original. So when instantiating QtSvgDialGauge with my custom background.svg file, you should set QtSvgDialGauge's start and end angles to -125 and 125 respectively (the original background.svg ranged from -130 to 133 degrees). For example:

QtSvgDialGauge *gauge = new QtSvgDialGauge;
gauge->setNeedleOrigin(0.486, 0.466);

Enjoy! ;)