html
This commit is contained in:
552
www/static/file/home/js/circle-progress.js
Normal file
552
www/static/file/home/js/circle-progress.js
Normal file
@@ -0,0 +1,552 @@
|
||||
/**
|
||||
* 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.2
|
||||
* @licence MIT
|
||||
* @preserve
|
||||
*/
|
||||
// UMD factory - https://github.com/umdjs/umd/blob/d31bb6ee7098715e019f52bdfe27b3e4bfd2b97e/templates/jqueryPlugin.js
|
||||
// Uses AMD, CommonJS 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
|
||||
var $ = require('jquery');
|
||||
factory($);
|
||||
module.exports = $;
|
||||
} 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);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
/**
|
||||
* Size of the canvas in pixels.
|
||||
* It's a square so we need only one dimension.
|
||||
* @type {number}
|
||||
* @default 100.0
|
||||
*/
|
||||
size: 100.0,
|
||||
|
||||
/**
|
||||
* Initial angle for `0.0` value in radians.
|
||||
* @type {number}
|
||||
* @default -Math.PI
|
||||
*/
|
||||
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',
|
||||
|
||||
/**
|
||||
* 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']
|
||||
},
|
||||
|
||||
/**
|
||||
* Color of the "empty" arc. Only a color fill supported by now.
|
||||
* @type {string}
|
||||
* @default 'rgba(0, 0, 0, .1)'
|
||||
*/
|
||||
emptyFill: 'rgba(255, 255, 255, 0.06)',
|
||||
|
||||
/**
|
||||
* 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'
|
||||
},
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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',
|
||||
|
||||
/**
|
||||
* Canvas insertion mode: append or prepend it into the parent element?
|
||||
* @type {string}
|
||||
* @default 'prepend'
|
||||
*/
|
||||
insertMode: 'prepend',
|
||||
|
||||
//------------------------------ 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,
|
||||
|
||||
/**
|
||||
* Canvas element. Automatically generated and prepended to [this.el]{@link CircleProgress#el}.
|
||||
* @protected
|
||||
* @type {HTMLCanvasElement}
|
||||
*/
|
||||
canvas: null,
|
||||
|
||||
/**
|
||||
* 2D-context of [this.canvas]{@link CircleProgress#canvas}.
|
||||
* @protected
|
||||
* @type {CanvasRenderingContext2D}
|
||||
*/
|
||||
ctx: null,
|
||||
|
||||
/**
|
||||
* 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 [this.fill]{@link CircleProgress#fill} option.
|
||||
* @protected
|
||||
* @type {string|CanvasGradient|CanvasPattern}
|
||||
*/
|
||||
arcFill: null,
|
||||
|
||||
/**
|
||||
* Last rendered frame value.
|
||||
* @protected
|
||||
* @type {number}
|
||||
*/
|
||||
lastFrameValue: 0.0,
|
||||
|
||||
/**
|
||||
* 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');
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize `<canvas>`.
|
||||
* @protected
|
||||
*/
|
||||
initWidget: function() {
|
||||
if (!this.canvas)
|
||||
this.canvas = $('<canvas>')[this.insertMode == 'prepend' ? 'prependTo' : 'appendTo'](this.el)[0];
|
||||
|
||||
var canvas = this.canvas;
|
||||
canvas.width = this.size;
|
||||
canvas.height = this.size;
|
||||
this.ctx = canvas.getContext('2d');
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
throw Error("The fill is not specified!");
|
||||
|
||||
if (typeof fill == 'string')
|
||||
fill = {color: fill};
|
||||
|
||||
if (fill.color)
|
||||
this.arcFill = fill.color;
|
||||
|
||||
if (fill.gradient) {
|
||||
var gr = fill.gradient;
|
||||
|
||||
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
|
||||
];
|
||||
|
||||
var lg = ctx.createLinearGradient.apply(ctx, gd);
|
||||
|
||||
for (var i = 0; i < gr.length; i++) {
|
||||
var color = gr[i],
|
||||
pos = i / (gr.length - 1);
|
||||
|
||||
if ($.isArray(color)) {
|
||||
pos = color[1];
|
||||
color = color[0];
|
||||
}
|
||||
|
||||
lg.addColorStop(pos, color);
|
||||
}
|
||||
|
||||
this.arcFill = lg;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw the circle.
|
||||
* @protected
|
||||
*/
|
||||
draw: function() {
|
||||
if (this.animation)
|
||||
this.drawAnimated(this.value);
|
||||
else
|
||||
this.drawFrame(this.value);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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);
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw the arc (part of the circle).
|
||||
* @protected
|
||||
* @param {number} v - Frame value.
|
||||
*/
|
||||
drawArc: function(v) {
|
||||
if (v === 0)
|
||||
return;
|
||||
|
||||
var ctx = this.ctx,
|
||||
r = this.radius,
|
||||
t = this.getThickness(),
|
||||
a = this.startAngle;
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ctx.lineWidth = t;
|
||||
ctx.lineCap = this.lineCap;
|
||||
ctx.strokeStyle = this.arcFill;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
if (v < 1) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.lineWidth = t;
|
||||
ctx.strokeStyle = this.emptyFill;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Animate the progress bar.
|
||||
*
|
||||
* Throws 3 jQuery 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)`
|
||||
*
|
||||
* @protected
|
||||
* @param {number} v - Final value.
|
||||
*/
|
||||
drawAnimated: function(v) {
|
||||
var self = this,
|
||||
el = this.el,
|
||||
canvas = $(this.canvas);
|
||||
|
||||
// stop previous animation before new "start" event is triggered
|
||||
canvas.stop(true, false);
|
||||
el.trigger('circle-animation-start');
|
||||
|
||||
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) {
|
||||
if (x < 0.5) {
|
||||
x = 2 * x;
|
||||
return 0.5 * x * x * x;
|
||||
} else {
|
||||
x = 2 - 2 * x;
|
||||
return 1 - 0.5 * x * x * x;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
$(this).data(dataName).setValue(newValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user