Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jquery-circle-progress

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jquery-circle-progress - npm Package Compare versions

Comparing version 1.1.4 to 1.2.0

.npmignore

50

bower.json
{
"name": "jquery-circle-progress",
"version": "1.1.4",
"authors": [
"Rostyslav Bryzgunov <kottenator@gmail.com>"
],
"description": "Plugin to draw animated circular progress bars",
"license": "MIT",
"main": "dist/circle-progress.js",
"keywords": [
"jquery",
"canvas",
"progress-bar"
],
"homepage": "https://kottenator.github.io/jquery-circle-progress/",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"tests"
],
"dependencies": {
"jquery": "*"
},
"devDependencies": {
"qunit": "1.15.0",
"modernizr": "*"
}
"name": "jquery-circle-progress",
"version": "1.2.0",
"authors": [
"Rostyslav Bryzgunov <kottenator@gmail.com>"
],
"description": "Plugin to draw animated circular progress bars",
"license": "MIT",
"main": "dist/circle-progress.js",
"keywords": [
"jquery",
"canvas",
"progress-bar"
],
"homepage": "https://kottenator.github.io/jquery-circle-progress/",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"tests"
],
"dependencies": {
"jquery": "*"
}
}

@@ -1,439 +0,560 @@

/*
jquery-circle-progress - jQuery Plugin to draw animated circular progress bars
/**
* jquery-circle-progress - jQuery Plugin to draw animated circular progress bars:
* {@link http://kottenator.github.io/jquery-circle-progress/}
*
* @author Rostyslav Bryzgunov <kottenator@gmail.com>
* @version 1.2.0
* @licence MIT
* @preserve
*/
// UMD factory - https://github.com/umdjs/umd/blob/d31bb6ee7098715e019f52bdfe27b3e4bfd2b97e/templates/jqueryPlugin.js
// Uses CommonJS, AMD or browser globals to create a jQuery plugin.
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = function(root, jQuery) {
if (jQuery === undefined) {
// require('jQuery') returns a factory that requires window to
// build a jQuery instance, we normalize how we use modules
// that require this pattern but the window provided is a noop
// if it's defined (how jquery works)
if (typeof window !== 'undefined') {
jQuery = require('jquery');
} else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
// Browser globals
factory(jQuery);
}
})(function($) {
/**
* Inner implementation of the circle progress bar.
* The class is not exposed _yet_ but you can create an instance through jQuery method call.
*
* @param {object} config - You can customize any class member (property or method).
* @class
* @alias CircleProgress
*/
function CircleProgress(config) {
this.init(config);
}
URL: http://kottenator.github.io/jquery-circle-progress/
Author: Rostyslav Bryzgunov <kottenator@gmail.com>
Version: 1.1.4
License: MIT
*/
(function($) {
function CircleProgress(config) {
this.init(config);
}
CircleProgress.prototype = {
//--------------------------------------- public options ---------------------------------------
/**
* This is the only required option. It should be from `0.0` to `1.0`.
* @type {number}
* @default 0.0
*/
value: 0.0,
CircleProgress.prototype = {
//----------------------------------------------- public options -----------------------------------------------
/**
* This is the only required option. It should be from 0.0 to 1.0
* @type {number}
*/
value: 0.0,
/**
* Size of the canvas in pixels.
* It's a square so we need only one dimension.
* @type {number}
* @default 100.0
*/
size: 100.0,
/**
* Size of the circle / canvas in pixels
* @type {number}
*/
size: 100.0,
/**
* Initial angle for `0.0` value in radians.
* @type {number}
* @default -Math.PI
*/
startAngle: -Math.PI,
/**
* Initial angle for 0.0 value in radians
* @type {number}
*/
startAngle: -Math.PI,
/**
* Width of the arc in pixels.
* If it's `'auto'` - the value is calculated as `[this.size]{@link CircleProgress#size} / 14`.
* @type {number|string}
* @default 'auto'
*/
thickness: 'auto',
/**
* Width of the arc. By default it's auto-calculated as 1/14 of size, but you may set it explicitly in pixels
* @type {number|string}
*/
thickness: 'auto',
/**
* Fill of the arc. You may set it to:
*
* - solid color:
* - `'#3aeabb'`
* - `{ color: '#3aeabb' }`
* - `{ color: 'rgba(255, 255, 255, .3)' }`
* - linear gradient _(left to right)_:
* - `{ gradient: ['#3aeabb', '#fdd250'], gradientAngle: Math.PI / 4 }`
* - `{ gradient: ['red', 'green', 'blue'], gradientDirection: [x0, y0, x1, y1] }`
* - `{ gradient: [["red", .2], ["green", .3], ["blue", .8]] }`
* - image:
* - `{ image: 'http://i.imgur.com/pT0i89v.png' }`
* - `{ image: imageObject }`
* - `{ color: 'lime', image: 'http://i.imgur.com/pT0i89v.png' }` -
* color displayed until the image is loaded
*
* @default {gradient: ['#3aeabb', '#fdd250']}
*/
fill: {
gradient: ['#3aeabb', '#fdd250']
},
/**
* Fill of the arc. You may set it to:
* - solid color:
* - { color: '#3aeabb' }
* - { color: 'rgba(255, 255, 255, .3)' }
* - linear gradient (left to right):
* - { gradient: ['#3aeabb', '#fdd250'], gradientAngle: Math.PI / 4 }
* - { gradient: ['red', 'green', 'blue'], gradientDirection: [x0, y0, x1, y1] }
* - image:
* - { image: 'http://i.imgur.com/pT0i89v.png' }
* - { image: imageObject }
* - { color: 'lime', image: 'http://i.imgur.com/pT0i89v.png' } - color displayed until the image is loaded
*/
fill: {
gradient: ['#3aeabb', '#fdd250']
},
/**
* Color of the "empty" arc. Only a color fill supported by now.
* @type {string}
* @default 'rgba(0, 0, 0, .1)'
*/
emptyFill: 'rgba(0, 0, 0, .1)',
/**
* Color of the "empty" arc. Only a color fill supported by now
* @type {string}
*/
emptyFill: 'rgba(0, 0, 0, .1)',
/**
* jQuery Animation config.
* You can pass `false` to disable the animation.
* @see http://api.jquery.com/animate/
* @type {object|boolean}
* @default {duration: 1200, easing: 'circleProgressEasing'}
*/
animation: {
duration: 1200,
easing: 'circleProgressEasing'
},
/**
* Animation config (see jQuery animations: http://api.jquery.com/animate/)
*/
animation: {
duration: 1200,
easing: 'circleProgressEasing'
},
/**
* Default animation starts at `0.0` and ends at specified `value`. Let's call this _direct animation_.
* If you want to make _reversed animation_ - set `animationStartValue: 1.0`.
* Also you may specify any other value from `0.0` to `1.0`.
* @type {number}
* @default 0.0
*/
animationStartValue: 0.0,
/**
* Default animation starts at 0.0 and ends at specified `value`. Let's call this direct animation.
* If you want to make reversed animation then you should set `animationStartValue` to 1.0.
* Also you may specify any other value from 0.0 to 1.0
* @type {number}
*/
animationStartValue: 0.0,
/**
* Reverse animation and arc draw.
* By default, the arc is filled from `0.0` to `value`, _clockwise_.
* With `reverse: true` the arc is filled from `1.0` to `value`, _counter-clockwise_.
* @type {boolean}
* @default false
*/
reverse: false,
/**
* Reverse animation and arc draw
* @type {boolean}
*/
reverse: false,
/**
* Arc line cap: `'butt'`, `'round'` or `'square'` -
* [read more]{@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.lineCap}.
* @type {string}
* @default 'butt'
*/
lineCap: 'butt',
/**
* Arc line cap ('butt', 'round' or 'square')
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.lineCap
* @type {string}
*/
lineCap: 'butt',
/**
* Canvas insertion mode: append or prepend it into the parent element?
* @type {string}
* @default 'prepend'
*/
insertMode: 'prepend',
//-------------------------------------- protected properties and methods --------------------------------------
/**
* @protected
*/
constructor: CircleProgress,
//------------------------------ protected properties and methods ------------------------------
/**
* Link to {@link CircleProgress} constructor.
* @protected
*/
constructor: CircleProgress,
/**
* Container element. Should be passed into constructor config
* @protected
* @type {jQuery}
*/
el: null,
/**
* Container element. Should be passed into constructor config.
* @protected
* @type {jQuery}
*/
el: null,
/**
* Canvas element. Automatically generated and prepended to the {@link CircleProgress.el container}
* @protected
* @type {HTMLCanvasElement}
*/
canvas: null,
/**
* Canvas element. Automatically generated and prepended to [this.el]{@link CircleProgress#el}.
* @protected
* @type {HTMLCanvasElement}
*/
canvas: null,
/**
* 2D-context of the {@link CircleProgress.canvas canvas}
* @protected
* @type {CanvasRenderingContext2D}
*/
ctx: null,
/**
* 2D-context of [this.canvas]{@link CircleProgress#canvas}.
* @protected
* @type {CanvasRenderingContext2D}
*/
ctx: null,
/**
* Radius of the outer circle. Automatically calculated as {@link CircleProgress.size} / 2
* @protected
* @type {number}
*/
radius: 0.0,
/**
* Radius of the outer circle. Automatically calculated as `[this.size]{@link CircleProgress#size} / 2`.
* @protected
* @type {number}
*/
radius: 0.0,
/**
* Fill of the main arc. Automatically calculated, depending on {@link CircleProgress.fill} option
* @protected
* @type {string|CanvasGradient|CanvasPattern}
*/
arcFill: null,
/**
* Fill of the main arc. Automatically calculated, depending on [this.fill]{@link CircleProgress#fill} option.
* @protected
* @type {string|CanvasGradient|CanvasPattern}
*/
arcFill: null,
/**
* Last rendered frame value
* @protected
* @type {number}
*/
lastFrameValue: 0.0,
/**
* Last rendered frame value.
* @protected
* @type {number}
*/
lastFrameValue: 0.0,
/**
* Init/re-init the widget
* @param {object} config - Config
*/
init: function(config) {
$.extend(this, config);
this.radius = this.size / 2;
this.initWidget();
this.initFill();
this.draw();
},
/**
* Init/re-init the widget.
*
* Throws a jQuery event:
*
* - `circle-inited(jqEvent)`
*
* @param {object} config - You can customize any class member (property or method).
*/
init: function(config) {
$.extend(this, config);
this.radius = this.size / 2;
this.initWidget();
this.initFill();
this.draw();
this.el.trigger('circle-inited');
},
/**
* @protected
*/
initWidget: function() {
var canvas = this.canvas = this.canvas || $('<canvas>').prependTo(this.el)[0];
canvas.width = this.size;
canvas.height = this.size;
this.ctx = canvas.getContext('2d');
},
/**
* Initialize `<canvas>`.
* @protected
*/
initWidget: function() {
if (!this.canvas)
this.canvas = $('<canvas>')[this.insertMode == 'prepend' ? 'prependTo' : 'appendTo'](this.el)[0];
/**
* This method sets {@link CircleProgress.arcFill}
* It could do this async (on image load)
* @protected
*/
initFill: function() {
var self = this,
fill = this.fill,
ctx = this.ctx,
size = this.size;
var canvas = this.canvas;
canvas.width = this.size;
canvas.height = this.size;
this.ctx = canvas.getContext('2d');
if (!fill)
throw Error("The fill is not specified!");
if (window.devicePixelRatio > 1) {
var scaleBy = window.devicePixelRatio;
canvas.style.width = canvas.style.height = this.size + 'px';
canvas.width = canvas.height = this.size * scaleBy;
this.ctx.scale(scaleBy, scaleBy);
}
},
if (fill.color)
this.arcFill = fill.color;
/**
* This method sets [this.arcFill]{@link CircleProgress#arcFill}.
* It could do this async (on image load).
* @protected
*/
initFill: function() {
var self = this,
fill = this.fill,
ctx = this.ctx,
size = this.size;
if (fill.gradient) {
var gr = fill.gradient;
if (!fill)
throw Error("The fill is not specified!");
if (gr.length == 1) {
this.arcFill = gr[0];
} else if (gr.length > 1) {
var ga = fill.gradientAngle || 0, // gradient direction angle; 0 by default
gd = fill.gradientDirection || [
size / 2 * (1 - Math.cos(ga)), // x0
size / 2 * (1 + Math.sin(ga)), // y0
size / 2 * (1 + Math.cos(ga)), // x1
size / 2 * (1 - Math.sin(ga)) // y1
];
if (typeof fill == 'string')
fill = {color: fill};
var lg = ctx.createLinearGradient.apply(ctx, gd);
if (fill.color)
this.arcFill = fill.color;
for (var i = 0; i < gr.length; i++) {
var color = gr[i],
pos = i / (gr.length - 1);
if (fill.gradient) {
var gr = fill.gradient;
if ($.isArray(color)) {
pos = color[1];
color = color[0];
}
if (gr.length == 1) {
this.arcFill = gr[0];
} else if (gr.length > 1) {
var ga = fill.gradientAngle || 0, // gradient direction angle; 0 by default
gd = fill.gradientDirection || [
size / 2 * (1 - Math.cos(ga)), // x0
size / 2 * (1 + Math.sin(ga)), // y0
size / 2 * (1 + Math.cos(ga)), // x1
size / 2 * (1 - Math.sin(ga)) // y1
];
lg.addColorStop(pos, color);
}
var lg = ctx.createLinearGradient.apply(ctx, gd);
this.arcFill = lg;
}
}
for (var i = 0; i < gr.length; i++) {
var color = gr[i],
pos = i / (gr.length - 1);
if (fill.image) {
var img;
if (fill.image instanceof Image) {
img = fill.image;
} else {
img = new Image();
img.src = fill.image;
}
if (img.complete)
setImageFill();
else
img.onload = setImageFill;
if ($.isArray(color)) {
pos = color[1];
color = color[0];
}
function setImageFill() {
var bg = $('<canvas>')[0];
bg.width = self.size;
bg.height = self.size;
bg.getContext('2d').drawImage(img, 0, 0, size, size);
self.arcFill = self.ctx.createPattern(bg, 'no-repeat');
self.drawFrame(self.lastFrameValue);
}
},
lg.addColorStop(pos, color);
}
draw: function() {
if (this.animation)
this.drawAnimated(this.value);
else
this.drawFrame(this.value);
},
this.arcFill = lg;
}
}
/**
* @protected
* @param {number} v - Frame value
*/
drawFrame: function(v) {
this.lastFrameValue = v;
this.ctx.clearRect(0, 0, this.size, this.size);
this.drawEmptyArc(v);
this.drawArc(v);
},
if (fill.image) {
var img;
/**
* @protected
* @param {number} v - Frame value
*/
drawArc: function(v) {
var ctx = this.ctx,
r = this.radius,
t = this.getThickness(),
a = this.startAngle;
if (fill.image instanceof Image) {
img = fill.image;
} else {
img = new Image();
img.src = fill.image;
}
ctx.save();
ctx.beginPath();
if (img.complete)
setImageFill();
else
img.onload = setImageFill;
}
if (!this.reverse) {
ctx.arc(r, r, r - t / 2, a, a + Math.PI * 2 * v);
} else {
ctx.arc(r, r, r - t / 2, a - Math.PI * 2 * v, a);
}
function setImageFill() {
var bg = $('<canvas>')[0];
bg.width = self.size;
bg.height = self.size;
bg.getContext('2d').drawImage(img, 0, 0, size, size);
self.arcFill = self.ctx.createPattern(bg, 'no-repeat');
self.drawFrame(self.lastFrameValue);
}
},
ctx.lineWidth = t;
ctx.lineCap = this.lineCap;
ctx.strokeStyle = this.arcFill;
ctx.stroke();
ctx.restore();
},
/**
* Draw the circle.
* @protected
*/
draw: function() {
if (this.animation)
this.drawAnimated(this.value);
else
this.drawFrame(this.value);
},
/**
* @protected
* @param {number} v - Frame value
*/
drawEmptyArc: function(v) {
var ctx = this.ctx,
r = this.radius,
t = this.getThickness(),
a = this.startAngle;
/**
* Draw a single animation frame.
* @protected
* @param {number} v - Frame value.
*/
drawFrame: function(v) {
this.lastFrameValue = v;
this.ctx.clearRect(0, 0, this.size, this.size);
this.drawEmptyArc(v);
this.drawArc(v);
},
if (v < 1) {
ctx.save();
ctx.beginPath();
/**
* Draw the arc (part of the circle).
* @protected
* @param {number} v - Frame value.
*/
drawArc: function(v) {
if (v === 0)
return;
if (v <= 0) {
ctx.arc(r, r, r - t / 2, 0, Math.PI * 2);
} else {
if (!this.reverse) {
ctx.arc(r, r, r - t / 2, a + Math.PI * 2 * v, a);
} else {
ctx.arc(r, r, r - t / 2, a, a - Math.PI * 2 * v);
}
}
var ctx = this.ctx,
r = this.radius,
t = this.getThickness(),
a = this.startAngle;
ctx.lineWidth = t;
ctx.strokeStyle = this.emptyFill;
ctx.stroke();
ctx.restore();
}
},
ctx.save();
ctx.beginPath();
/**
* @protected
* @param {number} v - Value
*/
drawAnimated: function(v) {
var self = this,
el = this.el,
canvas = $(this.canvas);
if (!this.reverse) {
ctx.arc(r, r, r - t / 2, a, a + Math.PI * 2 * v);
} else {
ctx.arc(r, r, r - t / 2, a - Math.PI * 2 * v, a);
}
// stop previous animation before new "start" event is triggered
canvas.stop(true, false);
el.trigger('circle-animation-start');
ctx.lineWidth = t;
ctx.lineCap = this.lineCap;
ctx.strokeStyle = this.arcFill;
ctx.stroke();
ctx.restore();
},
canvas
.css({ animationProgress: 0 })
.animate({ animationProgress: 1 }, $.extend({}, this.animation, {
step: function (animationProgress) {
var stepValue = self.animationStartValue * (1 - animationProgress) + v * animationProgress;
self.drawFrame(stepValue);
el.trigger('circle-animation-progress', [animationProgress, stepValue]);
}
}))
.promise()
.always(function() {
// trigger on both successful & failure animation end
el.trigger('circle-animation-end');
});
},
/**
* Draw the _empty (background)_ arc (part of the circle).
* @protected
* @param {number} v - Frame value.
*/
drawEmptyArc: function(v) {
var ctx = this.ctx,
r = this.radius,
t = this.getThickness(),
a = this.startAngle;
/**
* @protected
* @returns {number}
*/
getThickness: function() {
return $.isNumeric(this.thickness) ? this.thickness : this.size / 14;
},
if (v < 1) {
ctx.save();
ctx.beginPath();
getValue: function() {
return this.value;
},
setValue: function(newValue) {
if (this.animation)
this.animationStartValue = this.lastFrameValue;
this.value = newValue;
this.draw();
if (v <= 0) {
ctx.arc(r, r, r - t / 2, 0, Math.PI * 2);
} else {
if (!this.reverse) {
ctx.arc(r, r, r - t / 2, a + Math.PI * 2 * v, a);
} else {
ctx.arc(r, r, r - t / 2, a, a - Math.PI * 2 * v);
}
}
};
//-------------------------------------------- Initiating jQuery plugin --------------------------------------------
$.circleProgress = {
// Default options (you may override them)
defaults: CircleProgress.prototype
};
ctx.lineWidth = t;
ctx.strokeStyle = this.emptyFill;
ctx.stroke();
ctx.restore();
}
},
// ease-in-out-cubic
$.easing.circleProgressEasing = function(x, t, b, c, d) {
if ((t /= d / 2) < 1)
return c / 2 * t * t * t + b;
return c / 2 * ((t -= 2) * t * t + 2) + b;
};
/**
* Draw animated circular progress bar.
* Animate the progress bar.
*
* Appends <canvas> to the element or updates already appended one.
* Throws 3 jQuery events:
*
* If animated, throws 3 events:
* - `circle-animation-start(jqEvent)`
* - `circle-animation-progress(jqEvent, animationProgress, stepValue)` - multiple event
* animationProgress: from `0.0` to `1.0`; stepValue: from `0.0` to `value`
* - `circle-animation-end(jqEvent)`
*
* - circle-animation-start(jqEvent)
* - circle-animation-progress(jqEvent, animationProgress, stepValue) - multiple event;
* animationProgress: from 0.0 to 1.0;
* stepValue: from 0.0 to value
* - circle-animation-end(jqEvent)
*
* @param configOrCommand - Config object or command name
* Example: { value: 0.75, size: 50, animation: false };
* you may set any public property (see above);
* `animation` may be set to false;
* you may use .circleProgress('widget') to get the canvas
* you may use .circleProgress('value', newValue) to dynamically update the value
*
* @param commandArgument - Some commands (like 'value') may require an argument
* @protected
* @param {number} v - Final value.
*/
$.fn.circleProgress = function(configOrCommand, commandArgument) {
var dataName = 'circle-progress',
firstInstance = this.data(dataName);
drawAnimated: function(v) {
var self = this,
el = this.el,
canvas = $(this.canvas);
if (configOrCommand == 'widget') {
if (!firstInstance)
throw Error('Calling "widget" method on not initialized instance is forbidden');
return firstInstance.canvas;
}
// stop previous animation before new "start" event is triggered
canvas.stop(true, false);
el.trigger('circle-animation-start');
if (configOrCommand == 'value') {
if (!firstInstance)
throw Error('Calling "value" method on not initialized instance is forbidden');
if (typeof commandArgument == 'undefined') {
return firstInstance.getValue();
} else {
var newValue = arguments[1];
return this.each(function() {
$(this).data(dataName).setValue(newValue);
});
}
}
canvas
.css({animationProgress: 0})
.animate({animationProgress: 1}, $.extend({}, this.animation, {
step: function(animationProgress) {
var stepValue = self.animationStartValue * (1 - animationProgress) + v * animationProgress;
self.drawFrame(stepValue);
el.trigger('circle-animation-progress', [animationProgress, stepValue]);
}
}))
.promise()
.always(function() {
// trigger on both successful & failure animation end
el.trigger('circle-animation-end');
});
},
/**
* Get the circle thickness.
* @see CircleProgress#thickness
* @protected
* @returns {number}
*/
getThickness: function() {
return $.isNumeric(this.thickness) ? this.thickness : this.size / 14;
},
/**
* Get current value.
* @protected
* @return {number}
*/
getValue: function() {
return this.value;
},
/**
* Set current value (with smooth animation transition).
* @protected
* @param {number} newValue
*/
setValue: function(newValue) {
if (this.animation)
this.animationStartValue = this.lastFrameValue;
this.value = newValue;
this.draw();
}
};
//----------------------------------- Initiating jQuery plugin -----------------------------------
$.circleProgress = {
// Default options (you may override them)
defaults: CircleProgress.prototype
};
// ease-in-out-cubic
$.easing.circleProgressEasing = function(x, t, b, c, d) {
if ((t /= d / 2) < 1)
return c / 2 * t * t * t + b;
return c / 2 * ((t -= 2) * t * t + 2) + b;
};
/**
* Creates an instance of {@link CircleProgress}.
* Produces [init event]{@link CircleProgress#init} and [animation events]{@link CircleProgress#drawAnimated}.
*
* @param {object} [configOrCommand] - Config object or command name.
*
* Config example (you can specify any {@link CircleProgress} property):
*
* ```js
* { value: 0.75, size: 50, animation: false }
* ```
*
* Commands:
*
* ```js
* el.circleProgress('widget'); // get the <canvas>
* el.circleProgress('value'); // get the value
* el.circleProgress('value', newValue); // update the value
* el.circleProgress('redraw'); // redraw the circle
* el.circleProgress(); // the same as 'redraw'
* ```
*
* @param {string} [commandArgument] - Some commands (like `'value'`) may require an argument.
* @see CircleProgress
* @alias "$(...).circleProgress"
*/
$.fn.circleProgress = function(configOrCommand, commandArgument) {
var dataName = 'circle-progress',
firstInstance = this.data(dataName);
if (configOrCommand == 'widget') {
if (!firstInstance)
throw Error('Calling "widget" method on not initialized instance is forbidden');
return firstInstance.canvas;
}
if (configOrCommand == 'value') {
if (!firstInstance)
throw Error('Calling "value" method on not initialized instance is forbidden');
if (typeof commandArgument == 'undefined') {
return firstInstance.getValue();
} else {
var newValue = arguments[1];
return this.each(function() {
var el = $(this),
instance = el.data(dataName),
config = $.isPlainObject(configOrCommand) ? configOrCommand : {};
$(this).data(dataName).setValue(newValue);
});
}
}
if (instance) {
instance.init(config);
} else {
var initialConfig = $.extend({}, el.data());
if (typeof initialConfig.fill == 'string')
initialConfig.fill = JSON.parse(initialConfig.fill);
if (typeof initialConfig.animation == 'string')
initialConfig.animation = JSON.parse(initialConfig.animation);
config = $.extend(initialConfig, config);
config.el = el;
instance = new CircleProgress(config);
el.data(dataName, instance);
}
});
};
})(jQuery);
return this.each(function() {
var el = $(this),
instance = el.data(dataName),
config = $.isPlainObject(configOrCommand) ? configOrCommand : {};
if (instance) {
instance.init(config);
} else {
var initialConfig = $.extend({}, el.data());
if (typeof initialConfig.fill == 'string')
initialConfig.fill = JSON.parse(initialConfig.fill);
if (typeof initialConfig.animation == 'string')
initialConfig.animation = JSON.parse(initialConfig.animation);
config = $.extend(initialConfig, config);
config.el = el;
instance = new CircleProgress(config);
el.data(dataName, instance);
}
});
};
});
// Karma configuration
module.exports = function(config) {
var customLaunchers = {
'latest-chrome': {
base: 'SauceLabs',
browserName: 'chrome'
},
'latest-firefox': {
base: 'SauceLabs',
browserName: 'firefox'
},
'internet-explorer-9': {
base: 'SauceLabs',
browserName: 'internet explorer',
version: '9'
},
'safari-5': {
base: 'SauceLabs',
platform: "OS X 10.6",
browserName: 'safari',
version: '5'
},
'ios-6': {
base: 'SauceLabs',
platform: "OS X 10.8",
browserName: 'iphone',
version: "6.0"
},
'android-4': {
base: 'SauceLabs',
platform: "Linux",
device: 'Motorola Droid Razr Emulator',
browserName: 'android',
version: "4.0"
}
};
var customLaunchers = {
'Latest Chrome on Windows 10': {
base: 'SauceLabs',
platform: 'Windows 10',
browserName: 'chrome',
version: 'latest'
},
'Latest Firefox on Windows 10': {
base: 'SauceLabs',
platform: 'Windows 10',
browserName: 'firefox',
version: 'latest'
},
'IE9 on Windows 7': {
base: 'SauceLabs',
platform: 'Windows 7',
browserName: 'internet explorer',
version: '9'
},
'Latest Safari on OS X 10.11': {
base: 'SauceLabs',
platform: 'OS X 10.11',
browserName: 'safari',
version: 'latest'
},
'iPhone emulator': {
base: 'SauceLabs',
platform: "OS X 10.11",
browserName: 'iphone',
version: "8.1"
},
'Android emulator': {
base: 'SauceLabs',
platform: 'Linux',
browserName: 'android',
version: '5.0'
}
};
config.set({
frameworks: ['qunit'],
files: [
{ pattern: 'tests/images/circle.png', served: true, watched: false, included: false },
'bower_components/jquery/dist/jquery.min.js',
'bower_components/modernizr/modernizr.js',
'dist/circle-progress.js',
'tests/test_utils.js',
'tests/tests.js'
],
sauceLabs: {
testName: 'Unit Tests for jquery-circle-progress'
},
captureTimeout: 120000,
customLaunchers: customLaunchers,
browsers: Object.keys(customLaunchers),
reporters: ['dots', 'saucelabs'],
singleRun: true
});
config.set({
frameworks: ['qunit'],
files: [
{pattern: 'tests/images/circle.png', served: true, watched: false, included: false},
'node_modules/jquery/dist/jquery.min.js',
'dist/circle-progress.js',
'tests/test_utils.js',
'tests/tests.js'
],
sauceLabs: {
testName: 'Unit tests for jquery-circle-progress'
},
captureTimeout: 120000,
customLaunchers: customLaunchers,
browsers: Object.keys(customLaunchers),
reporters: ['dots', 'saucelabs'],
singleRun: true
});
};
// Karma configuration
module.exports = function(config) {
config.set({
frameworks: ['qunit'],
files: [
{ pattern: 'tests/images/circle.png', served: true, watched: false, included: false },
'bower_components/jquery/dist/jquery.min.js',
'bower_components/modernizr/modernizr.js',
'dist/circle-progress.js',
'tests/test_utils.js',
'tests/tests.js'
],
browsers: ['Firefox', 'PhantomJS'],
singleRun: true
});
config.set({
frameworks: ['qunit'],
files: [
{pattern: 'tests/images/circle.png', served: true, watched: false, included: false},
'node_modules/jquery/dist/jquery.min.js',
'dist/circle-progress.js',
'tests/test_utils.js',
'tests/tests.js'
],
browsers: ['Firefox', 'PhantomJS'],
singleRun: true
});
};
{
"name": "jquery-circle-progress",
"version": "1.1.4",
"author": "Rostyslav Bryzgunov <kottenator@gmail.com>",
"description": "Plugin to draw animated circular progress bars",
"license": "MIT",
"keywords": [
"jquery",
"canvas",
"progress-bar"
],
"main": "dist/circle-progress.js",
"dependencies": {},
"devDependencies": {
"karma": "~0.12.24",
"qunitjs": "~1.15.0",
"karma-qunit": "~0.1.4",
"karma-firefox-launcher": "~0.1.3",
"karma-phantomjs-launcher": "~0.1.4",
"karma-sauce-launcher": "~0.2.10"
},
"scripts": {
"test": "karma start"
},
"repository": {
"type": "git",
"url": "git://github.com/kottenator/jquery-circle-progress.git"
}
"name": "jquery-circle-progress",
"version": "1.2.0",
"author": "Rostyslav Bryzgunov <kottenator@gmail.com>",
"description": "Plugin to draw animated circular progress bars",
"license": "MIT",
"main": "dist/circle-progress.js",
"keywords": [
"jquery",
"canvas",
"progress-bar"
],
"dependencies": {
"jquery": "*"
},
"devDependencies": {
"karma": "~1.2",
"qunitjs": "~2.0",
"karma-qunit": "~1.2",
"karma-firefox-launcher": "~1.0",
"karma-phantomjs-launcher": "~1.0",
"karma-sauce-launcher": "~1.0",
"uglify-js": "~2.7",
"jsdoc": "~3.4"
},
"scripts": {
"test": "karma start",
"build-min": "uglifyjs dist/circle-progress.js -cmo dist/circle-progress.min.js --comments",
"build-docs": "jsdoc dist/circle-progress.js -c jsdoc.conf"
},
"repository": {
"type": "git",
"url": "git://github.com/kottenator/jquery-circle-progress.git"
}
}
jquery-circle-progress
======================
[![Build Status](https://travis-ci.org/kottenator/jquery-circle-progress.svg?branch=master)](https://travis-ci.org/kottenator/jquery-circle-progress)
[![Bower version](https://badge.fury.io/bo/jquery-circle-progress.svg)](https://badge.fury.io/bo/jquery-circle-progress)

@@ -13,2 +15,3 @@ jQuery Plugin to draw animated circular progress bars like this:

-------
Download [latest GitHub release](https://github.com/kottenator/jquery-circle-progress/releases)

@@ -19,4 +22,5 @@ or `bower install jquery-circle-progress`

-----
```html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="jquery-circle-progress/dist/circle-progress.js"></script>

@@ -39,2 +43,3 @@

-------
You should specify options like in usage example above.

@@ -47,13 +52,14 @@

| startAngle | Initial angle (for `0` value) <br> Default: `-Math.PI` |
| reverse | Reverse animation and arc draw<br> Default: `false` |
| reverse | Reverse animation and arc draw <br> Default: `false` |
| thickness | Width of the arc. By default it's automatically calculated as 1/14 of `size` but you may set your own number <br> Default: `"auto"` |
| lineCap | Arc line cap: `"butt"`, `"round"` or `"square"` - [read more](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.lineCap) <br> Default: `"butt"`
| fill | The arc fill config. You may specify next: <br>- `{ color: "#ff1e41" }` <br>- `{ color: 'rgba(255, 255, 255, .3)' }` <br>- `{ gradient: ["red", "green", "blue"] }` <br>- `{ gradient: [["red", .2], ["green", .3], ["blue", .8]] }` <br>- `{ gradient: [ ... ], gradientAngle: Math.PI / 4 }` <br>- `{ gradient: [ ... ], gradientDirection: [x0, y0, x1, y1] }` <br>- `{ image: "http://i.imgur.com/pT0i89v.png" }`<br>- `{ image: imageInstance }`<br>- `{ color: "lime", image: "http://i.imgur.com/pT0i89v.png" }` <br> Default: `{ gradient: ["#3aeabb", "#fdd250"] }` |
| fill | The arc fill config. You may specify next: <br>- `"#ff1e41"` <br>- `{ color: "#ff1e41" }` <br>- `{ color: 'rgba(255, 255, 255, .3)' }` <br>- `{ gradient: ["red", "green", "blue"] }` <br>- `{ gradient: [["red", .2], ["green", .3], ["blue", .8]] }` <br>- `{ gradient: [ ... ], gradientAngle: Math.PI / 4 }` <br>- `{ gradient: [ ... ], gradientDirection: [x0, y0, x1, y1] }` <br>- `{ image: "http://i.imgur.com/pT0i89v.png" }`<br>- `{ image: imageInstance }`<br>- `{ color: "lime", image: "http://i.imgur.com/pT0i89v.png" }` <br> Default: `{ gradient: ["#3aeabb", "#fdd250"] }` |
| emptyFill | Color of the "empty" arc. Only a color fill supported by now <br> Default: `"rgba(0, 0, 0, .1)"` |
| animation | Animation config. See [jQuery animations](http://api.jquery.com/animate/). <br> You may also set it to `false` <br> Default: `{ duration: 1200, easing: "circleProgressEase" }` <br> `"circleProgressEase"` *is just a ease-in-out-cubic easing* |
| animationStartValue | Default animation starts at `0.0` and ends at specified `value`. Let's call this direct animation. If you want to make reversed animation then you should set `animationStartValue` to `1.0`. Also you may specify any other value from `0.0` to `1.0` <br> Default: `0.0`
| insertMode | Canvas insertion mode: append or prepend it into the parent element? <br> Default: `"prepend"` |
From version `1.1.3` you can specify any config option as HTML `data-` attribute.
From version `1.1.3` you can specify any config option as HTML `data-` attribute.
It will work *only on init*, i.e. after the widget is inited you may update its properties only via `.circleProgress({/*...*/})` method. `data-` attributes will be ignored.
It will work *only on init*, i.e. after the widget is inited you may update its properties only via `.circleProgress({/*...*/})` method. `data-` attributes will be ignored.

@@ -79,2 +85,3 @@ Also, object options like `"fill"` or `"animation"` should be valid JSON (and don't forget about HTML-escaping):

------
When animation is enabled, there are 3 events available:

@@ -88,4 +95,11 @@

When the circular progress bar is inited or re-inited, there is the following event:
| Event | Handler |
| ---- | ---- |
| `circle-inited` | `function(event)`: <br>- `event` - jQuery event |
Browsers support
----------------
It uses `<canvas>` which is supported by all modern browsers *(including mobile browsers)*

@@ -100,5 +114,6 @@ and Internet Explorer 9+ ([Can I Use](http://caniuse.com/#search=canvas)).

#### Get/set value
### Get/set value
Get it:
```js

@@ -113,11 +128,12 @@ $('.circle').circleProgress({ value: 0.5 });

Set it:
```js
$('.circle').circleProgress('value', 0.75); // set value to 0.75 & animate the change
$('.circle').circleProgress('value', 0.75); // set value to 0.75 & animate the change
```
It will update *all* selected items value and animate the change.
It will update *all* selected items value and animate the change.
It doesn't *redraw* the widget - it updates the value & animates the changes.
For example, it may be an AJAX loading indicator, which shows the loading progress.
#### Get `<canvas>`
### Get `<canvas>`

@@ -132,3 +148,4 @@ ```js

#### Get `CircleProgress` instance
### Get `CircleProgress` instance
```js

@@ -138,3 +155,4 @@ var instance = $('#circle').data('circle-progress');

#### Redraw existing circle
### Redraw existing circle
```js

@@ -149,3 +167,4 @@ $('#circle').circleProgress({ value: 0.5, fill: { color: 'orange' }});

#### Change default options
### Change default options
```js

@@ -158,24 +177,71 @@ $.circleProgress.defaults.size = 50;

#### How to start the animation only when the circle appears in browser's view (on scrolling)?
<dl>
<dt>How to start the animation only when the circle appears in browser's view (on scrolling)?
<dd>Here is <a href="https://github.com/kottenator/jquery-circle-progress/issues/8">my proposed solution</a>.
<dt>How to make the size flexible?
<dd>E.g. for responsive design, you can do it <a href="https://github.com/kottenator/jquery-circle-progress/issues/17">in the following way</a>.
<dt>What if I need it to run in IE8?
<dd>There is no full-feature support for IE8 (actually, I didn't imlpement IE8 support at all). But you may follow <a href="https://github.com/kottenator/jquery-circle-progress/issues/35">my recommendations</a>.
<dt>How to stop the animation?
<dd>Here is <a href="https://github.com/kottenator/jquery-circle-progress/issues/37">what you can do</a>.
<dt>Can I handle "click" event?
<dd>It's not in the "core" but you can use <a href="http://output.jsbin.com/fetequ/5">my example of mouse/touch events handling</a>.
<dt>May I customize the shape somehow?
<dd>It's a bit "tricky" but possible. Here is <a href="https://github.com/kottenator/jquery-circle-progress/wiki/Custom-layouts">my little collection</a>.
</dl>
Here is [my proposed solution](https://github.com/kottenator/jquery-circle-progress/issues/8).
Development
-----------
#### How to make the size flexible?
### Install
E.g. for Retina support or for responsive design, you can do it [in the following way](https://github.com/kottenator/jquery-circle-progress/issues/17).
```sh
git clone git@github.com:kottenator/jquery-circle-progress.git
npm install
```
#### What if I need it to run in IE8?
### Update minified version
There is no full-feature support for IE8 (actually, I didn't imlpement IE8 support at all). But you may follow [my recommendations](https://github.com/kottenator/jquery-circle-progress/issues/35).
You need to update `dist/circle-progress.min.js` after any change to `dist/circle-progress.js`:
```sh
npm run build-min
```
#### How to stop the animation?
If you're using one of JetBrains IDEs - you can configure a File Watcher.
It's also possible to use some CLI tool like [Watchman](https://facebook.github.io/watchman/).
Here is [what you can do](https://github.com/kottenator/jquery-circle-progress/issues/37).
### Test
#### Can I handle "click" event?
```sh
npm test
```
It's not in the "core" but you can use [my example of mouse/touch events handling](http://output.jsbin.com/fetequ/5).
SauceLabs:
#### May I customize the shape somehow?
```sh
export SAUCE_USERNAME=...
export SAUCE_ACCESS_KEY=...
export BUILD_NUMBER=...
npm test -- karma-saucelabs.conf.js
```
It's a bit "tricky" but possible. Here is [my little collection](https://github.com/kottenator/jquery-circle-progress/wiki/Custom-layouts).
### Build docs
The API docs are not complete yet but you can build them:
```sh
npm run build-docs
```
They will be generated in `docs/api/`.
### Release new version
You need to:
* finalize the code
* update min dist: `npm run build-min`
* push into `master`
* create new version tag (e.g.): `git tag v1.2.3 && git push --tags`
* update the version in `package.json`, `bower.json` and `dist/circle-progress.js` docstring
(function() {
QUnit.extend(QUnit.assert, {
pixelRGBA: function(canvas, x, y, expectedRGBA, message) {
return _pixelColor(canvas, x, y, expectedRGBA, null, message, _parseRGBA, _dumpRGBA);
},
QUnit.extend(QUnit.assert, {
pixelRGBA: function(canvas, x, y, expectedRGBA, message) {
return _pixelColor.call(this, canvas, x, y, expectedRGBA, 0, message, _parseRGBA, _dumpRGBA);
},
pixelHex: function(canvas, x, y, expectedHex, message) {
return _pixelColor(canvas, x, y, expectedHex, null, message, _parseHex, _dumpHex, true);
},
pixelHex: function(canvas, x, y, expectedHex, message) {
return _pixelColor.call(this, canvas, x, y, expectedHex, 0, message, _parseHex, _dumpHex, true);
},
pixelCloseRGBA: function(canvas, x, y, expectedRGBA, maxDiff, message) {
return _pixelColor(canvas, x, y, expectedRGBA, maxDiff, message, _parseRGBA, _dumpRGBA);
},
pixelCloseRGBA: function(canvas, x, y, expectedRGBA, maxDiff, message) {
if (typeof maxDiff == 'undefined' || maxDiff === null)
maxDiff = 0.01;
return _pixelColor.call(this, canvas, x, y, expectedRGBA, maxDiff, message, _parseRGBA, _dumpRGBA);
},
pixelCloseHex: function(canvas, x, y, expectedHex, maxDiff, message) {
return _pixelColor(canvas, x, y, expectedHex, maxDiff, message, _parseHex, _dumpHex, true);
}
});
pixelCloseHex: function(canvas, x, y, expectedHex, maxDiff, message) {
if (typeof maxDiff == 'undefined' || maxDiff === null)
maxDiff = 0.015;
return _pixelColor.call(this, canvas, x, y, expectedHex, maxDiff, message, _parseHex, _dumpHex, true);
}
});
function _pixelColor(canvas, x, y, expectedColor, maxDiff, message, parseColorFn, dumpColorFn, ignoreAlpha) {
var data = canvas.getContext('2d').getImageData(x, y, 1, 1).data,
expectedData = parseColorFn(expectedColor),
actualColor = dumpColorFn(data);
function _pixelColor(canvas, x, y, expectedColor, maxDiff, message, parseColorFn, dumpColorFn, ignoreAlpha) {
var scaleBy = window.devicePixelRatio || 1,
data = canvas.getContext('2d').getImageData(Math.round(x * scaleBy), Math.round(y * scaleBy), 1, 1).data,
expectedData = parseColorFn(expectedColor),
actualColor = dumpColorFn(data);
maxDiff = maxDiff || 0;
maxDiff = maxDiff || 0;
var actualDiff = Math.max(
Math.abs(data[0] - expectedData[0]) / 255,
Math.abs(data[1] - expectedData[1]) / 255,
Math.abs(data[2] - expectedData[2]) / 255,
ignoreAlpha ? 0 : Math.abs(data[3] - expectedData[3]) / 255
);
var actualDiff = Math.max(
Math.abs(data[0] - expectedData[0]) / 255,
Math.abs(data[1] - expectedData[1]) / 255,
Math.abs(data[2] - expectedData[2]) / 255,
ignoreAlpha ? 0 : Math.abs(data[3] - expectedData[3]) / 255
);
var result = actualDiff <= maxDiff;
var result = actualDiff <= maxDiff;
if (!message) {
message = "Pixel color at " + x + "×" + y + " should be ";
message += maxDiff ? "close to " + expectedColor : "equal to " + expectedColor;
if (!result) {
message += ". Actual color: " + actualColor;
message += maxDiff ? ". Actual diff: " + actualDiff.toFixed(6) + ". Expected diff: " + maxDiff : "";
}
}
QUnit.push(result, actualColor, expectedColor, message);
if (!message) {
message = "Pixel color at " + x + "×" + y + " should be ";
message += maxDiff ? "close to " + expectedColor : "equal to " + expectedColor;
if (!result) {
message += ". Actual color: " + actualColor;
message += maxDiff ? ". Actual diff: " + actualDiff.toFixed(6) + ". Expected diff: " + maxDiff : "";
}
}
function _parseRGBA(s) {
s = s.replace(/^rgba\(|\s+|\)$/gi, '').split(',');
return [
parseInt(s[0], 10),
parseInt(s[1], 10),
parseInt(s[2], 10),
s[3] * 255
];
}
this.push(result, actualColor, expectedColor, message);
}
function _dumpRGBA(data) {
return 'rgba(' + data[0] + ', ' + data[1] + ', ' + data[2] + ', ' + data[3] / 255 + ')';
}
function _parseRGBA(s) {
s = s.replace(/^rgba\(|\s+|\)$/gi, '').split(',');
return [
parseInt(s[0], 10),
parseInt(s[1], 10),
parseInt(s[2], 10),
s[3] * 255
];
}
function _parseHex(s) {
s = s.replace(/[#\s]/gi, '');
return [
parseInt(s.substr(0, 2), 16),
parseInt(s.substr(2, 2), 16),
parseInt(s.substr(4, 2), 16),
255
];
}
function _dumpRGBA(data) {
return 'rgba(' + data[0] + ', ' + data[1] + ', ' + data[2] + ', ' + data[3] / 255 + ')';
}
function _dumpHex(data) {
var r = '0' + data[0].toString(16),
g = '0' + data[1].toString(16),
b = '0' + data[2].toString(16);
r = r.substr(r.length - 2);
g = g.substr(g.length - 2);
b = b.substr(b.length - 2);
return '#' + r + g + b;
}
function _parseHex(s) {
s = s.replace(/[#\s]/gi, '');
return [
parseInt(s.substr(0, 2), 16),
parseInt(s.substr(2, 2), 16),
parseInt(s.substr(4, 2), 16),
255
];
}
function _dumpHex(data) {
var r = '0' + data[0].toString(16),
g = '0' + data[1].toString(16),
b = '0' + data[2].toString(16);
r = r.substr(r.length - 2);
g = g.substr(g.length - 2);
b = b.substr(b.length - 2);
return '#' + r + g + b;
}
})();
(function() {
if (Modernizr.canvas) {
QUnit.module("Layout tests, no animation");
// Utilities
function createCircle(cfg) {
var output = $('#qunit-fixture');
if (!output[0])
output = $('body');
var el = $('<span>').appendTo(output).circleProgress(cfg);
return el.circleProgress('widget');
}
QUnit.test("Test circle with value = 0 (without any options)", function(assert) {
var canvas = createCircle({ value: 0 }),
$canvas = $(canvas),
defaultSize = 100,
defaultThickness = parseInt(defaultSize / 14); // 7
QUnit.module("Layout tests, no animation");
assert.equal($.circleProgress.defaults.size, defaultSize, "Default circle size: 100 pixels");
assert.equal($.circleProgress.defaults.thickness, 'auto', "Default circle thickness: 'auto' (i.e. 1/14 of size)");
assert.equal(canvas.tagName.toLowerCase(), 'canvas', "Method .circleProgress('widget') returns HTMLCanvasElement");
assert.equal($canvas.width(), defaultSize, "Default width: 100 pixels");
assert.equal($canvas.height(), defaultSize, "Default height: 100 pixels");
assert.pixelCloseRGBA(canvas, 0, defaultSize / 2, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseRGBA(canvas, defaultThickness - 1, defaultSize / 2, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelRGBA(canvas, defaultThickness + 1, defaultSize / 2, 'rgba(0, 0, 0, 0)');
});
QUnit.test("Test circle with value = 0 (without any options)", function(assert) {
var canvas = createCircle({value: 0}),
$canvas = $(canvas),
defaultSize = 100,
defaultThickness = parseInt(defaultSize / 14); // 7
QUnit.test("Test circle with value = 0.5 and default fill", function(assert) {
var canvas = createCircle({
value: 0.5,
animation: false
}),
size = $.circleProgress.defaults.size;
assert.equal($.circleProgress.defaults.size, defaultSize, "Default circle size: 100 pixels");
assert.equal($.circleProgress.defaults.thickness, 'auto', "Default circle thickness: 'auto' (i.e. 1/14 of size)");
assert.equal(canvas.tagName.toLowerCase(), 'canvas', "Method .circleProgress('widget') returns HTMLCanvasElement");
assert.equal($canvas.width(), defaultSize, "Default width: 100 pixels");
assert.equal($canvas.height(), defaultSize, "Default height: 100 pixels");
assert.pixelCloseRGBA(canvas, 0, defaultSize / 2, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseRGBA(canvas, defaultThickness - 1, defaultSize / 2, 'rgba(0, 0, 0, 0.1)');
assert.pixelRGBA(canvas, defaultThickness + 1, defaultSize / 2, 'rgba(0, 0, 0, 0)');
});
assert.pixelCloseHex(canvas, 1, size / 2 - 1, '#3aeabb', 0.015);
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseHex(canvas, size - 1, size / 2 - 1, '#fdd250', 0.015);
assert.pixelCloseRGBA(canvas, size - 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseHex(canvas, size / 2, 1, '#9ade85', 0.015);
assert.pixelRGBA(canvas, size / 2, 8, 'rgba(0, 0, 0, 0)');
assert.pixelCloseRGBA(canvas, size / 2, size - 1, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelRGBA(canvas, size / 2, size - 9, 'rgba(0, 0, 0, 0)');
});
QUnit.test("Test circle with value = 0.5 and default fill", function(assert) {
var canvas = createCircle({
value: 0.5,
animation: false
}),
size = $.circleProgress.defaults.size;
QUnit.test("Test circle with value = 0.5 and solid fill", function(assert) {
var color = '#ff0000',
canvas = createCircle({
value: 0.5,
fill: { color: color },
animation: false
}),
defaultSize = $.circleProgress.defaults.size;
assert.pixelCloseHex(canvas, 1, size / 2 - 1, '#3aeabb');
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseHex(canvas, size - 1, size / 2 - 1, '#fdd250');
assert.pixelCloseRGBA(canvas, size - 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseHex(canvas, size / 2, 1, '#9ade85');
assert.pixelRGBA(canvas, size / 2, 8, 'rgba(0, 0, 0, 0)');
assert.pixelCloseRGBA(canvas, size / 2, size - 1, 'rgba(0, 0, 0, 0.1)');
assert.pixelRGBA(canvas, size / 2, size - 9, 'rgba(0, 0, 0, 0)');
});
assert.pixelHex(canvas, 1, defaultSize / 2 - 1, color);
assert.pixelHex(canvas, defaultSize - 1, defaultSize / 2 - 1, color);
});
QUnit.test("Test circle with value = 0.5 and solid fill", function(assert) {
var color = '#ff0000',
canvas = createCircle({
value: 0.5,
fill: {color: color},
animation: false
}),
defaultSize = $.circleProgress.defaults.size;
QUnit.module("Layout tests with animation");
assert.pixelHex(canvas, 1, defaultSize / 2 - 1, color);
assert.pixelHex(canvas, defaultSize - 1, defaultSize / 2 - 1, color);
});
QUnit.test("Test circle with value = 0.5 and solid fill", function(assert) {
var color = '#00aa55',
canvas = createCircle({
value: 0.5,
fill: { color: color }
}),
size = $.circleProgress.defaults.size;
QUnit.module("Layout tests with animation");
assert.expect(8);
QUnit.stop();
QUnit.test("Test circle with value = 0.5 and solid fill", function(assert) {
var color = '#00aa55',
canvas = createCircle({
value: 0.5,
fill: {color: color}
}),
size = $.circleProgress.defaults.size;
assert.pixelCloseRGBA(canvas, 1, size / 2 - 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelHex(canvas, 1, size / 2 - 1, color);
}, 200);
assert.expect(8);
var done = assert.async();
assert.pixelCloseRGBA(canvas, size / 2 + 1, 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelHex(canvas, size / 2 + 1, 1, color);
}, 700);
assert.pixelCloseRGBA(canvas, 1, size / 2 - 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelHex(canvas, 1, size / 2 - 1, color);
}, 200);
assert.pixelCloseRGBA(canvas, size - 2, size / 2 - 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelHex(canvas, size - 2, size / 2 - 1, color);
QUnit.start();
}, 1300);
assert.pixelCloseRGBA(canvas, size / 2 + 1, 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelHex(canvas, size / 2 + 1, 1, color);
}, 700);
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseRGBA(canvas, size - 2, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
});
assert.pixelCloseRGBA(canvas, size - 2, size / 2 - 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelHex(canvas, size - 2, size / 2 - 1, color);
done();
}, 1300);
QUnit.test("Test circle with value = 0.5, size = 80 and custom gradient", function(assert) {
var canvas = createCircle({
value: 0.5,
size: 80,
fill: {
gradient: ['#ff327a', '#fff430', '#ff8989']
}
}),
size = 80;
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseRGBA(canvas, size - 2, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
});
assert.expect(8);
QUnit.stop();
QUnit.test("Test circle with value = 0.5, size = 80 and custom gradient", function(assert) {
var canvas = createCircle({
value: 0.5,
size: 80,
fill: {
gradient: ['#ff327a', '#fff430', '#ff8989']
}
}),
size = 80;
assert.pixelCloseRGBA(canvas, 1, size / 2 - 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 1, size / 2 - 1, '#ff3777', 0.01);
}, 200);
assert.expect(8);
var done = assert.async();
assert.pixelCloseRGBA(canvas, size / 2, 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, size / 2, 1, '#fff330', 0.01);
}, 700);
assert.pixelCloseRGBA(canvas, 1, size / 2 - 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 1, size / 2 - 1, '#ff3777');
}, 200);
assert.pixelCloseRGBA(canvas, size - 2, size / 2 - 1, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, size - 2, size / 2 - 1, '#ff8c86', 0.01);
QUnit.start();
}, 1300);
assert.pixelCloseRGBA(canvas, size / 2, 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, size / 2, 1, '#fff330');
}, 700);
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseRGBA(canvas, size - 2, size / 2 + 1, 'rgba(0, 0, 0, 0.1)', 0.01);
});
assert.pixelCloseRGBA(canvas, size - 2, size / 2 - 1, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, size - 2, size / 2 - 1, '#ff8c86');
done();
}, 1300);
QUnit.test("Test circle with value = 0.75, custom start angle and custom animation start value", function(assert) {
var canvas = createCircle({
value: 0.75,
startAngle: -Math.PI / 4,
animationStartValue: 0.25
});
assert.pixelCloseRGBA(canvas, 1, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseRGBA(canvas, size - 2, size / 2 + 1, 'rgba(0, 0, 0, 0.1)');
});
assert.expect(8);
QUnit.stop();
QUnit.test("Test circle with value = 0.75, custom start angle and custom animation start value", function(assert) {
var canvas = createCircle({
value: 0.75,
startAngle: -Math.PI / 4,
animationStartValue: 0.25
});
assert.pixelCloseRGBA(canvas, 80, 15, 'rgba(0, 0, 0, 0.1)', 0.01);
assert.pixelCloseHex(canvas, 85, 20, '#e0d55f', 0.01);
assert.pixelCloseHex(canvas, 85, 80, '#e0d55f', 0.01);
assert.pixelCloseRGBA(canvas, 80, 85, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 80, 85, '#d6d664', 0.01);
}, 400);
assert.expect(8);
var done = assert.async();
assert.pixelCloseRGBA(canvas, 15, 20, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 15, 20, '#57e6aa', 0.01);
assert.pixelCloseRGBA(canvas, 20, 15, 'rgba(0, 0, 0, 0.1)', 0.01);
QUnit.start();
}, 1300);
});
assert.pixelCloseRGBA(canvas, 80, 15, 'rgba(0, 0, 0, 0.1)');
assert.pixelCloseHex(canvas, 85, 20, '#e0d55f');
assert.pixelCloseHex(canvas, 85, 80, '#e0d55f');
assert.pixelCloseRGBA(canvas, 80, 85, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 80, 85, '#d6d664');
}, 400);
QUnit.asyncTest("Test circle with value = 0.5, image background and reverse", function(assert) {
var urlPrefix = $('script[src*="tests.js"]').attr('src').replace(/tests\.js.*$/, ''),
imageUrl = urlPrefix + 'images/circle.png',
image = new Image();
assert.pixelCloseRGBA(canvas, 15, 20, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 15, 20, '#57e6aa');
assert.pixelCloseRGBA(canvas, 20, 15, 'rgba(0, 0, 0, 0.1)');
done();
}, 1300);
});
assert.expect(9);
image.src = imageUrl;
QUnit.test("Test circle with value = 0.5, image background and reverse", function(assert) {
var urlPrefix = $('script[src*="tests.js"]').attr('src').replace(/tests\.js.*$/, ''),
imageUrl = urlPrefix + 'images/circle.png',
image = new Image();
$(image).load(function() {
var canvas = createCircle({
value: 0.5,
thickness: 20,
fill: {image: image},
reverse: true
});
assert.expect(9);
var done = assert.async();
image.src = imageUrl;
assert.pixelRGBA(canvas, 21, 49, 'rgba(0, 0, 0, 0)');
assert.pixelRGBA(canvas, 78, 49, 'rgba(0, 0, 0, 0)');
assert.pixelRGBA(canvas, 49, 77, 'rgba(0, 0, 0, 0)');
$(image).on('load', function() {
var canvas = createCircle({
value: 0.5,
thickness: 20,
fill: {image: image},
reverse: true
});
assert.pixelCloseRGBA(canvas, 17, 51, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 17, 51, '#00f7ff', 0.01);
}, 400);
assert.pixelRGBA(canvas, 21, 49, 'rgba(0, 0, 0, 0)');
assert.pixelRGBA(canvas, 78, 49, 'rgba(0, 0, 0, 0)');
assert.pixelRGBA(canvas, 49, 77, 'rgba(0, 0, 0, 0)');
assert.pixelCloseRGBA(canvas, 49, 81, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 49, 81, '#7700ff', 0.01);
}, 700);
assert.pixelCloseRGBA(canvas, 17, 51, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 17, 51, '#00f7ff');
}, 400);
assert.pixelCloseRGBA(canvas, 81, 51, 'rgba(0, 0, 0, 0.1)', 0.01);
setTimeout(function() {
assert.pixelCloseHex(canvas, 81, 51, '#ff0008', 0.01);
QUnit.start();
}, 1400);
});
});
} else {
QUnit.test("Your browser doesn't support Canvas", function(assert) {
assert.ok(true, "That's fine");
});
}
assert.pixelCloseRGBA(canvas, 49, 81, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 49, 81, '#7700ff');
}, 700);
// Utilities
function createCircle(cfg) {
var output = $('#qunit-fixture');
if (!output[0])
output = $('body');
var el = $('<span>').appendTo(output).circleProgress(cfg);
return el.circleProgress('widget');
}
assert.pixelCloseRGBA(canvas, 81, 51, 'rgba(0, 0, 0, 0.1)');
setTimeout(function() {
assert.pixelCloseHex(canvas, 81, 51, '#ff0008');
done();
}, 1400);
});
});
QUnit.test("Test correct rendering on Retina displays", function(assert) {
/**
* Mock devicePixelRatio
*/
window.devicePixelRatio = 2;
var canvas = createCircle({
value: 0.75,
size: 50
});
assert.equal(50, $(canvas).width());
assert.equal(100, canvas.width);
});
QUnit.test("Test correct rendering on regular pixel density", function(assert) {
/**
* Mock devicePixelRatio
*/
window.devicePixelRatio = 1;
var canvas = createCircle({
value: 0.75,
size: 50
});
assert.equal(50, $(canvas).height());
assert.equal(50, canvas.width);
});
})();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc