Examples: jQuery plugin

directly calling the plugin

Some selected previews of the examples (shown in detail further down in this document), to give you a first idea of the plugin's customizability:

25 % 30 % 40 % 45 % 55 % 65 % 100 %

1:55

80
%
20
sec.

General usage

The following examples each show a JavaScript line of the kind:

$(selector).progressPie(options)

or alternatively:

$(selector).setupProgressPie(options).progressPie()
  • The first way is usually used for a one-time drawing without dynamic updates. The second kind (setupProgressPie) stores the options, enabling you to repeatedly call the parameterless progressPie() method to redraw / update the chart with a new value but otherwise unchanged settings.

  • selector is a jQuery selector string, depending on the actual HTML document. In these cases it's a selector specific to this actual HTML page, selecting the span elements corresponding to the respective example.

  • The actually interesting bit is thus the options portion of each example.

  • Please note, that these lines have to be executed after the DOM tree has been created by the browser. Typically, using jQuery, this is done in the following way:

    <head>
        …
        <script type="text/javascript">
            $(function() {
                $(selector).progressPie(options);
            });
        </script>
    </head>
    

Default mode

$(".pp.default").progressPie();

applied to elements like:

<span class="pp default">100</span> %

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Predefined modes

Color mode (dynamic color)

$(".pp.dyncolor").progressPie({mode:$.fn.progressPie.Mode.COLOR});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Green mode (static color)

$(".pp.green").progressPie({mode:$.fn.progressPie.Mode.GREEN});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Red mode (static color)

$(".pp.red").progressPie({mode:$.fn.progressPie.Mode.RED});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Ring instead of full pie

Add the ringWidth option in order to draw a ring segment instead of a pie.
It's recommended to combine this with either a very small strokeWidth (defining the stroke of the full surrounding circle)…

$(".pr.dyncolor").progressPie({mode:$.fn.progressPie.Mode.COLOR, strokeWidth: 1, ringWidth: 3});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

… or with a strokeWidth identical to the ringWidth but setting a different, constant color for the outer circle's stroke via the strokeColor option:

$(".pr.onsilver").progressPie({mode:$.fn.progressPie.Mode.COLOR, ringWidth: 4, strokeWidth: 4, strokeColor: '#ddd'});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

User-defined colors

User-defined static color (via color option)

$(".pp.navy").progressPie({color:"navy"});
$(".pp.yellow").progressPie({color:"#eee000"});
$(".pp.rgb").progressPie({color:"rgb(0,150,100)"});
$(".pp.rgba").progressPie({color:"rgba(0,150,100,0.6)"});

The following pies are each assigned one of the four classes ‘navy’, ‘yellow’, ‘rgb’, or ‘rgba’. The option set is always the same (color), the difference (beside from the color itself) is the color notation syntax. The ‘rgba’ example demonstrates an alpha channel, setting a transparancy level for the pie graph.

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Notice that the foreground pie overlaps the background circle. In this case, using an alpha channel, i.e. semi-transparent strokes, this causes the opacity of the doubly covered area to increase, the background circle remains visible behind the foreground. If you don't want that, set the overlap option (see below) to false:

$(".pp.rgbanooverlap").progressPie({color:"rgba(0,150,100,0.6)", overlap: false});
$(".pr.rgbanooverlap").progressPie({color:"rgba(0,150,100,0.6)", overlap: false, ringWidth: 3});

25 % 50 % 65 % 80 % 99 % 100 %

Local Color Function (via color option)

Example 1: Inline function

$(".pp.myfunc").progressPie({color:function(percent) {
    return percent >= 50 ? "#3f3" : "#f33";
}});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Example 2: Function reference

function blueGt25(percent) {
    var blue = percent < 25 ? 0 : (percent-25)*3; //range from 0 to 3*75 = 225 ( = max brightness for value of 100%)
    return "rgb(0,0," + blue + ")";
}
…
$(function(){
    $(".pp.myblue").progressPie({color:blueGt25});
});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Example 3: A function (referenced) re-using/adapting the internal function colorByPercent

function colorGt50(percent) {
    var p = percent <= 50 ? 0 : 2 * (percent - 50);
    return $.fn.progressPie.colorByPercent(p);
}
…
$(function(){
    $(".pp.gt50").progressPie({color:colorGt50});
});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

CSS formatting

Starting with V2.0.0, the ProgressPie plug-in adds class attributes to the SVG components, enabling you to define some global CSS rules to globally format some of the pie diagram's design features instead of programmatically configuring everything via plug-in options alone: The default classnames are:

  • progresspie-background for the background circle and

  • progresspie-foreground for the pie or ring drawn on top of the latter.

  • If you are drawing a double pie/ring chart, both foreground pies or rings (outer and inner) bear the progresspie-foreground class, but they get (both) fitted with a second class:

    • progresspie-outer for the outer and

    • progresspie-inner for the inner pie or ring.

    So a CSS rule like .progresspie-foreground{...} will apply to all foregrounds of single pies as well as for inner and outer displays of double pies, while a selector like .progresspie-foreground.progresspie-inner explicitly selects all inner parts of double pies.

  • Should you even add further values (triple pies or more), i.e. you have an outer ring containing an inner ring, which itself contains a further inner ring, which might again contain yet another inner ring and so on, the inner classes get postfixed with numbers:

    • The outer ring still gets marked class progresspie-outer,

    • the second ring (inner) still gets marked by class progresspie-inner,

    • the third ring (inner.inner) gets marked by class progresspie-inner2,

    • the fourth ring (inner.inner.inner) gets marked by class progresspie-inner3.

    • and so on.

Overriding CSS in „normal“ mode

Assume a regular plug-in call (programatically defining the colors, in this case using the predefined COLOR mode):

$(".pr.css1").progressPie({mode:$.fn.progressPie.Mode.COLOR, ringWidth: 4, strokeWidth: 4});

This example alone doesn't make any sense, since a ring segment is drawn on top of a full circle with the same width and the same color, i.e. the ring segment will be effectively invisible.
But we can use CSS to override style properties of the chart. Here, we firstly set a stroke-dasharray for a dashed background circle and secondly we override the background circle's color (like we could have done locally programatically via the strokeColor option, see above):

.pr.css1 .progresspie-background {
    stroke-dasharray: 1px 3px;
    stroke: #bbb !important;
}

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Keep in mind that local styles (i.e. style attributes inside the SVG markup generated by the plug-in) have priority over global styles in a CSS ruleset. Since the plug-in locally sets a color via stroke property in a style attribute, we need to add the !important directive in order to override that local stroke style.

