Beispiele: jQuery-Plugin

Direkte Aufrufe des Plugins

Folgende ausgewählte Vorschaubilder von nachfolgend genauer beschriebenen Beispielen können einen ersten Eindruck der Anpassbarkeit und Vielseitigkeit des Plugins geben:

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

1:55

80
%
20
sec.

Allgemeine Verwendung

Die folgenden Beispiele zeigen jeweils eine Code-Zeile JavaScript der folgenden Art:

$(selector).progressPie(options)

oder alternativ:

$(selector).setupProgressPie(options).progressPie()
  • Die erste Variante ist der typische einmalige Aufruf zum Zeichnen eines konstanten Wertes. Die zweite Variante ist vorzuziehen, falls der Prozentwert sich (skriptgesteuert) ändern kann und dann die Grafik unter Beibehaltung derselben Optionen aktualisiert werden soll. Die setupProgressPie-Methode speichert dabei zunächst nur die Optionen, anschließend kann beliebig oft progressPie() ohne Parameter aufgerufen werden, um das Diagramm (neu) zu zeichnen.

  • selector ist dabei der jQuery-Selektor-String zur Auswahl eines oder mehrerer DOM-Elemente, die bereits einen Prozentwert enthalten und denen nun die Grafik hinzugefügt werden soll. Der Selektor hängt also vom jeweiligen HTML-Dokument ab und ist nicht nicht der primäre Teil des Beispiels. In diesem Fall selektiert er spezifisch die zum jeweiligen Beispiel gehörenden span-Elemente dieser Demoseite.

  • Der eigentliche, interessante Teil eines jeden Beispiels ist daher das Argument options.

  • Beachten Sie bitte, dass diese jQuery-Anweisungen jeweils erst ausgeführt werden dürfen, nachdem das Seitenmodell (DOM) vom Browser komplett geladen wurde. In jQuery erreicht man dies typischerweise durch Einbettung in einen Eventhandler der folgenden Art:

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

Default-Modus

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

angewendet auf Elemente wie:

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

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

Vordefinierte Farb-Modi

Color mode (dynamische Farben)

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

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

Green mode (statisch grüne Farbe)

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

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

Red mode (statisch rote Farbe)

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

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

Ring anstelle von Torte zeichnen

Setzen Sie die Option ringWidth, um statt eines Tortensegments ein Ring-/Kreissegment zu zeichnen. Der Wert der Option bestimmt die „Dicke“ dieses Rings.
Es wird empfohlen, den Ring mit einem dünneren Außen-Umkreis zu kombinieren, wozu die Option strokeWidth dient:

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

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

Oder setzen Sie z.B. die strokeWidth auf denselben Wert wie ringWidth und legen statt dessen mittels strokeColor eine abweichende (kontante) Farbe für den vollen (Hintergrund-)Kreis fest, damit sich der darüber gelegte (Teil-)Ring davon abhebt:

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

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

Benutzerdefinierte Farben

Benutzerdefinierte statische Farbe (via Option color)

$(".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)"});

Den folgenden Torten ist jeweils eine der vier Klassen ‘navy’, ‘yellow’, ‘rgb’ oder ‘rgba’ zugeordnet. Für alle drei Klassen wird das Plugin separat aufgerufen und jeweils dieselbe Option (color) gesetzt. Neben den verschiedenen Farben für diesen Klassen besteht ein weiterer Unterscheid in der Syntax zur Notation der Farbwerte. Das rgba-Beispiel demonstriert die Auswirkung eines Alpha-Kanals.

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

Beachten Sie, dass der Vordergrund (Tortenstück) den Hintergrund-Kreis überlappt. In diesem Fall fällt das besonders auf, da beide Figuren per Alpha-Kanal halbtransparent sind, und dort, wo sie sich überlappen, die Deckkraft zunimmt: Der Hintergrund-Kreis bleibt so hinter dem Tortenstück sichtbar. Ist das nicht gewünscht, kann die Überlappung abgeschaltet werden, indem die overlap-Option (weiter unten vorgestellt) auf false gesetzt wird:

$(".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 %

Lokale Farb-Funktion (via Option color)

Beispiel 1: Anonyme "Inline-"Funktion

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

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

Beispiel 2: Funktionsreferenz

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 %

Beispiel 3: (referenzierte) Funktion, welche die interne Funktion colorByPercent wiederverwendet

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 %

Formatierung per CSS

Ab Version 2.0.0 fügt das ProgressPieSVG Plugin den generierten SVG-Diagrammen CSS-Klassen hinzu, über die es möglich ist, per externen CSS Style Sheets das Aussehen weiter zu beeinflussen, anstatt alles ausschließlich über die Optionen beim Plugin-Aufruf konfigurieren zu müssen. Die Standard-CSS-Klassennamen lauten:

  • progresspie-background für den Hintergrund-Kreis und

  • progresspie-foreground für das Torten- oder Ringstück im Vordergrund.

  • Falls Sie doppelte Ringdiagramme zeichnen, wird beiden Diagrammteilen, also Hintergrundkreis und Vordergrundring jeweils zusätzlich zu den oben genannten Klassen eine jeweils zweite zur Unterscheidung der einzelnen dargestellten Werte zugewiesen:

    • progresspie-outer für den äußeren Ring/Torte

    • progresspie-inner für den inneren Ring/Torte.

    Beispielsweise wird eine CSS-Regel der Art .progresspie-foreground{...} Formate für alle Vordergründe sowohl einfacher als auch doppelter Torten-/Ringdiagramme festlegen, während ein Selektor wie .progresspie-foreground.progresspie-inner explizit nur die inneren Torten- oder Ringstücke anspricht.

  • Sollten Sie sogar durch geschachtelte inner-Optionen noch mehr als zwei Werte in einem Diagramm vereinen, d.h. einen äußeren Ring zeichenn, der einen inneren Ring enthält, der wiederum einen weiteren inneren Ring enthält (der wiederum einen inneren Ring enthalten könnte u.s.w.), so werden ab dem dritten Ring (dem inneren inneren) die Inner-Klassen um eine Nummer erweitert:

    • Der äußere Ring bekommt wie gehabt die Klasse progresspie-outer,

    • der zweite Ring (inner) bekommt wie gehabt die Klasse progresspie-inner,

    • der dritte Ring (inner.inner) bekommt Klasse progresspie-inner2,

    • der vierte Ring (inner.inner.inner) bekommt Klasse progresspie-inner3.

    • und so weiter.

CSS-Stile im „normalen“ Modus überstimmen

Gehen wir von einem regulären Plugin-Aufruf aus, der insbesondere auch die Diagrammfarben festlegt, in diesem Beispiel durch den vordefinierten COLOR-Modus:

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

In dieser Form ergibt das Beispiel gar keinen Sinn, da ein Ringsegment auf einen vollen Hintergrundkreis gezeichnet wird und beide dieselbe Farbe haben, der Vordergrund sich also gar nicht vom Hintergrund abhebt und somit effektiv unsichtbar ist.
Wir könnten dieses Problem nun (statt durch sinnvollere Plugin-Optionen wie die Angabe einer strokeColor-Option zum Umfärben des Hintergrundkreises, siehe frühere Beispiele) auch durch CSS-Regeln beheben: In diesem beispiel legen wir erstens mittels stroke-dasharray fest, dass der Hintergrundkreis nicht mehr massiv, sondern gestrichelt sein soll (mit 1 Pixel kurzen Strichen und 3 Pixel langen Lücken), vor allem aber ändern wir auch per CSS die Farbe des Hintergrundkreises:

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

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

Dabei ist stets zu bedenken, dass lokale Stile (also style-Attribute in den SVG-Tags) Vorrang vor globalen CSS-Regeln haben, und da im „normalen“ Modus das ProgressPieSVG-Plug-in die Farben für die Diagrammelemente direkt in lokalen Stilattributen des erzeugen SVGs definiert, muss eine externe Regel um den Zusatz !important ergänzt werden, um die Standardrangfolge außer Kraft zu setzen und den lokalen Stil doch extern überstimmen zu können.

Spezieller CSS-Modus

Wenn Sie wirklich Farben (und Ausrichtung) lieber über externe CSS-Regeln statt Plugin-Optionen festlegen möchten, können Sie das Plugin auch anweisen, die Farb- und vertical-align-Inline-Styles im SVG komplett wegzulassen. Das sorgt für etwas kompakteren SVG-Code und damit entfällt dann auch der Bedarf für die oben erwähnte !important-Direktive in Ihren CSS-Regeln. Diesen Modus aktiveren Sie, indem Sie die Option mode auf den vierten vorgegebenen Farbmodus stellen: $.fn.progressPie.Mode.CSS.
Beachten Sie aber, dass im CSS-Modus…

  • unbedingt alle Farben per CSS definiert werden müssen, d.h. Sie müssen für diese Diagramme per CSS die Eigenschaften stroke und fill für den Hintergrundkreis und die Eigenschaft stroke für den Vordergrund (Torte/Ring) setzen (fill wird für den Vordergrund vom Plugin auch im CSS-Modus stets auf none gesetzt, denn ein Füllen eines Ring-Segments ergibt keinen Sinn),

  • und die vertical-align-Property des SVG-Knotens sollte ebenfalls per CSS definiert werden, zumindest wenn das Zielelement, in das das SVG eingefügt wird, nicht leer ist: Das erste der beiden folgenden Beispiele unterlässt die Definition eines vertical-align-Stils, mit dem Ergebnis, wie Sie sehen, dass die Torten und die Prozentangaben nicht schön ausgerichtet sind. (In jedem anderen Modus wird die vertikale Ausrichtung über die Option verticalAlign des ProgressPieSVG-Plugins festgelegt, und auch wenn Sie diese nicht angeben, bekommt sie mit bottom einen oft passenden Default-Wert. Im CSS-Modus dagegen wird die verticalAlign-Option ignoriert und gar kein vertical-align-Inline-Style ins SVG eingefügt.

$(".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 %

Ein Beispiel zur CSS-Formatierung von Doppel-/Mehrfach-Ringdiagrammen per CSS findet sich im zugehörigen Abschnitt weiter unten.

CSS-Klassen anders benennen

Die vorgegebenen Klassennamen progresspie-foreground etc. wurden absichtlich sämtlich mit dem Präfix "progresspie-" versehen, um Namenskonflikte mit in Ihren Dokumenten schon bestehenden CSS-Klassen so weit wie möglich zu vermeiden. Wenn Ihnen diese Klassennamen aber zu lang und sperrig sind, können Sie sie z.B. durch kürzere ersetzen.

Sie können die Defaultnamen global umbenennen, indem Sie die folgenden Variablen überschreiben: jQuery.fn.progressPie.defaults.cssClassBackgroundCircle, jQuery.fn.progressPie.defaults.cssClassForegroundPie, jQuery.fn.progressPie.defaults.cssClassOuter und jQuery.fn.progressPie.defaults.cssClassInner.

Oder Sie können beim Plugin-Aufruf lokal in den Plugin-Optionen eigene Klassennamen für die von dem Aufruf gezeichneten Diagramme festlegen. Die zugehörigen Optionen heißen cssClassBackgroundCircle, cssClassForegroundPie, cssClassOuter und cssClassInner.
Das folgende Beispiel demonstriert dies (wobei die Optionen cssClassOuter und cssClassInner nicht mit angegeben werden, da sie nur für Doppel-/Mehrfachdiagramme eine Auswirkung haben):

$(".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 %

Fortgeschrittene Optionen

Vertikale Anordnung

Das folgende Beispiel zeigt abwechselnd Grafiken mit und ohne die Option verticalAlign:"middle" (Defaultwert ist "bottom") in einer Zeile, deren Höhe (line-height) größer als die Schrift (font-size) ist – so dass diese Ausrichtungsoption überhaupt einen Unterschied macht.

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

angewendet auf Elemente wie:

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

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

Hinten anfügen statt voranstellen

Standardmäßig werden die Grafiken jeweils vor dem Inhalt des selektierten Elements als erster Kindknoten eingefügt, dem Inhalt also vorangestellt. Sie können alternativ einstellen, dass die Grafik hinter dem bisherigen Element-Inhalt angefügt werden soll:

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

angewendet auf Elemente wie:

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

0 5 25 42 50 65 80 99 100

Titel (Tooltip) hinzufügen

Zu HTML-Elementen können Sie bekanntlich ein title-Attribut hinzufügen. Die Auswirkung hängt vom Browser ab. Ein typischer Desktop-Browser z.B. wird den Titel als so genannten Tooltip anzeigen, wenn der Mauscursor einige Zeit auf dem betitelten Element verharrt. Solche Titel können Sie nun auch Ihren ProgressPie-Grafiken hinzufügen:

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

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

Die Option globalTitle legt einen Titel für die gesamte rechteckige SVG-Grafik fest. Alternativ dazu gibt es noch die Option title, die ihren Titel nur dem Diagrammelement selbst hinzufügt. D.h. in diesem Fall wird z.B. ein Desktop-Browser den Titel nur anzeigen, wenn der Mauscursor auf der Torte bzw. dem Ring selbst stehen bleibt, nicht jedoch in den transparenten Hintergrundbereichen.
Beide Optionen lassen sich kombinieren, dann wird beim Zeigen auf den Diagramm-Vordergrund der title, beim Zeigen auf den Hintergrund der globalTitle angezeigt.

Die title-Option ist jedoch vor allem vorgesehen für Diagramme mit mehreren Werten, typischerweise mehreren Ringen, um so jedem Ring eine eigene Legende geben zu können. Dies wird weiter unten in einem Beispiel mit drei Ringen demonstriert.

Wert-Attribute, manuelle Größenwahl und Außenkreis-Optionen:

Standardmäßig muss der von der Grafik darzustellende Prozentwert der (einzige) Inhalt des per jQuery selektierten DOM-Elements sein, und die erzeugte SVG-Grafik wird diesem dann vorangestellt (oder optional hinten angehängt, s.o.). Alternativ können Sie jedoch den Prozentwert auch unsichtbar in einem Attribut des HTML-Elements hinterlegen, wobei das Attribut üblicherweise (um HTML-konform zu bleiben) mit data- beginnen sollte, worauf ein selbst gewählter (Rest-)Bezeichner folgen darf. Der Elementinhalt kann dann leer bleiben. (Ist er nicht leer, wird wie gehabt die SVG-Grafik diesem Inhalt vorangestellt bzw. hinten angehängt.)

Die folgenden Beispiele demonstrieren ein Data-Attribut und leeren Elementinhalt unter Verwendung der valueData-Option des Plugins. Weiterhin demonstrieren sie verschiedene Anwendungen der Optionen strokeWidth und strokeColor zur Darstellung des Außen-Umkreises.

Ein dritter Aspekt, der hier ebenfalls demonstriert wird, ist die size-Option: Wird diese nicht gesetzt, so wird die Größe der Grafik automatisch bestimmt: Falls der DOM-Knoten, dem die Grafik hinzugefügt wird, Text enthält (dem die Grafik vorangestellt bzw. angehängt wird), so wird die Grafik an die Zeilenhöhe angepasst. Ist der Zielknoten dagegen leer, funktioniert das leider nicht, und es wird eine Standardgröße verwendet. Durch Setzen der size-Option können Sie explizit eine Größe festlegen, was die automatische Größenbestimmung deaktiviert. Der Wert der Option ist der Durchmesser der Grafik in Pixeln.

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

angewendet auf Elemente wie:

<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 darf den Wert Null haben:

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

Wenn Sie die Option strokeWidth auf den Radius (also den halben Durchmesser, wie er per size definiert wird) einstellen, dan wird effektiv der gesamte Hintergrundkreis mit der Farbe strokeColor gefüllt. Dies war früher einmal eine empfohlene Art, den Kreis auszufüllen, aber inzwischen gibt es bessere Wege dazu:

  • Erstens (seit V2.0.0) können Sie eine Füllfarbe per CSS festlegen, siehe Abschnitt zur CSS-Formatierung!

  • Zweitens (seit V2.1.0) können Sie nun die Option backgroundColor verwenden. Analog zur color-Option kann auch diese wahlweise einen String enthalten, der einen Farbcode beschreibt, oder eine Funktion, die einen Prozentwert (0..100) auf einen Farbcode abbildet.
    Das folgende Beispiel demonstriert eine Farbkonstante zur Hintergrundfüllung:

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

strokeWidth 1 kombiniert mit ringWidth und Verwendung von Option valueAttr anstelle von valueData sowie Demonstration einer backgroundColor-Funktion:

$(".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);
    }
});

Die backgroundColor-Function in diesem Beispiel nutzt als Ausgangspunkt dieselbe Farbfunktion wie der vordefinierte COLOR-Modus, nur fügt sie neben dem Prozentwert einen optionalen zweiten Parameter hinzu, der einen Alpha-Kanal zur Farbe hinzufügt, in diesem Fall 10% Opazität (also 90% Transparent).

Wert eines Formular-Eingabefeldes (Input) anzeigen

Angenommen, Sie designen ein HTML-Formular, das von einem Nutzer im Browser ausgefüllt werden soll, und Sie möchten den Wert eines Eingabefeldes (Input) als Torte oder Ring visualisieren. Dazu können Sie einfach die Option valueInput verwenden:

$("#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>

Wenn das Input-Element eine einfache Text-Eingabezeile ist, möchten Sie vielleicht die eine Fehleranzeige bei ungültiger Eingabe realisieren. Dazu können Sie die Option optionsByRawValue in Kombination mit einem Content-Plugin (siehe separate Beispielseite) verwenden:

$("#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>

Die Option richtet eine automatische Aktualisierung der Grafik bei einer Wertänderung ein, standardmäßig fürs change-Event. Bei einem Text-Eingabefeld jedoch wird das erst beim Verlassen (Defokussieren) des Inputs ausgelöst.
Über die Option valueInputEvents können Sie selbst bestimmen, bei welchen Ereignissen eine Aktualisierung getriggert werden soll.

Das nächste Beispiel demonstriert diese valueInputEvents-Option in Kombination mit einem jQuery-UI-Spinner, indem nicht nur nach einer Defokussierung, sondern auch bei Betätigung der Spin-Buttons (Ereignis spin) eine Aktualisierung der Grafik ausgelöst werden soll:

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

Hinweise:

  • Die Option valueInput funktioniert lediglich in setupProgressPie()! Wenn Sie progressPie({…}) direkt mit Optionen aufrufen (für ein einmaliges Zeichnen), wird eine darin ggf. vorkommende valueInput-Option ignoriert!

  • Die setupProgressPie()-Funktion wird in diesem Fall nicht einfach nur die Optionen zum Zeichnen der Grafik speichern (so dass über Aufruf von progressPie() jederzeit ein Neuzeichnen ausgelöst werden kann), sondern sie wird zusätzlich noch einen Event-Handler bei dem Input-Element registrieren, welcher bei den konfigurierten Events (Default: change) dann selbst progressPie() aufruft, um die Anzeige zu aktualisieren. Falls Sie später durch einen erneuten Aufruf von setupProgressPie() die Konfiguration ändern, wird dadurch der bereits registrierte Event-Handler nicht automatisch wieder abgemeldet!

Value Selector

Neben valueAttr, valueData und valueInput gibt es noch eine vierte Option, um festzulegen, wie und wo der anzuzeigende Wert ermittelt werden soll: valueSelector. Diese Option wird später/weiter unten auf dieser Beispielseite noch demonstriert.

Überlappen des Hintergrundkreises vermeiden

Wenn Sie für Hintergrundkreis und Vordergrund abweichende Farben verwenden (siehe obiges Beispiel pp.attr.silverborder) oder allgemein für den Vordergrund eine semitransparente Farbe (rgba), wird sichtbar, dass der Vordergrund (Torten- oder Ringstück) den vollen Kreis im Hintergrund überlappt. Diese Überlappung lässt sich auch abschalten, so dass der Radius des Vordergrunds ins Innere des Hintergrund-/Außenkreises eingepasst wird. Dies erreichen Sie, indem Sie die Option overlap auf false setzen.

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

Weiter oben gab es bereits ein anderes Beispiel mit overlap: false, und zwar im Rahmen einer für Vorder- und Hintergrund einheitlich eingerichteten Farbe mit Alphakanal (semitransparent).

Speziell im Ring-Modus: Ausrichtung von Ring und Hintergrundkreis

In allen vorangehenden Beispielen, die einen Ring und einen Hintergrundkreis zeigten, hatten wir entweder ringWidth auf denselben Wert wie strokeWidth eingestellt (wobei die Ringfarbe color von der des Hintergrundkreises strokeColor abweichen muss!), oder ringWidth war größer als strokeWidth und Ring und Hintergrundkreis waren an ihren Außenseiten bündig ausgerichtet.

Mit der Option ringAlign können Sie diese Ausrichtung verändern. Die Option steht nur zur Verfügung, wenn Ring und Hintergrundkreis beide sichtbar sind (ringWidth > 0 && strokeWidth > 0).

Die Bedeutung von ringAlign hängt auch davon ab, ob die overlap-Option (s.o.) auf true oder false gesetzt wurde. Standardmäßig hat overlap den Wert true, so dass der Ring den Außenkreis überlappt. In diesem Fall können Sie zwischen drei Ausrichtungen wählen (die sich nur bemerkbar machen, falls die Stärke des Rings ringWidth größer oder kleiner als die des Kreises strokeWidth ist, wenn beide gleich dick sind und sich überlappen, bewirken alle drei Ausrichtungen dasselbe): Die Standardausrichtung (wie in den vorangehenden Beispielen) ist OUTER, Sie können Ring und Kreis aber auch per INNER an ihren Innenkanten bündig ausrichten oder per CENTER einstellen, dass der dünnere der beiden Striche mittig innerhalb des dickeren ausgerichtet wird.

Falls overlap auf false gesetzt wurde, der Ring also den Hintergrundkreis nicht überlappen darf (s.o.), so ändert sich die Bedeutung von ringAlign ein wenig: In der Standardeinstellung (OUTER) wird die Außenseite des Rings an der Innenseite des Kreises ausgerichtet, der Ring also im Inneren des Kreises gezeichnet. In der Alternativeinstellung INNER ist es genau umgekehrt: Die Innenseite des Rings wird mit der Außenseite des Kreises ausgerichtet, der Hintergrundkreis also effektiv innerhalb des Rings angeordnet. (Eine zentrierte Ausrichtung "CENTER" ist ohne Überlappung nicht möglich.)

Alle Kombinationen von overlap und ringAlign werden in der folgenden Tabelle demonstriert. Für jede mögliche Kombination dieser beiden Optionen werden drei Sätze von Beispielen gezeigt: Eine Zeile mit ringWidth < strokeWidth, eine Zeile mit ringWidth === strokeWidth und eine mit ringWidth > strokeWidth.

Der nachfolgende JavaScript-Code richtet alle diese Beispiele ein, indem per setupProgressPie() zunächst die für alle Beispiele gemeinsamen Grundeinstellungen und dann durch weitere Setup-Aufrufe für verschiedene Teilmengen (Klassen) davon weitere spezifische Einstellungen hinzugefügt werden. (Da overlap standardmäßig den Wert true und ringAlign standardmäßig den Wert $.fn.progressPie.RingAlign.OUTER hat, setzen wir diese beiden Optionen nur für die Klassen mit davon abweichenden Werten.)

$(".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();

(Zeigen Sie mit der Maus auf eine der Grafiken, um die dem jeweiligen Beispiel zugeordnete CSS-Klasse angezeigt zu bekommen.)

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

…CENTER

keine gültige
Kombination

…INNER

Gestrichelter Hintergrundkreis

Allgemein können Linien in SVG-Grafiken gepunktet oder gestrichelt sein. Im Abschnitt CSS wurde das auch bereits durch direktes Setzen des stroke-dasharray-Stils demonstriert. Auf dem Weg können Sie zwar einfache bis komplexe Strichmuster festlegen, allerdings müssen Sie dazu stets die Längen der Striche und Lücken in Pixeln angeben, unabhängig von der Größe Ihrer Tortengrafik. Damit ist es praktisch unmöglich, die Striche an bestimmte Positionen auf dem Kreis zu positionieren, wenn so lange der Kreisumfang in Pixeln Ihnen nicht exakt bekannt ist und konstant bleibt. Denn Sie benötigten den Kreisumfang, um die korrekten Strich-Längen zu berechnen. Und selbst wenn Sie den Umfang kennen, ist die Berechnung lästige und nicht für jeden einfache Arbeit!

Aus diesem Grund bietet das ProgressPie-Plugin nun eine neue Option, das Strichmuster (dasharray) selbst zu berechnen, aus Kreisumfang und mindestens einer Zusatzangabe:

Die einfachste Anwendung ist, einfach nur anzugeben, in wieviele Striche (und Lücken) der Kreis aufgeteilt werden soll:

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

In diesem Fall sind Striche und Lücken exakt gleich lang. Ist das nicht gewünscht, können Sie über eine zusätzliche Angabe festlegen, wie lang die einuelnen Striche sein sollen, und zwar entweder absolut in Pixeln oder relativ in Prozent des Kreisumfangs. Auch gilt für absolute Angaben, dass mit größeren Diagrammen dennoch die Striche immer gleich lang blieben und dafür die Lücken immer mehr wüchsen, während bei Prozent-Angaben nur das Verhältnis zwischen Strich- und Lückengröße festgelegt wird und bei wachsenden Diagrammen beide gleichmäßig mitwachsen. Das sei an einem Beispiel mit unterschiedlichen Diagrammgrößen demonstriert:

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

0 5 25 33 45 50 70 80 100

Um die Strichlänge in Prozent anzugeben, muss der strokeDashes.length-Option ein String-Literal mit einer Zahl gefolgt vom Prozent-Symbol zugewiesen werden, siehe oben. Weisen Sie statt des Strings direkt eine Nummer zu, wird diese als absolute Größe in Pixeln interpretiert! Lediglich Angaben in Prozent sind wirklich unabhängig von der jeweiligen Diagrammgröße, denn wenn Sie Anzahl von Strichen und Länge der einzelnen Striche in Pixeln angeben, muss der Kreisumfang offensichtlich größer als Anzahl × Länge der Striche sein, d.h. Sie müssen dann sicherstellen, dass strokeDashes.length * strokeDashes.count kleiner als der Kreisumfang ist.

Beachten Sie in den obigen Beispielen weiterhin, dass der erste Strich jeweils exakt am höchsten Punkt des Kreises (12-Uhr-/0%-Position) beginnt. Alternativ können Sie durch Setzen der Option strokeDashes.centered auf true einstellen, dass der erste Strich nicht an diesem 12-Uhr-Punkt beginnen, sondern um diesen zentriert sein soll:

$(".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
    }
});

Durch Setzen der Option strokeDashes.inverted auf true können Sie das Muster invertieren, d.h. Striche und Lücken vertauschen. In dem Fall beschreibt also die length-Option nicht mehr die Länge der Striche, sondern die Länge der Lücken, während die Striche zwischen diesen gleichmäßig verteilt werden:

$(".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
    }
});

Relative Größenanpassungen: sizeFactor vs. scale

Wie oben bereits beschrieben, deaktiviert das Setzen der size-Option die automatische Größenanpassung und setzt statt dessen eine absolute Größe in Pixeln. Alternativ können Sie jedoch auch die automatische Größenbestimmung beeinflussen, indem Sie die sizeFactor-Option angeben: Die ansonsten verwendete Größe (egal ob automatisch bestimmt oder per size festgelegt) wird mit diesem Faktor multipliziert, um die endgültige Grafik-Größe (Kreisdurchmesser) zu bestimmen.

Das folgende Beispiel legt eine 50%-ige Vergrößerung der Grafik gegenüber der Standardgröße fest. Um zu betonen, dass diese Option wirklich eine relative Größenänderung (hier: relativ zur Schriftgröße) vornimmt und keine absolute Größe vorgibt, wird in diesem Besipiel jedem Wert eine andere Schriftgröße zugewiesen:

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

0 5 25 42 50 65 80 99 100

Die sizeFactor-Option wird vor dem eigentlichen Zeichnen der Grafik angewendet, um den Durchmesser der zu zeichennden Grafik zu bestimmen. Damit hat diese Option keine Auswirkung auf Aspekte wie die Strichstärken des Außenumkreises (strokeWidth) oder im Falle von Ring- statt Tortengrafik die Dicke des Rings (ringWidth). In obigem Beispiel wurde somit zwar die Tortengrafik größer, hat aber genau wie die unskalierten Beispiele einen 2-Pixel-Rand.

Es gibt eine zweite Option, die dem sizeFactor auf den ersten Blick sehr ähnlich ist, aber im Hinblick auf die letztgenannten Aspekte einen anderen Effekt erzielt: Die Option scale nimmt ebenfalls einen Faktor für eine relative Größenänderung entgegen, berechnet aber eben nicht vor dem Zeichnen eine neue Sollgröße, sondern weist den Browser an, die fertig gezeichnete Grafik nachträglich um diesen Faktor zu skalieren. Damit werden insbesondere auch die Strichstärken entsprechend mit skaliert. Ersetzt man demnach in obigem Beispiel die sizeFactor-Angabe durch scale, erhält man im Endeffekt zwar gleich große Tortengrafiken, aber die Strichstärke des Umkreises ist ebenfalls um 50% fetter geworden:

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

0 5 25 42 50 65 80 99 100

In diesem Beispiel ist der Unterschied noch „marginal“, bei komplexeren Grafiken können extremere Unterschiede auftreten.

Wenn Sie „Doppel-Torten“ (s.u.) verwenden, beachten Sie: Beide diese Optionen sind „global“ für beide Teildiagramme, außen wie innen. Die Optionen können entsprechend nicht in der inner-Option eingesetzt werden. Der sizeFactor wird dabei für beide Grafiken separat angewendet, um ihre jeweiligen Solldurchmesser zu bestimmen. Der Spalt zwischen einem äußeren Ring und einer inneren Grafik wird sich dadurch verändern, anders als bei Anwendung von scale: Dort werden alle Aspekte der Grafik einschließlich dieses Spaltes proportional skaliert.

Wert-Selektor

Soll der Prozentwert (Zahl) zwar durchaus sichtbar sein, jedoch nicht als einziger Elementinhalt fungieren, so kann der Wert in einem Subelement desjenigen Elements, in das die Grafik einzufügen ist, platziert werden. Mit jQuery direkt wird dann das äußere Element (Einfügeziel für die Grafik) selektiert, und beim Plugin-Aufruf wird als Option ein weiterer jQuery-Selektor übergeben, der dem Plugin mitteilt, wie es das Kindelement selektieren soll, welches den darzustellenden Wert enthält:

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

angewendet auf Elemente wie:

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

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

Hinweis: In den ersten Beispielen auf dieser Seite war die Beschriftung/Einheit »%« einfach hinter dem Span-Element platziert worden (da das Element ja standardmäßig nur die Zahl enthalten darf). Aber in gewissen Fällen (z.B. aus Gründen der CSS-Formatierung) kann es sinnvoll sein, statische Elemente wie diese Einheit innerhalb des Ziel-Elements anzuordnen und den Prozent-Wert in ein Subelement zu packen.
Das folgende Beispiel zeigt einen speziellen Anwendungsfall für die valueSelector-Option:

Wert-Seleketor, Beschriftung/Einheit und Wert innerhalb eines Rings (mit abgerundeten Linienenden)

Das folgende Beispiel demonstriert eine Anwendung eines Kindelements mit dem Prozentwert innerhalb des selektierten Elternelements. Hier liegt diese Konstruktion in dem Ziel begründet, den gesamten Elementinhalt (den Wert sowie seine Einheit) innerhalb des zu zeichnenden Rings anzuzeigen. Genauer wird dazu dieser Inhalt per CSS über die erzeugte SVG-Grafik gelegt, und dazu muss der gesamte Elementinhalt (Wert und Einheit) in einem Element gebündet sein (welches wiederum Kindelement des Zielelements ist, in welchem ihm später die SVG-Grafik vorangestellt werden soll).

(Das Plugin selbst bietet derzeit keine Option, direkt innerhalb des SVGs Inhalte im Ring zu rendern – hauptsächlich, weil die hier demonstrierte Anordnung des Ring-Inhalt als HTML-Code flexible CSS-Stylingmöglichkeiten bietet, aber auch weil auf diese Weise der Wert selbst von Browsern angezeigt wird, die kein SVG unterstützen.)

Weiterhin demonstriert dieses Beispiel die Option ringEndsRounded.

Sie haben zwei Möglichkeiten, Werte innerhalb einer Ring-Grafik anzuzeigen. Dieses Beispiel zeigt die erste Möglichkeit: Benutzung des progressPie-Plugins, um nur eine Ringgrafik ohne Inhalt zeichnen zu lassen und Rendern des „Inhalts“ als vom Browser über die Grafik zu legenden HTML-Container, was durch CSS-Regeln bewerkstelligt wird, wie unten beispielhaft gezeigt.
Eine Alternative ist der Einsatz eines Content-Plugins für progressPie, mit dessen Hilfe Inhalt als Teil des SVGs selbst gezeichnet werden kann. Zu dieser Möglichkeit sehen Sie sich die separate Content-Plugin-Beispielseite an!

Vorteile der hier benutzten ersten Version (HTML über SVG) liegen in einfacherem Styling des Inhalts direkt per CSS sowie darin, dass selbst ältere Browser, die noch nicht SVG-fähig sind, dann wenigstens die HTML-Wertangabe darstellen und nur den Ring darum weglassen, während bei Inhalten als Teil des SVGs dann natürlich die gesamte Grafik samt Werten fehlen würde.

Plugin-Aufruf (die Sequenz aus setupProgressPie() und progressPie() vereinfacht Aktualisierungen und wird weiter unten noch beschrieben):

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

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;
}

