progresspieSVG

jQuery plug-in for dynamically rendering a pie or circle diagram comparable to a progress bar, depicting a progress, countdown, percent value or similar.

Project home page

What is this?

This software module contains a jQuery plug-in for drawing a partially filled circle (pie-chart with only one slice of the pie) for visualizing a single value between 0% and 100% inclusive, i.e. a kind of progress bar, but not in form of a bar but of a pie. The graphic is rendered inside a web page as SVG. In difference to e.g. the HTML canvas element, SVGs are scalable and render sharply on high resolution displays with device-pixel-ratio > 1 (e.g. Apple’s “retina displays”).

As the name suggests, this component may be used to display a progress, starting at 0%, incrementing until 100% are reached. For this purpose the graphic may be dynamically updated (or, more precisely, replaced).

But just like progress bars these pies may actually be used to depict any percentual value, including static ones like e.g. percents of points achieved in a test. Mainly for this purpose, the pie may be dynamically colored based on the percentual value with colors like red hinting at a “bad” result, yellow for “mediocre” and green for “good”. There are default color schemes (always grey, green or red or dynamically calculated red/yellow/gree-shade as described above), but you may also assign any static color or your own JavaScript function mapping the value into a color.

This jQuery-Plug-in supports a wide range of options for customizability, so you may style the pie or ring charts in various ways, define value adapter functions for converting any raw value into a percent value to be displayed, even render more than one value in one chart (typically by arranging smaller rings or pies inside one outer ring). A content plug-in architecture allows for additional content to be added to a chart, like control icons, error or warning icons (e.g. if the diagram is used to depict the progress of some job which will not always terminate successfully but might produce errors or warnings), background icons, value display etc. Various content plug-ins are included (see separate example page), and you can also create your own ones.

The basic usage is to add static charts to a page already containing the values, so these get displayed graphically. If the value is not static but the user’s input in a form field, the plug-in can automatically update the chart when the input’s value changes.

Via JavaScript, it’s also possible to dynamically updated charts (even with smooth transition/animation), e.g. for building a real progress indicator for some process running in the background (maybe even a server’s progress monitored by Ajax status requests).

Examples

See the examples pages to get an impression of the looks and for different demo scenarios.

You’ll also find an online live view of these examples on the project’s home page.

JavaScripts

This package contains several JavaScript files.

  1. The script files in folder js are the source files. Please note that—starting with version 2.4.0—these use ECMAScript-6-Syntax and are not compatible with older browsers wich only support up to ECMAScript 5! For better browser compatiblity use the following minified versions!
  2. The folder js/min contains the production versions. These have been transpiled (with Babel) to ECMAScript 5 and minified (with UglifyJS), so they are smaller and may be run on more, older browsers that the source scripts.