Special CSS mode

If you really want to style the color (and alignment) of your diagrams (statically) via CSS rules, you can tell the progressPie plug-in to completely omit color and vertical-align definitions in the local styles (thus removing the need for !important directives). This is done by setting the mode option to the fourth predefined color mode: $.fn.progressPie.Mode.CSS.
Be aware, however, that in CSS mode…

  • you must define all colors yourself, i.e. you have to set the stroke and fill properties for the background and the stroke property for the foreground. (The foreground's fill property is still set locally to none by the ProgressPie plug-in even in CSS mode, since filling of a ring segment doesn't make sense),

  • and you should define the vertical-align style of the SVG node, at least if the target element is not empty, but the SVG is appended or prepended to text content: The first of the following examples omits the vertical-align rule with the result, as you can see, that the pies and the percent labels are not nicely aligned. (In any other mode, this vertical alignment is set via the plug-in's verticalAlign option, defaulting to bottom, but in CSS mode, that option is ignored.

$(".pp.css1").progressPie({mode:$.fn.progressPie.Mode.CSS});
.pp.css1 .progresspie-background {
    stroke-dasharray: 3px 1px;
    stroke: #bbb;
    fill: none;
}
.pp.css1 .progresspie-foreground {
    stroke: rgba(0, 100, 150, 0.5);
}

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

$(".pr.css2").progressPie({mode:$.fn.progressPie.Mode.CSS, ringWidth: 3, strokeWidth: 3});
.pr.css2 svg {
    vertical-align: bottom;
}
.pr.css2 .progresspie-background {
    stroke: rgb(200, 200, 200);
    fill: rgba(200, 200, 200, 0.2);
}
.pr.css2 .progresspie-foreground {
    stroke: rgb(0, 200, 0);
}

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

For an example if CSS formatting double pie/ring charts see the corresponding section.

Renaming the CSS classes

The default classes progresspie-foreground etc. have intentionally been prefixed with "progresspie-" in order to avoid name conflicts with other CSS code.

You may globally change these defaults by overwriting the properties jQuery.fn.progressPie.defaults.cssClassBackgroundCircle, jQuery.fn.progressPie.defaults.cssClassForegroundPie, jQuery.fn.progressPie.defaults.cssClassOuter and jQuery.fn.progressPie.defaults.cssClassInner.

Or you may locally set other classnames by adding the options cssClassBackgroundCircle, cssClassForegroundPie, cssClassOuter or cssClassInner to the options argument of your plug-in call.
The following example will demonstrate this (omitting the cssClassOuter and cssClassInner options, since they are only used with double pies):

$(".pp.css2").progressPie({
    mode: $.fn.progressPie.Mode.CSS, 
    strokeWidth: 0,
    cssClassBackgroundCircle: "piebg",
    cssClassForegroundPie: "piefg"
});
.pp.css2 svg {
    vertical-align: middle;
}
.pp.css2 .piebg {
    stroke-dasharray: 1,4;
    fill: silver;
}
.pp.css2 .piefg {
    stroke: navy
}

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Advanced options

Vertical alignment

The following example shows alternating pies with and without the option verticalAlign:"middle" (default is "bottom") in a line with a line-height greater than the font-size (so that alignment makes a difference).

$(".pp.vc").progressPie({verticalAlign:"middle"});

applied to elements like:

<span class="pp default">0</span>
<span class="pp vc">5</span>
…

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

append instead of prepend

By default, the pie gets prepended to the selected element's content. You may opt to appending it behind the content instead:

$(".pp.append").progressPie({prepend: false, separator: "%:&nbsp;"});

applied to elements like:

<span class="pp append">5</span>

0 5 25 42 50 65 80 99 100

Adding a title

Just like to HTML elements you may add a title string to a chart. Most desktop browsers will display the title as popup when the mouse cursor rest on the image for some time:

$(".pp.withTitle").progressPie({globalTitle: "Demo pie chart"});

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

The globalTitle option adds a title to the whole (rectangular) image. Alternatively, you might use the title option which adds a title to the chart itself. In this case, in a desktop browser, the popup title will only show if the mouse cursor rests on the chart's foreground, not on the transparent background regions.
You may also combine both options, in which case the title shows on the chart's foreground, while the globalTitle shows on the rest of the image (i.e. the background).

The title option is mainly intended for use on diagrams with more than one value, so each value can get its individual title. This will be demonstrated further below in examples with three rings.

Value attribute / value data, manual size, overridden background circle's stroke (with/color) and filled background circle:

By default, the percent value to display has to be the (only) content of the selected element and the SVG graphic gets prepended (or optionally appended) to that value (see above). But you may also provide the percent value invisibly in an attribute of the HTML element, usually (conforming to HTML) in a data-* attribute. The element's content may be left empty. (If not empty, the graphic still gets prepended or appended to that content.)

The following examples demonstrate a data-attribute on an empty span element, using the valueData option. Also, they demonstrate different uses of the strokeWidth and strokeColor options which configure the look of the surrounding circle.

And a third aspect also demonstrated is the size option: If you don't set a size option, the pies will be auto-sized. If the DOM node the SVG gets prepended or appended to also contains text, the pie is auto-sized to the line-height. If the pie is be be inserted into a text-less node, this does not work and the plug-in simply chooses a default width. By setting the size option, you may explicitly set a size (diameter) in pixels and thus turn off auto-sizing.

$(".pp.attr:not(.silverborder):not(.navyborder):not(.noborder):not(.ring):not(.filledCircle)").progressPie({
    mode:$.fn.progressPie.Mode.COLOR, valueData:"val", size:30, strokeWidth: 5});

applied to elements like:

<span class="pp attr" data-val="0"></span>

$(".pp.attr.silverborder").progressPie({mode:$.fn.progressPie.Mode.COLOR, valueData:"val", size:30, strokeWidth: 5, strokeColor: "silver"});

strokeWidth may also be zero:

$(".pp.attr.noborder").progressPie({mode:$.fn.progressPie.Mode.COLOR, valueData:"val", size:50, strokeWidth: 0});

If you set the strokeWidth to the radius, i.e. half the diameter, defined by size, the whole background circle would effectively be filled by the background circle's strokeColor. This has once been recommended, but by now there are better ways for filling the background circle:

  • Firstly (since V2.0.0), you may use external CSS to define a fill color, see section on CSS formatting!

  • Secondly (since V2.1.0), you may specify the option backgroundColor. Just like the color option this may alternatively hold a string describing a color or a function mapping a percent value to a color string.
    The following example demonstrates a color constant for the background filling:

$(".pp.attr.filledCircle").progressPie({
    mode:$.fn.progressPie.Mode.COLOR, 
    valueData:"val", 
    size:50, 
    strokeWidth: 0,
    backgroundColor: "#ddd"
});

strokeWidth 1 combined with a ringWidth and use of valueAttr instead of valueData and demonstration of a backgroundColor function:

$(".pp.attr.ring").progressPie({
    mode:$.fn.progressPie.Mode.COLOR, 
    valueAttr:"data-val", 
    size:30, 
    strokeWidth: 1, 
    ringWidth: 5,
    backgroundColor: function(percent) {
        return $.fn.progressPie.colorByPercent(percent, 0.1);
    }
});

The backgroundColor function in the example above uses the same color function as is used for the foreground color in COLOR mode, only adding an optional second parameter which specifies an alpha channel, in this case set to 10% opacity (90% transparency).

Take value from form input element

Consider you're designing an HTML form for a user to fill, you might want to add a pie or ring chart visualizing the value of an input (like a text input or a select box). In that case, simply use the valueInput option:

$("#inputSelect span").setupProgressPie({
	valueInput: $("#inputSelect select"),
	animate: true
}).progressPie();

applied to

<div id="inputSelect">
    <select>
        <option value="0">—</option>
        <option value="20">20 %</option>
        <option value="40">40 %</option>
        <option value="60">60 %</option>
        <option value="80">80 %</option>
        <option value="100">100 %</option>
    </select>
    <span></span>
</div>

If the input is a simple text input, you might want to add the optionsByRawValue option in order to define a function showing an error icon (see separate content plug-in examples page) if an invalid value has been entered which cannot be visualized as percent value:

$("#inputText span").setupProgressPie({
    valueInput: "#inputText input",
    optionsByRawValue: raw => {
        let i = parseInt(raw);
        return !isNaN(i) && i >= 0 && i <= 100 ? null : {
            contentPlugin: "cross",
            globalTitle: "Illegal input, enter number in [0..100]!"
        };
    }
}).progressPie();
<div id="inputText">
    <input type="text" value="50" size="3">
    <span></span>
</div>

The default event on which a chart update is triggered is the change event. On a text input, change is fired only after defocussing the input element. You may change that by specifying all events which should trigger an update in the valueInputEvents option.

The next example demonstrates this valueInputEvents option by using a jQuery-UI-Spinner element and adding support for the spinstop event (besides the default change event) which is triggered when the user clicks on one of the spin buttons for increasing or decreasing the value. (Unlike the 'spin' event, the 'spinstop' event only triggers after the spin has completed, i.e. when the value has been increased or decreased)

$("#inputSpinner span").setupProgressPie({
    valueInput: $("#inputSpinner input").spinner({
        min: 0,
        max: 100
    }),
    valueInputEvents: "spinstop change",
    verticalAlign: "middle",
    size: 25
}).progressPie();
<div id="inputSpinner">
    <input type="text" value="50" size="3">
    <span></span>
</div>

Notes:

  • The valueInput option can only be used in setupProgressPie()! If you call the progressPie({…}) function directly with an options object (used only once and not stored for updates), this option will be ignored!

  • The setupProgressPie() function, in this case, not only stores a configuration for the pie chart, but also registers an event handler on the specified input element (for the events specified by valueInputEvents). If you should change the setup later (by calling setupProgressPie() again), this event handler will not be deregistered again automatically!

Value Selector

Besides valueAttr, valueData and valueInput there's a fourth option for defining where to look up the raw value to be displayed: valueSelector. This is covered later on in this document.

Avoid overlapping outer stroke

If you set a different stroke color for the outer circle (see example pp.attr.silverborder above) or choose a semi-transparent foreground color, you'll notice that the foreground (pie or ring) has the same radius as the background circle and thus overlaps it. You may optionally turn off that overlapping, so that the radius of the pie or ring is the total radius of the graphic minus the outer circle's strokeWidth. To do so, set the overlap option to false (it defaults to true).

$(".pp.attr.navyborder").progressPie({
    mode:$.fn.progressPie.Mode.COLOR, 
    valueData:"val", 
    size:30, 
    strokeWidth: 2,
    strokeColor: "navy",
    overlap: false
});

See above for another example (using user-defined color with alpha channel)

In ring mode: Alignment of ring with background circle

In the previous examples showing a ring on a background circle, we've either set ringWidth to the same value as strokeWidth (in which case the ring's color has to differ from the background circle's!) or the ringWidth has been larger than the background circle's strokeWidth and both strokes were aligned with their outer sides.

You may use the ringAlign option to change that alignment. This is only applicable, if background circle and foreground ring are both visible (ringWidth > 0 && strokeWidth > 0).

The meaning of the ringAlign option depends on whether the overlap option (see above) is true or false. By default, overlap is true. In this case, you can choose between three alignments (which only make a difference if the ringWidth is either smaller or larger than the strokeWidth): The default option is OUTER alignment (which has already been used in previous examples), but alternatively you may also CENTER the smaller of the two strokes within the wider one or align both strokes on their INNER sides.

If overlap is set to false (see above), the ringAlign option changes its meaning a bit: With default alignment (OUTER), the ring's OUTER side is aligned with the background circle, but since both are not overlapping, the ring's outer side is aligned with the background circle's inner edge. Effectively this means the ring is drawn inside of the background circle. With the alternative INNER alignment, the ring's inner side is aligned with the outer side of the background circle. To achieve that, the background circle is shrunk to fit inside the ring, which is effectively drawn around the background circle on its outside. (A CENTER alignment is not defined with overlap turned off.)

All combinations of the overlap option and the ringAlign option are demonstrated in the table below. For each combination of these two options, three sets of examples are shown, one with ringWidth < strokeWidth, one with ringWidth === strokeWidth and one with ringWidth > strokeWidth.

The following code sets up all these example combinations by iterated use of the setupProgressPie() function: The first call sets up basic properties for all examples, the following setups add more options to the specific examples. (Since overlap defaults to true we only explicitly set the option to false in the respective examples, and similarly, since the ringAlign option defaults to $.fn.progressPie.RingAlign.OUTER, we only explicitly set that option in the examples with other alignment values.)

$(".pr.align").setupProgressPie({
    mode: $.fn.progressPie.Mode.COLOR,
    valueData: "val",
    size: 40,
    strokeColor: "#ddd",
    scale: 2
});
$(".pr.align.thinner").setupProgressPie({
    ringWidth: 2,
    strokeWidth: 6
});
$(".pr.align.thicker").setupProgressPie({
    ringWidth: 6,
    strokeWidth: 2
});
$(".pr.align.same").setupProgressPie({
    ringWidth: 3,
    strokeWidth: 3
});
$(".pr.align.center").setupProgressPie({
    ringAlign: $.fn.progressPie.RingAlign.CENTER
});
$(".pr.align.inner").setupProgressPie({
    ringAlign: $.fn.progressPie.RingAlign.INNER
});
$(".pr.align.nooverlap").setupProgressPie({
    overlap: false
});
$(".pr.align").progressPie();

(Hover your mouse cursor above an image in the table to see the assigned classes.)

ringAlign overlap: true overlap: false
…OUTER
(default)

…CENTER

not a valid
combination

…INNER

Dashed background circle

Strokes in an SVG graphic may be dotted or dashed. The CSS section already demonstrated the use of the stroke-dasharray CSS property. That way you may define simple or complex dash patterns, but you can only define the length of dashes and gaps in pixels. If you want the dashes to be placed at certain points of the circle (e.g. draw a clock face consisting of 12 short dashes placed), you would need to know the exact length of the circle stroke in pixels in order to calculate the correct dasharray!

This is why the ProgressPie plug-in now also offers an option to calculate a dasharray dynamically based on the calculated circle size:

The simplest way is to just specify into how many dashes the chart's background circle should be split:

$(".pp.regulardashes").progressPie({
    valueData:"val", 
    size:30, 
    strokeWidth: 2,
    strokeDashes: 6
});

In this case, the dashes and the gaps between them are equally long. You may change this by additionally setting a stroke length in pixels or in percent (of the stroke's length / circumference). Only percentual settings are really independent of the pie chart's size, since they define the length in relation to the circumference. Let's demonstrate this by drawing pies of different sizes:

$(".pp.percentdashes").progressPie({
    strokeWidth: 2,
    strokeDashes: {
        count: 8,
        length: '10%'
    }
});

0 5 25 33 45 50 70 80 100

To specify the length in percent, you have to set the strokeDashes.length option to a string literal containing a number followed by the percent sign (see above). A single number literal would be interpreted as an abloute length in pixels! Absolute length should only be used with manually sized pies, and you have to ensure that strokeDashes.length * strokeDashes.count is less than the circumference (circle stroke's length in pixels), since the circle stroke can not be divided into parts that are (in sum) greater then the whole circle.

Also note that by default the dashes start the 12 o'clock (or 0 percent) position. You may set the strokeDashes.centered option to true (it defaults to false) in order to center the first stroke around the 12 o'clock position:

$(".pp.centereddashes").progressPie({
    valueData:"val", 
    size:30, 
    strokeWidth: 2,
    strokeDashes: {
        count: 8,
        length: '10%',
        centered: true
    }
});

$(".pp.clockface").progressPie({
    mode: $.fn.progressPie.Mode.COLOR,
    strokeColor: 'silver',
    valueData: "val",
    size: 30,
    strokeWidth: 4,
    strokeDashes: {
        count: 12,
        length: 2,
        centered: true
    }
});

You may set the strokeDashes.inverted option to true in order to invert the pattern, i.e. the options count and length then refer to the transparent gaps, devided by (auto-adjusted) visible dashes between them:

$(".pp.clockfaceInverted").progressPie({
    mode: $.fn.progressPie.Mode.COLOR,
    strokeColor: 'silver',
    valueData: "val",
    size: 30,
    strokeWidth: 4,
    strokeDashes: {
        count: 12,
        length: 2,
        centered: true,
        inverted: true
    }
});

Resizing relatively: sizeFactor vs. scale

Like said above, setting the size options disables auto-sizing and sets a new absolute size. But you may also adjust auto-sizing by specifying the sizeFactor option: The calculated size (either auto-size or value of the size option) is multiplied with this factor to get the final size for the graphic.

The following example sets the size to 50% larger than the default size, and to emphasize the effect of relative sizing (in this case relative to font-size), each number is styled with a different font size:

$(".pp.sizefactor").progressPie({sizeFactor:1.5, verticalAlign:"middle"});

0 5 25 42 50 65 80 99 100

The sizeFactor option is only applied to the default size (auto-size or size) option to calculate the diameter of the pie to draw. It has no effect on other sizes like the strokeWidth or ringWith options. So in the example above, the pies get larger while the strokeWidth of the circle stays the same as it were without the sizeFactor option.

There is a second option pretty similar, but which differs in this effect: The scale option defines a factor by which to resize the otherwise already rendered SVG graphic, thus resizing every aspect of the graphic including the strokeWidth. So if, in the example above, we replace sizeFactor by scale, not only the diameter of the pies increases by 50%, but also the with of the outer circle does:

$(".pp.scale").progressPie({scale:1.5, verticalAlign:"middle"});

0 5 25 42 50 65 80 99 100

In this example of a simple pie chart, the difference between these two options is “marginal”, in more complex eamples the differences may get extremer.

If you should use “double pies” (demonstrated below), please note: Both options are “global” for outer and inner pie and may only be set in the main options object, not inside the inner option. A sizeFactor is individually applied to both graphics, outer and inner pie or ring, the gap between an outer ring and an inner ring or pie will grow when increasing the sizeFactor, while scaling with the scale option will scale outer and inner ring/pie as well the gap between them proportionally, i.e. simply scale the whole graphic.

Value Selector

If the value should still be visible, but is not the only content of the selected element, but the content of some sub-element, you may provide a jQuery selector specifying the sub-element holding the value:

$(".pp.subelem").progressPie({mode:$.fn.progressPie.Mode.COLOR, valueSelector:".valueSub"});

applied to elements like:

<span class="pp subelem">(<span class="valueSub">0</span> %)</span>

(0 %) (5 %) (25 %) (42 %) (50 %) (65 %) (80 %) (99 %) (100 %)

Note: In the first examples, the “%” label was simply placed outside (behind) the span element holding the value and (later) the SVG. But in some cases (e.g. for CSS styling reasons) you might prefer to bundle static text labels and the value inside the same element and simply mark the value by wrapping it into a sub-element like shown here.
The following example shows a special use-case for the valueSelector:

Value Selector and label displayed inside a ring with rounded ends

The following example demonstrates an application of an inner element holding the actual percent value inside the selected element. The main reason for this construct lies in the goal to display the element's content inside the ring.

Also this example demonstrates the ringEndsRounded option.

You have two possibilities to show content inside a ring graph. This example demonstrates the first one: Use the progressPie plug-in to simply render a ring graph without content as SVG image and then place some HTML container with the content on top of the image via CSS rules like those shown below.
An alternative is to use a content plug-in to render the ring content as part of the generated SVG image. See separate content plug-in examples page for a demonstration.

Advantages of the first alternative (HTML content on top of SVG) are easier styling of the content and that even older browsers not capable of rendering SVG images will still show the content, only the ring graph around the value would be missing.

Call of the plugin (the sequence of setupProgressPie() and progressPie() simplifies updates, see below):

$(".pr.around.percent").setupProgressPie({
    size: 70,
    ringWidth: 7,
    strokeWidth: 0,
    ringEndsRounded: true,
    valueSelector: "span.value",
    color: "navy"
}).progressPie();

and CSS:

.pr.around {
    position: relative;
    display: inline-block;
    margin: 1em;
}
.pr.around span {
    color: navy;
}
.pr.around span.outer {
    position: absolute;
    left: 0;
    top: 0;
    width: 70px;
    text-align: center;
    font-size: 10px;
    padding: 15px 0;
}
.pr.around span.value {
    font-size: 25px;
}

applied to elements like:

<span class="pr around percent"><span class="outer"><span class="value">0</span><br>%</span></span>

0
%
5
%
25
%
42
%
50
%
65
%
80
%
99
%
100
%

Note the option separator: "" which avoids inserting a blank space text node between the inserted SVG and the span.outer.

A variation (using the same CSS code) for a one-minute countdown, with inverted dynamic color, a strokeColor (see above) and a valueAdapter for interpreting seconds (see below):

$(".pr.around.countdown").setupProgressPie({
    size: 70,
    ringWidth: 5,
    strokeWidth: 5,
    strokeColor: "#ddd",
    strokeDashes: {
        count: 12, 
        length: 2, 
        centered: true, 
        inverted: true
    },
    valueSelector: "span.value",
    valueAdapter: function(s) {return parseInt(s)*10/6;},
    color: function(p) {return $.fn.progressPie.colorByPercent(100-p);},
    separator: ""
}).progressPie();

60
sec.
50
sec.
40
sec.
30
sec.
20
sec.
15
sec.
10
sec.
5
sec.
0
sec.

Note: Of course, you can use CSS code like in the above example not only to place the value inside the ring. You might also keep the label invisible (providing the value in a data attribute, see above) and put some other graphic (SVG or other format) over/inside the ring, e.g. a pause or stop icon clickable to halt or abort the running process whose value is displayed by the ring.

Updating (and content plug-ins)

The following examples demonstrate dynamic updating of pies or rings, using the setupProgressPie plug-in function which was introduced in V1.3.0: This function once sets up the options and stores them in each selected DOM node. For updating, now all that's needed is to update the value and call the progressPie() again, which then re-uses the same options on each update.

The setup is usually only done once, but the #timerbutton example below also demonstrates, that the setup may be updated as well: In this case, the content plugin is updated to change the displayed control icon depending on the timer's state.

One of the following examples also demonstrates updating without the setupProgressPie() method. In this case, all the options have to be initialized again for each redraw, and the update option has to be set in order to enable replacing an existent graphic (using the setupProgressPie() method, the update option automatically defaults to true).

<head>
…
<script type="text/javascript">
    var timerVal = 120;
    var timerRunning = false;
    
    function startStopTimer() {
        if (timerVal == 0) {
            timerVal = 120;
            $("#timerbutton").data("val", 0);
        } else {
            timerRunning = !timerRunning;
        }
        if (timerRunning) {     
            timer();
        } else {
            updateTimerPies();
        }
    }
    
    function updateTimerPies() {
        var percent = Math.floor((120 - timerVal) / 1.2);
        //while progressPieSVG actually supports floating point numbers as input, these calculated percent
        //values are also to be displayed inside a ring graph and are therefore intentionally truncated to integers.
        $(".pp:not(.attr).timer").each(function(){
            $(this).text(percent).progressPie();
        });
        $(".pp.attr.timer").each(function(){
            $(this).data("val", percent);
            //if you watch the element in the DOM inspector, you'll probably notice that the original attribute `data-val` is not changed,
            //the value is stored as a number in a jQuery-internal cache (`$.cache`), not in the DOM.
            //Therefore this way of updating the value requires the use of the `valueData` option, `valueAttr` will not work here!
            var size = $(this).hasClass("growing") ? 30 + (percent / 2) : 30;
            var strokeColor = $(this).hasClass("silverborder") ? "silver" : undefined;
            $(this).progressPie({mode:$.fn.progressPie.Mode.COLOR, valueData:"val", size: size, strokeWidth: 5, strokeColor: strokeColor, update: true});
        });
        $(".pr.around.percent.timer").each(function(){
            $("span.value", $(this)).text(percent);
        }).progressPie();
        if (timerVal % 2 == 0) {
            $(".pr.around.countdown.timer").each(function(){
                $("span.value", $(this)).text(timerVal/2);
            }).progressPie();
        }
        $("#timerbutton").data("val", percent)
            .setupProgressPie({contentPlugin: timerRunning ? "pause" : timerVal > 0 ? "play" : "stop"})
            .progressPie();
    }
    
    function timer() {
        if (timerRunning) {
            timerVal -= 1;
            if (timerVal > 0) {
                window.setTimeout(timer, 500);
            } else {
                timerRunning = false;
            }
        }
        updateTimerPies();
    };
    
    $(function() {
        …
        $("#timerbutton").setupProgressPie({
            color: "#00d",
            strokeWidth: 1,
            ringWidth: 3,
            valueData: "val",
            contentPlugin: "play"
        }).progressPie();
        //Setup code for the other pies: see previous examples
    });
</script>
</head>
…
<body>
    …
    <p><span class="pp default timer">0</span> %<br>
        <span class="pp attr timer" data-val="0"></span><br>
        <span class="pp attr silverborder timer growing" data-val="0"></span><br>
        <span class="pr around percent timer"><span class="outer"><span class="value">0</span><br>%</span></span><br>
        <span class="pr around countdown timer"><span class="outer"><span class="value">60</span><br>sec.</span></span><br>
        <button onclick="startStopTimer()" id="timerbutton" data-val="0">Click me!</button>
    </p>
    …
</body>

0 %


0
%

60
sec.

The control icons in the button above are a demonstration of the SVG content plug-in mechanism: You may provide special plugin modules which render additional SVG content inside a ring graph. These control plug-ins require the inclusion of an additional JavaScript file:

<script type="text/javascript" src="js/min/jquery-progresspiesvg-controlIcons-min.js"></script>

See separate example page for more on content plug-ins!

ValueAdapters: Visualize other values than percent numbers

The following example takes a value in minutes instead of percent as a value. The valueAdapter converts any positive number of minutes into percent of an hour.

ValueAdapter functions may be used regardless of the value source: Whether the values are read from the element content (default) or from an attribute makes no difference.

$(".pp.minutes").progressPie({valueAdapter: function(valueStr) {
    return parseInt(valueStr) * 10 / 6;
}})

0 5 15 20 30 35 40 45 60 80

Double / multiple pies

Taking the previous example further: The progresspie component may also display two values overlapping. This might, for example, be used to depict a countdown in hours and minutes (or minutes and seconds). The following examples both show the hours-and-minutes example in different variations. In analogy to analog watch faces, the smaller, inner pie shall display an hour value (e.g. hours of a countdown still remaining) and the outer, larger pie the minutes-of-the-hour-value.

Parsing a visible element content of pattern hh:mm

Say, you have a span element containting a time value of format "hours:minutes" like

<span class="pp hmv">6:15</span>

You might now prepend a double pie chart als follows:

$(".pp.hmv").progressPie({
    mode:$.fn.progressPie.Mode.GREY,
    valueAdapter: function(str) { 
        var m = /\d+:(\d{1,2})/.exec(str)[1];
        return parseInt(m) * 10 / 6; 
    },
    inner: {
        mode:$.fn.progressPie.Mode.RED,
        valueAdapter: function(str) { 
            var hm = /(\d+):(\d{1,2})/.exec(str);
            var m = 60*parseInt(hm[1]) + parseInt(hm[2]); //hours converted to minutes plus minutes of hour = total minutes
            //100% <-> 12 hours = 720 minutes
            return m * 100 / 720;
        }
    }
});

0:00 0:15 1:00 1:55 2:45 6:15 07:58 12:15

Note that this example uses one single value string (here: the span's content, but of course you might also use an attribute value, see above), but two valueAdapter functions in order to derive two different percent values from one string value. Here, this is done using regular expressions.

Separate value attributes

Of course, if you happen to have two separate number values “at hand” you may insert these into two separate data-attributes of the HTML element and use these directly (if they happen to be percent values) or mapped via valueAdapter functions. This example uses separate attributes for hours and minutes:

<span class="pp hma" data-hours="6" data-minutes="15">6:15</span>

Also, this example demonstrates manual sizing of both the outer and the inner pie.

$(".pp.hma:not(.ring):not(.rings)").progressPie({
    mode:$.fn.progressPie.Mode.RED,
    valueData: "minutes",
    valueAdapter: function(mins) { return mins * 10 / 6; },
    size: 30,
    inner: {
        color: "navy",
        valueData: "hours",
        valueAdapter: function(hours) { return hours * 100 / 12; },
        size: 20
    },
    verticalAlign: "middle",
    strokeWidth: 1
});

0:00 0:15 1:00 1:55 2:45 6:15 7:60 12:15

Note however, that in this example the inner hour-pie is independent of the minutes pie: for the time "1:55" it fills exactly the same area (1/12) as for "1:00". The example above, on the other hand, takes advantage of the fact that the valueAdapter for the hour value also has access to the minutes value and displays for "1:55" a pie nearly as large as for "2:00" (1/6).

Combination with rings

As for single graphics, you may also set the ringWidth option for the outer and/or the inner pie. This example is simply a modification of the example above, displaying the minutes value as a ring instead of a full pie. The ringWidth is less than the difference between inner and outer radius, so that the inner pie (hour value) does fit into the ring without overlap. (Outer size is 30, inner size is 20, i.e. difference in diameter is 10, difference in radius is 5; ringWidth is set to 4, which is smaller than 5, which leaves a 1 pixel gap between inner pie and outer ring.)

$(".pp.hma.ring").progressPie({
    mode:$.fn.progressPie.Mode.RED,
    valueData: "minutes",
    valueAdapter: function(mins) { return mins * 10 / 6; },
    size: 30,
    inner: {
        color: "navy",
        valueData: "hours",
        valueAdapter: function(hours) { return hours * 100 / 12; },
        size: 20
    },
    verticalAlign: "middle",
    strokeWidth: 1,
    ringWidth: 4
});

0:00 0:15 1:00 1:55 2:45 6:15 7:60 12:15

Of course, you may also apply the ringWidth option to the inner pie:

$(".pp.hma.rings").progressPie({
    mode:$.fn.progressPie.Mode.RED,
    valueData: "minutes",
    valueAdapter: function(mins) { return mins * 10 / 6; },
    size: 30,
    inner: {
        color: "navy",
        valueData: "hours",
        valueAdapter: function(hours) { return hours * 100 / 12; },
        size: 20,
        ringWidth: 4
    },
    verticalAlign: "middle",
    strokeWidth: 1,
    ringWidth: 4
});

0:00 0:15 1:00 1:55 2:45 6:15 7:60 12:15

Three (or more) values/rings

Starting with V2.0.0, this plug-in now supports even more than 2 pies or rings: The inner option may now itself contain another inner option for a third value, that may, yet again, contain an inner option (fourth value) and so forth. When using this feature, you should use rings instead of (overlapping) pies by setting a ringWidth in the main options object and in each inner object (only the innermost might be a pie as demonstrated above for double diagrams). And you should set the size of each ring in order to control the spacing/gap between outer and inner ring manually for a good result (auto-spacing doesn't work well with more than 2 values).

Also new is the support of stroke* options even inside inner options, i.e. for each inner ring or pie you may draw a full circle around it or (more likely, like demonstrated below) with strokeWidth equal to the ringWidth in order to draw a full background circle overlapped by the ring.

Example with three rings, all with background circles (stroke*), colors configured programatically in plug-in call:

$(".triple1").progressPie({
    globalTitle: "Demo with three rings",
    size:50,
    ringWidth: 5,
    strokeWidth: 5,
    color: "rgb(200, 0, 0)",
    strokeColor: "rgba(200, 0, 0, 0.2)",
    ringEndsRounded: true,
    valueData: 'outer',
    inner: {
        size: 35,
        ringWidth: 5,
        strokeWidth: 5,
        color: "rgb(0, 200, 0)",
        strokeColor: "rgba(0, 200, 0, 0.2)",
        ringEndsRounded: true,
        valueData: 'middle',
        inner: {
            size: 20,
            ringWidth: 5,
            strokeWidth: 5,
            color: 'rgb(0, 200, 200)',
            strokeColor: 'rgba(0, 200, 200, 0.2)',
            ringEndsRounded: true,
            valueData: 'inner'
        }
    }
});

applied to:

<span class="triple1" data-outer="88" data-middle="45" data-inner="56"></span>

As explained above in section CSS formatting, you may, if you prefer, configure the color scheme by CSS rules instead of in the plug-in call options. A variation of the above example:

$(".triple2").progressPie({
    globalTitle: "Activity charts",
    title: "Move",
    animate: true,
    size: 60,
    ringWidth: 6,
    strokeWidth: 6,
    mode: $.fn.progressPie.Mode.CSS,
    ringEndsRounded: true,
    valueData: 'outer',
    inner: {
        title: "Exercise",
        size: 45,
        mode: $.fn.progressPie.Mode.CSS,
        ringWidth: 6,
        strokeWidth: 6,
        ringEndsRounded: true,
        valueData: 'middle',
        inner: {
            title: "Stand",
            size: 30,
            mode: $.fn.progressPie.Mode.CSS,
            ringWidth: 6,
            strokeWidth: 6,
            ringEndsRounded: true,
            valueData: 'inner'
        }
    }
});
.triple2 {
    background: black;
    border-radius: 5px;
    padding: 5px;
    margin: 1em;
    display: inline-block;
    box-shadow: 0 0 5px rgba(0,0,0,0.8)
}
.triple2 svg {
    vertical-align: middle;
}
.triple2 .progresspie-background {fill: none}
.triple2 .progresspie-background.progresspie-outer  {stroke: rgba(220, 0, 0, 0.3)}
.triple2 .progresspie-foreground.progresspie-outer  {stroke:  rgb(220, 0, 0)}
.triple2 .progresspie-background.progresspie-inner  {stroke: rgba(0, 220, 0, 0.3)}
.triple2 .progresspie-foreground.progresspie-inner  {stroke:  rgb(0, 220, 0)}
.triple2 .progresspie-background.progresspie-inner2 {stroke: rgba(0, 220, 220, 0.3)}
.triple2 .progresspie-foreground.progresspie-inner2 {stroke:  rgb(0, 220, 220)}
<span class="triple2" data-outer="40" data-middle="85" data-inner="70"></span>

This example also demonstrates the use of the title option, specifying a specific title for each of the ring, in combination with the globalTitle option, specifying a title for the whole chart. If, in a desktop browser, you point your mouse curser on the image and let it rest for a while, a title popup should show either the local ring's title, if you point to a ring, or the global chart's title, if you point anywhere else on the black background. (See Adding a title)

Note: This example uses SMIL animation (reload to play, not supported by Internet Explorer/Edge). See separate animation example page for more on that topic.

(Note 2: Obviously, this example is inspired by the activity display of the Apple Watch. It's not exactly a copy, though, just similar. Especially note that progresspieSVG does not support displaying values greater than 100%.)

See Example for optionsByRawValue below for another multiple-ring-example.

Rotation Animation

Note: This feature once used to be implemented by SMIL animation. SMIL Animations are supported by most modern browsers – except Microsoft's (IE or Edge). Since V2.5.0 the SMIL rotation animation has been replaced by a CSS animation. For now, this sadly does not improve browser support, since IE and Edge, while they do support CSS animation in general, don't support CSS transformations like rotation. This means, IE and Edge still don't support this rotation animation! But while SMIL support is not even intended for the future, at least Edge should support CSS transformations someday. Also, the CSS rotation can now be applied to inner pies/rings, while the old SMIL implementation only supported rotation for the outermost / main ring.

Update: With the new Feature Update for Windows 10 from April 2018, Microsoft finally added CSS transformation support for SVG to the Edge browser. I.e.: In the current Edge version, this rotation animation will now work! (Older Edge versions as well as Internet Explorer stillwon't play the animation.)

You may add a clockwise rotation animation to any pie or ring as shown above. For a normal value would not seem like a good idea, but if you want to indicate some waiting interval without the progress actually being measured at the time being, you might use this to build a “Busy-Indicator” like e.g. one of the following:

$('#rotate1').progressPie({
     rotation: "500ms",
     valueAdapter: function() {return 5;}
});
$('#rotate2').progressPie({
    strokeWidth: 1,
    ringWidth: 3,
    color: "#333",
    rotation: {
        duration: "2s",
        clockwise: false
    },
    valueAdapter: function() {return 50;}
});
$('#rotate3').progressPie({
    strokeWidth: 0,
    ringWidth: 1,
    color: "navy",
    rotation: true,
    valueAdapter: function() {return 90;}
});

Note the valueAdapter function in these examples, returning a constant value defining the size of the rotating pie or the size of the gap in the rotating ring.

The animation by default only applies to the main / outer pie or ring. But the inner option now (since V2.5.0) also supports a rotation property, so you can animate each sub diagram separately, as demonstrated below:

$('#rotate4').progressPie({
    size: 40,
    strokeWidth: 0,
    ringWidth: 5,
    ringEndsRounded: true,
    color: "#900",
    rotation: "1s",
    valueAdapter: function() {return 85;},
    inner: {
        color: "navy",
        valueData: "value",
        rotation: {
            duration: "5s",
            clockwise: false
        }
    }
});

A further example of a “busy indicator” for a process with result feedback can be found in the examples page for content plug-ins.

Overriding options based on percent values

Normally, you specify one set of options which gets applied regardless of the value. Most options are constant, an exception is the color: As demonstrated above, you may specify a color function setting the actual color dependent upon the percent value.

Maybe that's no enough, maybe you want to change other things dependent on the percent value, too. So, for example, you might want to show a rotaion animation (see above) as long as the percent value has not been increased yet (is still zero), but switch to a pie chart for any value greater than zero.

For static values, you might simply call the plug-in with different options depending on the static value. The “Updating” example above also already shows a way to change other options like the size by simply calling the progressPie plug-in with different, newly calculated options on each update. But if you want to set up a general rule (using the setupProgressPie plug-in function), simply define a set of default options and add an optionsByPercent function, mapping a percent value to either an object with some options or to null if the default options should not be altered for this percent value. An object returned does not have to be a complete set of options, but only to contain those options which differ from the defaults.

The following example sets some default values for a pie chart and then overrides some options only for a value of 0% in order to then show a spinning ring instead:

function greyToGreen(percent) {
    var v = percent < 50 ? 0 : percent - 50; //0..50
    var rb = 100 - (2 * v);
    var g = 100 + (2 * v);
    return "rgb(" + rb + ", " + g + ", " + rb +")";
}
…   
$(".spinThenPie").setupProgressPie({
    color: greyToGreen,
    strokeWidth: 2,
    contentPlugin: "checkComplete", //see separate examples page for details
    optionsByPercent: function(percent) {
        return percent > 0 ? null : { //return null for values > 0, meaning "no changes to the defaults"
            //for value 0: override strokeWith and color and add some more options
            strokeWidth: 0,
            ringWidth: 2,
            rotation: true,
            valueAdapter: function() { return 85; }, //takes the 0 value and returns 85 instead.
            color: greyToGreen(0) //otherwise the color would be "greenish", calculated for the value 85
        }
    }
}).progressPie();

0 % 5 % 25 % 42 % 50 % 65 % 80 % 99 % 100 %

Overriding options based on raw values

Note: The following example combines several different topics, like Double / multiple pies (see above), content plug-ins as well as SMIL animation. Yet its main purpose is the demonstration of the use of the optionsByRawValue option.

There may be cases where the calculated percent value is not suitable for deriving changes in options, but where you have to base your decision on the raw value before it gets converted into a percent value by the value adapter function.

In this case, simply use the similar optionsByRawValue option. But be aware that the type of the raw value (other than that of the calculated percent value) is not guaranteed to be "number"! Especially when the value is read from an attribute, its type is usually "string". Just like a value adapter has to check the type and maybe convert the raw value, so does this method!

The following example consists of two rings and one pie, all three of which deriving their individual percent values from the same raw value using different value adapters. The diagrams show a count-down. The raw value is the number of remaining seconds, which is converted into three values: hours, minutes and seconds. The inner pie's showing the total remaining time in hours (i.e. 100% filled pie represents 12 hours of remaining time or more), the ring around that shows the remaining minutes of the current hour and the outer ring the remaining seconds of the current minute—similar to an analog clock face.

In the last minute, i.e. the last 60 seconds, instead of the inner hour pie (which is already effectively empty) a content plug-in (see separate example page) is loaded which shows a numerical count-down of these 60 seconds. The decision whether to show this content plug-in or not, is easily made based on the raw value (seconds). The percent value of the outer ring (seconds) is not suitable for this decision at all, since this outer ring always shows the 100% value (60 seconds) for every full minute.

One second after the countdown reached its target (0), i.e. as soon as the raw seconds value gets negative, the optionsByRawValue define yet another modification of options, removing the content plug-in again and instead showing a wait indicator (rotating half arc). (Note that, since the raw value is allowed to be negative, the value adapter functions for all three rings as well as the label function for updating the hour-minute-second-label of the live pie, explicitly test for negativeness of the raw value and return 0 in that case.)

The following code snippet not only contains the setup for the progress pie plug-in but also code for a live count-down example and the user interface to manually change the count-down value. In order not to clutter up the global scope with functions and variables specific to this example, all of them have been wrapped into an immediately invoked function expression.

(function() {
    function parseSecsData(s) {
        return typeof s === 'number' ? s : parseInt(s);
    }
    var dashes = {
        count: 12,
        centered: true,
        length: 3,
        inverted: true
    };
    $(".countdownHms").setupProgressPie({
        globalTitle: "Countdown",
        title: "Remaining seconds of current minute",
        size: 60,
        verticalAlign: "middle",
        animate: true,
        ringWidth: 2,
        color: "rgb(0, 0, 200)",
        strokeWidth: 2,
        strokeColor: "rgba(0, 0, 200, 0.3)",
        strokeDashes: dashes,
        valueData: "remainingsecs",
        valueAdapter: function(s) {
            var totalSecs = parseSecsData(s);
            var secs = totalSecs < 0 ? 0 : totalSecs % 60;
            if (secs === 0 && totalSecs > 0) {
                secs = 60;
            }
            return secs * 10 / 6; //100% = 60 secs
        },
        optionsByRawValue: function(s) {
            var secs = parseSecsData(s);
            return secs > 60 ? null :  //no change if secs > 69
                   secs >= 0 ? { //last minute
                        contentPlugin: "rawValue",
                        contentPluginOptions: {
                            fontSizeFactor: 1.3
                        }
                    } : { //counter fell below zero
                        valueAdapter: p => 50,
                        rotation: true
                    };
        },
        inner: {
            title: "Remaining minutes of current hour",
            size: 52,
            ringWidth: 5,
            color: "rgb(50, 200, 150)",
            animate: true,
            strokeWidth: 5,
            strokeColor: "rgba(50, 200, 150, 0.3)",
            strokeDashes: dashes,
            valueData: "remainingsecs",
            valueAdapter: function(s) {
                var secs = parseSecsData(s);
                var p = secs < 0 ? 0 : secs % 3600 / 36; // 100% = 1h = 60min = 3600 secs
                if (p === 0 && secs > 0) {
                    p = 100;
                }
                return p;
            },
            inner: {
                title: "Remaining hours",
                animate: false,
                size: 38,
                valueData: "remainingsecs",
                valueAdapter: function(s) {
                    var secs = parseSecsData(s);
                    var mins = secs < 0 ? 0 : secs / 60;
                    return Math.round(mins * 10 / 72); //100% <-> 12 hours = 720 minutes
                },
                color: function(p) {
                    return $.fn.progressPie.colorByPercent(100-p);
                }
            }
        }
    }).progressPie();
    function hms(s) {
        const secs = s % 60;
        const ms = s % 3600;
        const mins = (ms - secs) / 60;
        const hrs  = (s - ms) / 3600;
        return `${hrs}h${("0" + mins).slice(-2)}'${("0" + secs).slice(-2)}"`;
    }
    function tick() {
        $(".countdownHms.live").each(function() {
            const ctd = $(this);
            let secs = ctd.data("remainingsecs");
            if (secs >= 0) {
                secs--;
                ctd.data("remainingsecs", secs);
                ctd.text(hms(Math.max(0, secs)));
                ctd.progressPie();
            }
        });
    }
    window.setInterval(tick, 1000);
    $("#livecountdownHmsUpdate").click(() => {
        $(".countdownHms.live").data("remainingsecs", $("#livecountdownHmsInput").val());
    });
})();

11h59'55" 8h55'11" 2h12'44" 1h00'01" 1h00'00"

0h01'00" 0h00'36" 0h00'01" 0h00'00" -1

Live Countdown:

^