angewendet auf Elemente wie:

<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
%

Beachten Sie die Option separator: "", durch die das per Default aktive Einfügen eines Leerzeichens zwischen dem eingefügten SVG und dem span.outer vermieden wird.

Die folgende Variation zeigt (mit demselben CSS-Code wie oben) einen einminütigen Countdown. Das Beispiel verwendet eine Umkehrung der dynamischen Farben des COLOR-Modus, eine abweichende Kreisfarbe (strokeColor, siehe oben) und einen valueAdapter zur Interpretation der Sekunden-Werte (siehe unten):

$(".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.

Hinweis: Natürlich können Sie CSS-Code wie in obigem Beispiel nicht nur dazu verwenden, den Prozentwert innerhalb des Rings darzustellen. Sie könnten z.B. auch den Wert selbst unsichtbar halten (in einem Data-Attribut, s.o.), jedoch eine weitere Grafik (SVG oder auch anderes Format) innerhalb des Rings anzeigen lassen, z.B. ein (anklickbares) Stopp- oder Pause-Icon zum Abbrechen oder Pausieren des laufenden Prozesses, dessen Fortschritt vom Ring dargestellt wird.

Aktualisieren der Grafik (und Content-Plugins)

Das folgende Beispiel demonstriert dynamisches Aktualisieren von Torten oder Ringen, wobei die setupProgressPie-Funktion verwendet wird, die in V1.3.0 eingeführt wurde: Diese Funktion speichert die zu verwendeten Einstellungen in den selektierten DOM-Elementen, so dass für einfache Updates später – nach dem Aktualisieren des zu zeichnenden Prozentwerts – einfach nur wieder die progressPie-Funktion anzuwenden ist, die die zuvor gesicherten Optionen wieder anwendet.

Ein solches „Setup“ wird im Normalfall nur einmal durchgeführt. Am #timerbutton im Beispiel wird aber auch demonstriert, dass das Setup vor dem Neuzeichnen auch durchaus verändert werden kann. In diesem Fall wird vor dem Neuzeichnen des Timer-Buttons das Steuerungs-Icon (Play/Pause/Stop) je nach Timer-Zustand aktualisiert.

<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.

Die Steuerungs-Icons (Wiedergabe/Stop/Pause) im obigen Button sind eine Demonstration des Content-Plugin-Mechanismus: Sie können das progressPie-jQuery-Plugin mit eigenen Content-Plugins erweitern, die Inhalte zur SVG-Grafik hinzufügen. Für diese Steuerungs-Icons muss eine weitere JavaScript-Datei eingebunden werden:

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

Siehe separate Beispiel-Seite für mehr Infos und Beispiele zu Content-Plugins!

ValueAdapters: Andere Werte als Prozentzahlen (1..100) grafisch darstellen

Das folgende Beispiel verwendet einen Wert in Minuten statt in Prozent als darzustellenden Wert. Ein ValueAdapter konvertiert jede positive Minutenzahl in einen darzustellenden Prozentwert, nämlich den Anteil einer vollen Stunde.

ValueAdapter-Funktionen können unabhängig davon eingesetzt werden, wie der Wert selektiert wird (ob also als Elementinhalt, Attribut oder Kindelement).

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

0 5 15 20 30 35 40 45 60 80

Doppel-/Mehrfach-Torten

Betrachten wir eine Erweiterung des vorangehenden Beispiels: Das Progresspie-Plugin kann nicht nur einen Wert darstellen, sondern bis zu zwei, wobei zwei Torten gezeichnet werden, von denen die zweite mittig auf die erste positioniert wird. Zum Beispiel könnte man nun einen Stunden- und einen Minutenwert in einem solchen Kombidiagramm visualisieren. In Anlehnung an ein Zifferblatt einer 12-Stunden-Analoguhr sollte die zweite, kleinere, innere (Vordergrund-)Torte einen Stundenwert (als Teil von 12 Stunden) und die erste, größere (Hintergrund-)Torte wie gehabt einen Minutenwert (als Teil einer Stunde).

Sichtbaren Elementinhalt des Muster hh:mm parsen

Nehmen wir an, Sie haben ein Span-Element mit Inhalt im Format "Stunden:Minuten" wie

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

Diesem könnte man nun wie folgt eine solche Doppel-Torte voranstellen:

$(".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

Beachten Sie, dass dieses Beispiel einen einzigen (String-)Wert als Quelle hat, aus dem mit zwei ValueAdapter-Funktionen zwei unterschiedliche Prozentwerte abgeleitet werden. In diesem Fall erfolgt die Extraktion der Teilwerte mittels regulärer Ausdrücke.

Separate Wert-Attribute

Sie können natürlich, wenn Sie die beiden Werte (hier Stunden und Minuten) bereits als Einzelwerte „zur Hand“ haben, auch an Stelle eines einzelen Wertes beide Werte getrennt angeben, z.B. in zwei Attributen. Diese können Sie, wenn es sich um Prozentwerte handeln sollte, direkt verwenden und ansonsten mit Value-Adaptern konvertieren. Dieses Beispiel verwendet zwei Wertattribute für Stunden und Minuten:

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

Weiterhin demonstriert dieses Beispiel die manuelle Größenwahl für beide Torten:

$(".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

Beachten Sie, dass in diesem Beispiel der Stunden-Wert unabhängig vom Minutenwert abgebildet wird, die innere Torte also nur 12 verschiedene Werte (volle Stunden) anzeigen kann: Für die Zeit »1:55« z.B. füllt sie dieselbe Fläche (ein Zwölftel, d.h. eine Stunde) wir für »1:00«. Das vorhergehende Beispiel dagegen konnte die Tatsache ausnutzen, dass dem Stunden-Adapter der gesamte String samt Minutenangabe zur Verfügung stand und er so (analog zum Stundenzeiger einer Analoguhr) auch anteilige Stunden darstellen konnte: Für »1:55« wird dort fast der gleiche Stundenanteil angezeigt wie für »2:00«, die 5 Minuten Differenz sind kaum zu erkennen.

Doppelgrafiken mit Ringen

Genau wie bei Einzelgrafiken kann die Option ringWidth für eine oder beide Teilgrafiken eingesetzt werden, um einen Ring statt einer Torte zu zeigen. Gerade bei Doppelgrafiken wie oben ist die Überlappung zweier Torten sicherlich weniger schön und schlechter lesbar, als eine überlappungsfreie Darstellung, bei der zumindest der äußere Wert ein Ring ist, der sich um die innere Grafik herumlegt.

Dieses Beispiel ist eine einfache Variation des vorangehenden, indem für die äußere Grafik eine ringWidth gesetzt wurde. Dabei ist ringWidth kleiner als die Differenz zwischen den Radien beider Grafiken, so dass die innere Torte überlappungsfrei in den äußeren Ring passt. (Gesamtgröße/-durchmesser ist 30 Pixel, Durchmesser der Stunden-Torte ist 20 Pixel, Durchmesser-Differenz also 10 Pixel, Radius-Differenz 5 Pixel. ringWidth ist mit 4 Pixeln kleiner als die Radius-Differenz, was einen 1 Pixel breiten Spalt zwischen äußerem Ring und innerer Torte frei lässt.)

$(".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

Natürlich kann auch die innere Grafik als Ring gezeichnet werden:

$(".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

Drei (oder noch mehr) Werte/Ringe

Ab V2.0.0 unterstützt ProgressPieSVG nicht mehr nur zwei Ringe, sondern beliebig viele: Ein inner-Objekt darf nun selbst wieder eine inner-Option enthalten. Wenn Sie diese Möglichkeit nutzen möchten, sollten Sie Ringe statt sich überlappender Torten verwenden (wie schon bei „nur“ zwei Werten sinnvoll, vgl. vorhergehende Beispiele), indem Sie jeweils die ringWidth-Option sowohl in den Haupt-Optionen (äußerer Wert) als auch in den inner-Optionsblöcken angeben – lediglich der innerste Wert, der nicht selbst wieder einen inneren enthält, kann problemlos auch eine Torte sein. Außerdem sollten Sie die size-Option für jeden Ring angeben, um die einzelnen Ringe in einheitlichen Abständen zueinandern anzuordnen (die Automatikfunktion liefert für mehr als zwei Werte derzeit keine besonders schönen Ergebnisse).

Neben der Möglichkeit, inner-Optionen zu schachteln, werden in inner-Blöcken ab Version 2.0 auch noch mehr weitere Optionen unterstützt, insbesondere die verschiedenen stroke*-Optionen, mit denen also auch für die inneren Ringe jeweils ein Hintergrundkreis definiert werden kann.

Ein Beispiel mit drei Ringen, alle mit eigenem Hintergrundkreis (stroke*), wobei die Farben programmatisch in den Plugin-Optionen festgelegt werden:

$(".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'
        }
    }
});

angewendet auf:

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

Wie in Abschnitt CSS-Formatierung schon gezeigt, können Sie, falls Sie das vorziehen, den CSS-Modus nutzen und das Farbschema extern per CSS definieren. Das sei hier an einer Variation des obigen Beispiels demonstriert:

$(".triple2").progressPie({
    globalTitle: "Aktivität",
    title: "Bewegen",
    animate: true,
    size: 60,
    ringWidth: 6,
    strokeWidth: 6,
    mode: $.fn.progressPie.Mode.CSS,
    ringEndsRounded: true,
    valueData: 'outer',
    inner: {
        title: "Training",
        size: 45,
        mode: $.fn.progressPie.Mode.CSS,
        ringWidth: 6,
        strokeWidth: 6,
        ringEndsRounded: true,
        valueData: 'middle',
        inner: {
            title: "Stehen",
            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>

Dieses Beispiel demonstriert auch den Einsatz der title-Option für Diagramme mit mehreren Werten. Hier wird für jeden der drei Ringe ein eigener Titel festgelegt, sowie per globalTitle ein weiterer Titel für die Gesamtgrafik. Wenn Sie nun z.B. in einem Desktop-Browser, mit dem Mauscursor auf einen Ring zeigen (und etwas warten/stillhalten), so sollte der Titel des jeweiligen Rings als Tooltip eingeblendet werden. Zeigen Sie auf die schwarze Fläche, wird der globale Titel angezeigt. (Siehe Titel (Tooltip) hinzufügen)

Hinweis: Dieses Beispiel verwendet SMIL-Animationen (Seite neu laden, um diese abzuspielen – SMIL wird nicht unterstützt von Microsoft Internet Explorer oder Edge). Siehe separate Animations-Beispielseite für mehr Informationen und Beispiele zu diesem Thema.

(Hinweis 2: Dieses Beispiel wurde offensichtlich durch die Aktivitätsanzeige der Apple Watch inspiriert. Es ist jedoch keine exakte Kopie, lediglich ähnlich. Ein wesentlicher funktionaler Unterschied ist auch, dass ProgressPieSVG keine Werte größer als 100% darstellen kann.

Siehe auch Beispiel zu optionsByRawValue (unten) für ein weiteres Multi-Ring-Beispiel.

Rotations-Animation

SMIL-Animationen werden von den meisten aktuellen Browsern unterstützt – mit Ausnahme derer von Microsoft (IE, Edge).

Sie können der SVG-Grafik auch eine Animation in Form einer Drehung um den Kreismittelpunkt (per Default im Uhrzeigersinn) hinzufügen. Für eine normale Prozent-Visualisierung ist eine solche Animation sicherlich normalerweise keine gute Idee, aber mit speziell gewählten (konstanten) Werten lässt sich so z.B. eine Aktivitätsanzeige („Busy-Indicator“, Anzeige, dass etwas passiert/arbeitet, ohne Fortschrittsmessung) bauen, wie z.B.:

$('#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;}
});

In diesem Beispielen wurde jeweils eine valueAdapter-Funktion eingesetzt, die gar keinen Eingabewert konvertiert, sondern immer einen konstanten Prozentwert zurückgibt, der hier allein zu Designzwecken dient und z.B. die Größe der Lücke im rotierenden Kreis oder die Länge des dickeren Kreisabschnitts oder die Breite des rotierenden Tortenstücks beschreibt.

Die Animation wird nicht auf die gesamte SVG-Grafik angewendet, sondern nur auf die Füllung der (äußeren/hinteren) Hauptgrafik. Bei Kombination mit einer inneren zweiten Grafik, wird letztere nicht animiert. So kann man z.B. einen rotierenden Ring mit einer inneren Fortschrittsmessung (Torte) kombinieren:

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

Ein weiteres Beispiel für eine Aktivitätsanzeige mit Ergebnisrückmeldung findet sich in der Beispielseite für Content-Plugins.

Optionen auf Basis von Prozentwerten variieren

Normalerweise legen Sie eine Menge von Optionen fest, die das Aussehen einer Torten-/Ringgrafik bestimmen, und zwar unabhängig vom jeweils anzuzeigenden Prozentwert. Eine Ausnahme ist die Farboption color, der Sie wie oben beschrieben auch eine Funktion zuordnen können, die abhängig vom Prozentwert eine Farbe bestimmt.

Vielleicht genügt Ihnen das nicht und Sie möchten gerne auch andere Optionen variabel abhängig vom Prozentwert definieren. Beispielsweise könnten Sie festlegen, dass, so lange der Prozentwert kein einziges Mal inkremetiert wurde, sondern noch 0 beträgt, statt einer komplett leeren Torte eine rotierende Warteanimation (siehe oben) angezeigt werden soll.

Für statische Werte können Sie einfach das Plugin mit verschiedenen Werten aufrufen. Auch obiges Animationsbeispiel zeigt einen Weg, dynamisch Aspekte wie die Größe einer Grafik zu ändern, indem die Optionen bei jedem Update neu berechnet und neu ans Plugin übergeben werden. Aber falls Sie einfach einmalig ein Regelwerk mit Hilfe der setupProgressPie-Funktion definieren möchten, definieren Sie zunächst eine Menge von Default-Optionen und eine Regel-Funktion, die wertabhängige Abweichungen von diesen Defaults definiert. Diese Funktion übergeben Sie in der Option optionsByPercent. Sie nimmt einen Prozentwert entgegen und gibt entweder null aus (wenn sie nichts überstimmen will) oder ein Optionsobjekt mit den vom Standard abweichenden Optionen.

Das folgende Beispiel legt einige Default-Optionen für ein Tortendiagramm fest und definiert eine Option, die für den Wert 0% abweichend einen rotierenden Ring beschreibt und für alle größeren Werte die Defaultoptionen unverändert lässt, indem sie null zurückgibt:

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 %

Optionen auf Basis von Rohwerten variieren

Hinweis: Das folgende Beispiel kombiniert diverse verschiedene Themen, insb.: Mehrfache Ring-/Tortendiagramme für (in diesem Fall) drei Werte, s.o., Content-Plugins und SMIL-Animationen. Der Hauptzweck des Beispiels ist jedoch die Demonstration der Option optionsByRawValue.

Im vorigen Abschnitt wurde mit optionsByPercent eine Möglichkeit vorgestellt, die Diagrammoptionen in Abhängigkeit des dargestellten Prozentwerts zu variieren. Es gibt aber Situationen, in denen ein (per Value-Adapter berechneter Prozentwert) nicht mehr für diesen Zweck geeignet ist, sondern die Entscheidung nur auf Basis des (abweichenden) Rohwerts getroffen werden kann.

In solchen Fällen nutzen Sie einfach die ähnliche Option optionsByRawValue. Beachten Sie dabei jedoch, dass der dieser Funktion übergebene Rohwert – im Gegensatz zum vom Value-Adapter berechneten Prozentwert, der der optionsByPercent-Funktion übergeben wird – nicht grundsätzlich vom Typ "number" ist! Viele Werte – insbesondere solche, die aus einem Attribut gelesen wurden – sind üblicherweise vom Typ "string". Genau wie eine Value-Adapter-Funktion muss also auch die optionsByRawValue-Funktion den Typ des Arguments überprüfen und ggf. eine Typkonvertierung vornehmen!

Im folgenden Beispiel bestehen die Diagramme jeweils aus zwei Ringen und einer Torte im Inneren. Alle drei Teildiagramme leiten ihren jeweiligen Prozentwert mittelts verschiedener Value-Adapter aus ein und demselben Rohwert ab. Der Diagrammtyp stellt einen Countdown dar, und der Rohwert ist die Anzahl der noch verbleibenden Sekunden. Aus diesem Rohwert werden drei Prozentwerte für verbleibende Stunden, Minuten und Sekunden abgeleitet: Die innere Torte zeigt die noch verbleibende Gesamtzeit in Stunden, d.h. eine voll gefüllte Torte steht für eine Wartezeit von 12 (oder mehr) Stunden. Der mittlere Ring zeigt die in der laufenden Stunde noch verbleibenden Minuten, der dünne äußere Ring die in der laufenden Minute noch verbleibenden Sekunden. Das Diagrammlayout ist damit angelehnt an eine normale Analoguhr, bei der der dünnste, längste Zeiger die Sekunden, der zweitdünnste und zweitlängste Zeiger die Minuten und der kürzeste und dickste Zeiger die Stunden anzeigt.

Beträgt der Countdown nur noch eine Minute (60 Sekunden) oder weniger, so ist von der inneren Stunden-Torte schon lang effektiv nichts mehr übrig. Statt dessen soll im Inneren nun eine Sekunden-Digitalanzeige eingeblendet werden. (Dazu wird das Value-Display-Content-Plugin verwendet, das auf der Content-Plugin-Beipspielseite genauer vorgestellt wird.) Die Entscheidung, ob dieses Content-Plugin geladen werden soll oder nicht, kann nicht vom Prozentwert des Sekundenrings abgeleitet werden, da dieser ja minütlich wieder auf 100% zurückgesetzt wurd. Vom Rohwert (absolut verbleibende Sekunden) ist sie jedoch ganz einfach ableitbar: Das Plug-in soll gezeigt werden, sobald dieser Rohwert ≤ 60 ist. Daher wird hier eine optionsByRawValue-Routine verwendet.

Eine Sekunde, nachdem der Countdown auf 0 angekommen ist (also sobald der Rohwert negativ wird), nimmt die optionsByRawValue-Funktion eine weitere Konfigurationsänderung vor und aktiviert eine „Busy-Anzeige“ in Form eines rotierenden halb-gefüllten Sekundenrings. (Da der Rohwert somit auch negativ werden kann, wurden die Value-Adapter-Funktionen für alle drei Teildiagramme ebenso wie die Label-Funktion, die aus dem Roh-Sekundenwert eine neben dem Diagramm eingeblentete Stunden-Minuten-Sekunden-Anzeige berechnet, so geschrieben, dass sie mit negativen Werten umgehen können und dann jeweils als Ergebnis "0%" ausgeben.)

Der folgende Code-Auszug enthält nicht nur das ProgressPie-Setup selbst, sondern darüber hinaus auch noch eine Label-Funktion für eine Digital-Anzeige des Countdowns, einen Timer für einen Live-Countdown und Code für das User-Interface zur Wertänderung des Live-Beispiels. Damit all diese Definitionen nicht den globalen Namensraum „vollmüllen“, obwohl sie nur lokal gebraucht werden, wurde ihre Deklaration in eine Immediately Invoked Function Expression eingebettet.

(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:

^