The individual script files (file names of source versions, production versions' names end with -min.js):

Changes in V2.0.0, backwards compatibility

Version 2 mostly adds new features like especially:

But some changes have been made which could affect backwards compatibility in a few cases. This is the main reason for the major version increase (see [semantic versioning][https://docs.npmjs.com/getting-started/semantic-versioning]): When updating to V2.0.0, you should make sure the following changes don’t affect your current uses, otherwise you might have to (slightly) change them.

Changes like having a separator only separate the newly inserted and old content and not (any more) adding a ‘separator’ that’s actually not separating anything, these are more kind of a fix than a new feature. They IMHO make sense, but sadly they affect backwards compatibility. Other than that, I’ve strived to retain backwards compatibility as far as possible, and most users won’t probably have to change anything.

Usage

Direct usage of the plug-in (without progresspiesvgAppl.js)

Basics

Options

If you simply call progressPie(), the plug-in will be used with default options. This includes that the percent number is expected to be the (only) content of the selected element, the pie will be prependet to this content (separated with an  ), it will be rendered in line-height and in a shade of grey (#888). It will only be inserted, if the element does not yet contain any SVG content: repetetive calling of the function will therefore neither insert the SVG multiple times nor will it update the graphic.

To modify the looks or behaviour, the function takes exactly one argument, which has to be a JavaScript object which defines options via its properties. The following option properties are defined:

Dynamically updating pies

The default usage is to have some static percent values (or even other kinds of values which can be transformed to a percent value using a value adapter function, see options / examples) and to insert pie graphs visualizing those values.

But of course your values might get updated (via JavaScript). If that happens, the derived pie charts are not automatically updated too, but your script code updating the values has to trigger a pie update as well.

In fact, the existing SVG code does not really get updated (meaning: modified), but completely replaced by a newly generated SVG image.

In order to redraw a pie, you might simply use usual $(target).progressPie({options...}) call, repeating the options all over. But if you do that, pay attention to the update option: If you leave it set to false, existing graphics won’t be replaced, but only missing graphics will be drawn:

But usually, the options should stay constant and only the displayed value changes. In this case, it’s best not to repeat the options with each update call.

Therefore, the recommended way is to setup the options once before first drawing the pie(s) (using the setupProgressPie() function) and then to redraw it (them) by only calling the parameterless progressPie() function (see section Basics above). If you do that, you also don’t have to bother thinking about the update option: When you use setupProgressPie() and don’t specify the update option, it automatically defaults to true, meaning each parameterless progressPie() call will update existing pies.

Have a look at the examples page to see updates in action.

Since version 2.0.0, updates may also use transitions, such that the update triggers an animation smoothly increasing (or decreasing) the pie or ring chart’s state starting from the old value (before the update) and ending with the current value. (SMIL animations are not supported by all browsers, especially neither Microsoft Internet Explorer nor Edge support them. The charts will sill be updated on those browsers, only the animation will be missing.) To use animation, simply add the animate option, maybe combined with the animateColor option, see above, to the setup.

See the separate examplesAnimation.html page for demonstration.

Overwriting default options

Writing your own color function

As described above, by simply setting the option {mode: $.fn.progressPie.Mode.COLOR}, the color of the pie get dynamically calculated based on the percent value, and the colors used for that are in some degree customizable via overwriting $.fn.progressPie.Mode.GREEN.value or …RED.value.

But if you want more flexibility in dynamically setting a color, you may provide your own JavaScript function which receives the percent value as parameter (number) and has to return a string describing the color (like #3bf or rgb(100,255,100)).

You could simply overwrite the function $.fn.progressPie.colorByPercent. This way your function would always be applied for any pie rendered in COLOR mode.

But the more flexible way is to write one or more own color functions and apply them individually to (classes of) pies instead of using the default COLOR mode, which is then still available.

Simply write your function and then set a reference to it in the options passed to the options, like in:

<script type="text/javascript">
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() {
  $(".test.myblue").progressPie({color:blueGt25});
});
</script>

The example above defines a color function which sets the pie color to black for all values of 0% to 25% inclusive. For values greater than 25% the color is blue: an rgb code with red and green values of 0 and a blue component growing brighter with the percent value up to 225 (a little darker than the brightest blue (255)).

Of course, a color function may also be embedded inline in the options object, if it’s not needed elsewhere. The following example defines an inline function setting one (greenish) color for values starting at 50% and another color (reddish) for lower values:

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

Last but not least you may reuse the internal color function $.fn.progressPie.colorByPercent within your own color function instead of calculating a color code all by yourself: Let’s say, you want all values between 0% and 50% to be drawn in the same red and apply the default COLOR scheme only for values starting at 50% (green for 100%, yellow for 75%, red for 50%). This could be done the following way:

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

valueAdapters and double/multiple pies

If the source value to be visualized as filled circle (pie) is not a percent value (0..100), you may write your own adapter function for mapping the actual values (any string) to a percent number (any number in [0..100], may be int or float). This mapping might be of arithmetic nature (e.g. converting a value of 0 to 60 minutes into a percent number) or of syntactic nature (e.g. extracting a percent number out of a string also containing other characters)—or both. Use the valueAdapter option (see above) to specify your adapter function. (The default value adapter is a function returning any number input unchanged, parsing any string input via parseFloat, and otherwise returning 0.)

If you want to display two values in one graphic (e.g. hours and minutes), that’s also possible—not as simple to read/understand at first glance, though. Use the inner option (see above) to specify that and how a second, inner pie should be generated. By adding yet another inner options into the first inner option, you may even add a third value and so on.

The examples page examples.html contains demonstrations for both options.

Note: These features are only available with direct use of jquery-progresspiessvg.js and not via progresspiesvgAppl.js.

Simplified usage via progresspiesvgAppl.js

If you prefer not to write your own JavaScript-/jQuery-Code in order to apply the progresspie plug-in to selected elements of your choice, you may use this additional JavaScript file. It is a default application of the plug-ins to elements which must meet some conventions.

If you include this script into an HTML document, each HTML element of class progresspie is fitted with a pie chart. This requires the element (which is usually an inline element like a span) to contain a number from 0 to 100 (inclusive) as its only content or alternatively in an attribute named data-percent.

By default the pie is grey. By adding an additional class color, red or green you get a dynamically colored resp. statically red or green pie. (These classes must not be combined and activate the corresponding plug-in mode COLOR, RED or GREEN respectively.)
Adding the class vcenter activates vertical centering, otherwise the graphic is aligned with the bottom of the element.

For user-defined color you may either add an attribute data-piecolor defining a static color code or an attribute data-piecolor-function providung a string which evaluates to a function mapping a number (range 0..100) to a color code.

For adding a pie to an input element with auto-updating the pie when the inputs value changes, use the data-input attribute. Its value has to be a jQuery selector for the input which is to provide the percent value. (Note: This simple application script only supports updating on the change event, only can read plain percent numbers and does not support error messages for illegal values. For more features, you’ll have to use the full-featured jQuery plug-in.)

SVG Content plug-ins

The progresspieSVG jQuery plug-in provides a private plug-in mechanism itself, which may be used to plug additional drawing logic into the main plug-in, adding SVG content to the pie or ring chart.

To apply a content plugin, add the option contentPlugin to the argument object you pass to the jQuery plug-in. The value of this option is either a reference to a javascript function (conforming to the plug-in API as described below), or simply the name of a function as a string. In the latter case the function must be member of the namespace jQuery.fn.progressPie.contentPlugin. Only then it can be looked up by its name. This is the recommended namespace for any content plug-in.

A content plug-in may itself be configured by an object defining options. Any properties defined in an object passed to the jQuery progress pie plug-in via its option contentPluginOptions will be passed along to the content plug-in specified by contentPlugin.

You may also apply more than one content plug-in: In this case, the contentPlugin option as well as the contentPluginOptions option have to be arrays of the same size: The contentPlugin array enumerates the names of the content plug-ins to apply (in that order), and the contentPluginOptions array has to hold the options object for the plug-in with the corresponding index.

Content plug-ins may draw into the foreground or into the background. Each content plug-in’s output is inserted as a new layer into the SVG image: A plug-in drawing into the foreground inserts a new layer on top of all already existing layers (i.e. if you enumerate more than one foreground-plug-in in the contentPlugin option array, the first one gets put on top of the chart, the second one on top of the first etc.). A plug-in drawing into the background inserts a new layer behind any previously existing (i.e. if you enumerate more than one background-plug-in, the first one’s output will be placed directly behind the chart, the second one’s behind the first one’s etc.).

Should you use the MASK or IMASK mode, the pie will not be inserted as a layer (between background and foreground plug-in’s layers) but will be applied as a mask to the first (topmost) background layer.

See separate examples page on content plug-ins for demonstrations.

Bundled content plug-ins

Control Icons

jquery-progresspiesvg-controlIcons.js is a script file defining three such content plug-ins play, stop and pause for drawing media control icons (a right-pointing triange, square or two parallel vertical rectangles, resp.) inside a ring graph.

By default, the play-, pause or stop icon is drawn in the same color as the pie/ring chart itself. If combined with a ring chart (i.e. option ringWidth is set, see above), it is auto-sized to fit inside the ring, otherwise it’s drawn on top of the pie and auto-sized to fit into the outer circle stroke. These defaults may be overridden by the following options (defined as properties of an object assigned to the contentPluginOptions option):

See the content plug-ins example page for demonstrations of the plug-in and its options.

Check if complete

jquery-progresspiesvg-checkComplete.js is a script file defining a single content plug-in (checkComplete). This plug-in will draw a check mark onto a fully filled pie or into a fully closed ring (i.e. on a graph visualizing a 100% value). It won’t add any content for lower values.

See the content plug-ins example page for demonstrations of the plug-in and its options.

Error icons

Imagine you set up a pie graph for visualizing the progress of a running job of your web application. You set it up once (per setupProgressPie()) to configure the looks of the pie itself and you might add the checkComplete-Plugin described above to draw a checkmark on green ground as soon as the job is completed successfully.

But maybe the job could also terminate with an error or a warning, and in these cases you would want neither the green check mark for success nor a frozen pie chart which looks like it depicts a still running job. Instead you might want to change the graph into an error or warning icon similar to the white check on green background, e.g. a white cross or exclamation mark on red or green background.

This error icons plug-in serves exactly this purpose. In difference from checkComplete, which gets setup at the beginning to show the icon as soon as the progress value reaches 100%, an error or warning icon has to be added retrospectively by an error event handler function or similar means.

If you have loaded this plug-in script file, your event handler may show a cross or exclamation mark inside a ring or on a fully filled pie, the exclamation mark may also be rendered onto a triangle hovering on top of the pie or ring graph (or inside the ring). The icon may be drawn on a colored background (e.g. red or yellow) covering the pie or ring chart completely (just like the check mark), or it may be rendered on top of a pie (without opaque background) or inside the ring, if you want the job’s progress at the time the error occurred to still be visible.

See content plug-in example page for demonstrations (and JSDoc for details on all options).

Value Display

jquery-progresspiesvg-valueDisplay.js is a script file defining content plug-ins for drawing a value inside a ring graph.

This script defines two content plug-ins: percent and rawValue. Both are designed to be combined with ring charts (i.e. usage of the progressPie plug-in with the ringWidth option set) and draw a number (value) and optionally a unit label into the ring. The percent plug-in always renders a percent value (0..100).

If the chart is defined with other than percent values and a valueAdapter function is used to convert the raw value to a percent value, then the percent plug-in will render the result of the valueAdapter function, while the rawValue plug-in will draw the unconverted, raw value. The percent plug-in always adds the label “%” to the value, while the rawVale plug-in takes a unit argument defining an optional label to append to the value.

The plug-ins accept the following options (defined via contentPluginOptions):

Instead of passing an individual options object to the progressPie plugin via its contentPluginOptions option, you may also globally alter the defaults by manipulating the object $.fn.progressPie.contentPlugin.valueDisplayDefaults.

See the content plug-ins example page for demonstrations of the plug-in and its options.

Image

jquery-progresspiesvg-image.js is a script file defining a content plug-in for inserting an external image as additional layer to the chart. The image may be used as background image or placed on top of the chart in the foreground (as do the other plug-ins above). If the image covers areas outside the actual chart’s circle, it may optionally be clipped to that circle or it may be allowed to draw outside of it. In the latter case, the padding option of the chart may be used to even enlarge the area outside of the chart that may be filled with the image.

The image is automatically scaled to fit into the target area. If it is wider than the target area, then it will be horizontally centered in the higher area, leaving equally sized transparent stripes above and under the image. If the image is higher than the target area, it will be horizontally centered, leaving transparent gaps to the left and to the right.

The target area is defined as follows:

The plug-in accepts the following options (via contentPluginOptions):

Some use cases

Background Rectangle

Adds a background layer to the chart filled with a rectangle. You may define a stroke and / or filling for the rectangle, so this may be used to add a rectangular border around the chart or the background may be filled with a solid or semi-transparent color. Yet this is primarily meant to be combined with background images, for example you might add a semi-transparent rectangular layer on top of a background image layer and the chart may be used as a mask for this rectangle. See examples page for demonstration.

The rectangle covers a target area which is exactly the same as the image plug-in’s target area, see above.

The plug-in accepts the following options (via contentPluginOptions):

At least on of the options stroke or fill has to be specified.

Writing your own content plug-ins (API)

You may create you own content plug-in:

With the older version of this API (of ProgressPieSVG V1.x), a content plug-in is simply a single function for drawing the content. Sine V2.0.0, ProgressPieSVG supports an extended API where your plug-in is an object consisting of a draw method for drawing the content and optional further methods for controlling whether the content should be drawn into the foreground (on top of the chart, default) or in the background (with the chart on top), or even whether the chart should be drawn at all in case the content plug-in is full sized.

The plug-in function resp. object should be in the namespace jQuery.fn.progressPie.contentPlugin. If it is, the user may simply state the its name as a string literal in the contentPlugin option. Otherwise the options needs to hold a JavaScript reference to the content plug-in (function or object).

Just like when writing jQuery plug-ins, you may locally bind the $ sybol to jQuery in an immediately invoked function expression like (old API):

( function($) {
    $.fn.progressPie.contentPlugin.yourPlugin = function(args) {
        …
    }
} (jQuery));

A plug-in using the new API could look something like this:

( function($) {
    $.fn.progressPie.contentPlugin.yourPlugin = {
        draw: function(args) {
            …
        },
        hidesChartIfFullSize: function(args) {
            …
        }
} (jQuery));

The draw method

The draw function of your object (new API) resp. your plug-in function (old API) has to take exactly one argument (let’s assume you call the formal parameter args like in the examples above). When the draw function gets called by ProgressPieSVG, this parameter will hold an object with at least the following methods and properties:

Methods of the parameter object
Properties of the parameter object

In addition to these properties, the args object will hold any property the user added to the contentPluginOptions object. If your plug-in should define its own properties (such as the fontSizeFactor option of the Value Display content plug-in described above), simply document these and the user of your content plug-in may insert these options into the contentPluginOptions.

After evaluating these arguments, your draw function may now insert SVG elements (using the newSvgElement function and maybe also newSvgSubelement). For positioning these elements, you need to know the origin of the coordinate system: The point (0, 0) refers to the center of the circle!

As a very simple example, the following function describes a content plug-in which simply draws a filled square inside the ring graph (or on top of a pie graph) in the same color and with a side length which equals the radius of the circle. So, since (0, 0) is the circle’s center and the square should be circled and radius is the width and height of the square, its top left corner has to be located at the coordinates (-radius/2, -radius/2):

( function($) {
    $.fn.progressPie.contentPlugin.mySquare = {
        draw: function(args) {
            var square = args.newSvgElement("rect");
            var topleft = - args.radius / 2;
            square.setAttribute("x", topleft);
            square.setAttribute("y", topleft);
            square.setAttribute("width", args.radius);
            square.setAttribute("height", args.radius);
            square.setAttribute("style", "fill: " + args.color + "; stroke: none");
        }
    }
} (jQuery));

Have a look at the source code of the included content plug-ins for more examples.

The inBackground method (or field)

The content plug-in object may contain a property named inBackground which must be either a boolean field or a boolean method (function which returns a boolean). If it’s a method, it gets the same parameter object as the draw method does and can return true or false dependent on this parameter.

If the function returns true (resp. the field is constantly true), the output of your content plug-in will be drawn in the background of the SVG, e.g. the generated pie or ring chart will be drawn on top of your plug-in’s content. Otherwise (which is the default, also if you don’t implement this method/field at all), your plug-in’s output will be drawn in the foreground, on top of the rendered chart.

The hidesChartIfFullSize method

With the new API, your plug-in may optionally implement a second method (function property) called hidesChartIfFullSize, also taking one argument object as parameter.

If you implement this, it gets called before the actual progressPie chart is drawn (and before the draw method is called).

It gets called only under the following circumstances:

I.e. if the user wants to draw a progress ring, to use your content plug-in without a fullsize option, it is assumed that your content plug-in always fits its content into the ring, thus the hidesChartIfFullSize method is never applied.

(See also the isFullSize() function of the draw method’s arguments object: The latter will return true under the exact same conditions.)

If the above preconditions are met (typeof ringWidth === 'undefined' || contentPluginOptions.fullsize) and your content plug-in’s hidesChartIfFullSize() method returns true (or any truthy value), then and only then the actual progress pie or ring will not be rendered at all, the content plug-in’s draw() method will be called and will be the only code generating SVG content.

So what is this good for?

A typical application of suppressing the rendering of the actual chart is any case where the content plug-in’s output would completely cover/occlude the chart anyway (typically by calling args.addBackgound(args.getBackgroundRadius()) with the aforementioned fullsize option or in pie mode). In this case, this mainly keeps the generated SVG slimmer (why render output that will always stay invisible?). But there is also another effect: Assume your pie chart would be drawn in a rather dark color (black, navy, …) and a content plug-in (e.g. the exclamationMark plug-in) adds a rather light (e.g. yellow) filled circle on top of that, then this light disc should cover the dark pie completely—theoretically. But practically, probably due to anti-aliasing of the circle’s outlines, most browsers would actually show a slight dark edge around the light disc, a sort of unwanted halo effect. This was visible with Version 1 of the progressPie plug-in and its included checkComplete-, error- and exclamationMark content plug-ins and was addressed by adapting these content plug-ins to this new API.

How should the method be implemented?

Usually you should make sure to only return true (and thus eliminate the actual chart completely) if you are absolutely certain, your draw method would otherwise completely occlude the chart anyway (except for the potential ‘halo’). Have a look at the content plug-ins error and exclamationMark in jquery-progresspiesvg-errorIcons.js: These check, that the user really configured a background color and that the color code does not start with rgba (in which case it would probably draw a semi-transparent background not completely occluding the chart). Also they check that no margin option is set which would reduce the size of the configured background and leave some of the chart visible.

Note: If you implement the inBackground method, you should also make sure that not both (inBackground and hidesChartIfFullSize) return true simultaneously for the same options. At least it would not make much sense to explicitly put your output into the background of a chart that will not be drawn at all. That’s why the error icons plug-ins, for example, make sure that hidesChartIfFullSize will never return true if inBackground returns true, i.e. that a chart can only be hidden by an icon in its foreground, not by its background.

The warning content plug-in in the same file is a different example: The triangular warning sign will never completely occlude a circular chart, but this plug-in explicitly introduces an option for the user to configure whether he wants his warning sign to be a layer on top of the chart or whether he wants the warning sign alone, without a chart in the background.

Properties of the parameter object

The hidesChartIfFullSize method also takes a parameter argument with information probably needed to decide whether to answer with true or false.

Since this method is called earlier in the whole process than the draw method is, it gets only a subset of the information (properties), also the methods of the draw method’s parameter are neither available nor needed here.

The following properties are passed to the hidesChartIfFullSize method (as properties of its sole parameter):

The semantics of these properties are the same as in the draw methods argument, see above.

License: BSD 2-clause

Copyright (c) 2015, Immo Schulz-Gerlach, www.isg-software.de
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.