vendor: 14,238 bytes, lines 1-439
1/* 2jquery-circle-progress - jQuery Plugin to draw animated circular progress bars 3 4URL: http://kottenator.github.io/jquery-circle-progress/ 5Author: Rostyslav Bryzgunov <[email protected]> 6Version: 1.1.3 7License: MIT 8*/ 9(function($) { 10 function CircleProgress(config) { 11 this.init(config); 12 } 13 14 CircleProgress.prototype = { 15 //----------------------------------------------- public options ----------------------------------------------- 16 /** 17 * This is the only required option. It should be from 0.0 to 1.0 18 * @type {number} 19 */ 20 value: 0.0, 21 22 /** 23 * Size of the circle / canvas in pixels 24 * @type {number} 25 */ 26 size: 100.0, 27 28 /** 29 * Initial angle for 0.0 value in radians 30 * @type {number} 31 */ 32 startAngle: -Math.PI, 33 34 /** 35 * Width of the arc. By default it's auto-calculated as 1/14 of size, but you may set it explicitly in pixels 36 * @type {number|string} 37 */ 38 thickness: 'auto', 39 40 /** 41 * Fill of the arc. You may set it to: 42 * - solid color: 43 * - { color: '#3aeabb' } 44 * - { color: 'rgba(255, 255, 255, .3)' } 45 * - linear gradient (left to right): 46 * - { gradient: ['#3aeabb', '#fdd250'], gradientAngle: Math.PI / 4 } 47 * - { gradient: ['red', 'green', 'blue'], gradientDirection: [x0, y0, x1, y1] } 48 * - image: 49 * - { image: 'http://i.imgur.com/pT0i89v.png' } 50 * - { image: imageObject } 51 * - { color: 'lime', image: 'http://i.imgur.com/pT0i89v.png' } - color displayed until the image is loaded 52 */ 53 fill: { 54 gradient: ['#3aeabb', '#fdd250'] 55 }, 56 57 /** 58 * Color of the "empty" arc. Only a color fill supported by now 59 * @type {string} 60 */ 61 emptyFill: 'rgba(0, 0, 0, .1)', 62 63 /** 64 * Animation config (see jQuery animations: http://api.jquery.com/animate/) 65 */ 66 animation: { 67 duration: 1200, 68 easing: 'circleProgressEasing' 69 }, 70 71 /** 72 * Default animation starts at 0.0 and ends at specified `value`. Let's call this direct animation. 73 * If you want to make reversed animation then you should set `animationStartValue` to 1.0. 74 * Also you may specify any other value from 0.0 to 1.0 75 * @type {number} 76 */ 77 animationStartValue: 0.0, 78 79 /** 80 * Reverse animation and arc draw 81 * @type {boolean} 82 */ 83 reverse: false, 84 85 /** 86 * Arc line cap ('butt', 'round' or 'square') 87 * Read more: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.lineCap 88 * @type {string} 89 */ 90 lineCap: 'butt', 91 92 //-------------------------------------- protected properties and methods -------------------------------------- 93 /** 94 * @protected 95 */ 96 constructor: CircleProgress, 97 98 /** 99 * Container element. Should be passed into constructor config 100 * @protected 101 * @type {jQuery} 102 */ 103 el: null, 104 105 /** 106 * Canvas element. Automatically generated and prepended to the {@link CircleProgress.el container} 107 * @protected 108 * @type {HTMLCanvasElement} 109 */ 110 canvas: null, 111 112 /** 113 * 2D-context of the {@link CircleProgress.canvas canvas} 114 * @protected 115 * @type {CanvasRenderingContext2D} 116 */ 117 ctx: null, 118 119 /** 120 * Radius of the outer circle. Automatically calculated as {@link CircleProgress.size} / 2 121 * @protected 122 * @type {number} 123 */ 124 radius: 0.0, 125 126 /** 127 * Fill of the main arc. Automatically calculated, depending on {@link CircleProgress.fill} option 128 * @protected 129 * @type {string|CanvasGradient|CanvasPattern} 130 */ 131 arcFill: null, 132 133 /** 134 * Last rendered frame value 135 * @protected 136 * @type {number} 137 */ 138 lastFrameValue: 0.0, 139 140 /** 141 * Init/re-init the widget 142 * @param {object} config - Config 143 */ 144 init: function(config) { 145 $.extend(this, config); 146 this.radius = this.size / 2; 147 this.initWidget(); 148 this.initFill(); 149 this.draw(); 150 }, 151 152 /** 153 * @protected 154 */ 155 initWidget: function() { 156 var canvas = this.canvas = this.canvas || $('<canvas>').prependTo(this.el)[0]; 157 canvas.width = this.size; 158 canvas.height = this.size; 159 this.ctx = canvas.getContext('2d'); 160 }, 161 162 /** 163 * This method sets {@link CircleProgress.arcFill} 164 * It could do this async (on image load) 165 * @protected 166 */ 167 initFill: function() { 168 var self = this, 169 fill = this.fill, 170 ctx = this.ctx, 171 size = this.size; 172 173 if (!fill) 174 throw Error("The fill is not specified!"); 175 176 if (fill.color) 177 this.arcFill = fill.color; 178 179 if (fill.gradient) { 180 var gr = fill.gradient; 181 182 if (gr.length == 1) { 183 this.arcFill = gr[0]; 184 } else if (gr.length > 1) { 185 var ga = fill.gradientAngle || 0, // gradient direction angle; 0 by default 186 gd = fill.gradientDirection || [ 187 size / 2 * (1 - Math.cos(ga)), // x0 188 size / 2 * (1 + Math.sin(ga)), // y0 189 size / 2 * (1 + Math.cos(ga)), // x1 190 size / 2 * (1 - Math.sin(ga)) // y1 191 ]; 192 193 var lg = ctx.createLinearGradient.apply(ctx, gd); 194 195 for (var i = 0; i < gr.length; i++) { 196 var color = gr[i], 197 pos = i / (gr.length - 1); 198 199 if ($.isArray(color)) { 200 pos = color[1]; 201 color = color[0]; 202 } 203 204 lg.addColorStop(pos, color); 205 } 206 207 this.arcFill = lg; 208 } 209 } 210 211 if (fill.image) { 212 var img; 213 214 if (fill.image instanceof Image) { 215 img = fill.image; 216 } else { 217 img = new Image(); 218 img.src = fill.image; 219 } 220 221 if (img.complete) 222 setImageFill(); 223 else 224 img.onload = setImageFill; 225 } 226 227 function setImageFill() { 228 var bg = $('<canvas>')[0]; 229 bg.width = self.size; 230 bg.height = self.size; 231 bg.getContext('2d').drawImage(img, 0, 0, size, size); 232 self.arcFill = self.ctx.createPattern(bg, 'no-repeat'); 233 self.drawFrame(self.lastFrameValue); 234 } 235 }, 236 237 draw: function() { 238 if (this.animation) 239 this.drawAnimated(this.value); 240 else 241 this.drawFrame(this.value); 242 }, 243 244 /** 245 * @protected 246 * @param {number} v - Frame value 247 */ 248 drawFrame: function(v) { 249 this.lastFrameValue = v; 250 this.ctx.clearRect(0, 0, this.size, this.size); 251 this.drawEmptyArc(v); 252 this.drawArc(v); 253 }, 254 255 /** 256 * @protected 257 * @param {number} v - Frame value 258 */ 259 drawArc: function(v) { 260 var ctx = this.ctx, 261 r = this.radius, 262 t = this.getThickness(), 263 a = this.startAngle; 264 265 ctx.save(); 266 ctx.beginPath(); 267 268 if (!this.reverse) { 269 ctx.arc(r, r, r - t / 2, a, a + Math.PI * 2 * v); 270 } else { 271 ctx.arc(r, r, r - t / 2, a - Math.PI * 2 * v, a); 272 } 273 274 ctx.lineWidth = t; 275 ctx.lineCap = this.lineCap; 276 ctx.strokeStyle = this.arcFill; 277 ctx.stroke(); 278 ctx.restore(); 279 }, 280 281 /** 282 * @protected 283 * @param {number} v - Frame value 284 */ 285 drawEmptyArc: function(v) { 286 var ctx = this.ctx, 287 r = this.radius, 288 t = this.getThickness(), 289 a = this.startAngle; 290 291 if (v < 1) { 292 ctx.save(); 293 ctx.beginPath(); 294 295 if (v <= 0) { 296 ctx.arc(r, r, r - t / 2, 0, Math.PI * 2); 297 } else { 298 if (!this.reverse) { 299 ctx.arc(r, r, r - t / 2, a + Math.PI * 2 * v, a); 300 } else { 301 ctx.arc(r, r, r - t / 2, a, a - Math.PI * 2 * v); 302 } 303 } 304 305 ctx.lineWidth = t; 306 ctx.strokeStyle = this.emptyFill; 307 ctx.stroke(); 308 ctx.restore(); 309 } 310 }, 311 312 /** 313 * @protected 314 * @param {number} v - Value 315 */ 316 drawAnimated: function(v) { 317 var self = this, 318 el = this.el, 319 canvas = $(this.canvas); 320 321 // stop previous animation before new "start" event is triggered 322 canvas.stop(true, false); 323 el.trigger('circle-animation-start'); 324 325 canvas 326 .css({ animationProgress: 0 }) 327 .animate({ animationProgress: 1 }, $.extend({}, this.animation, { 328 step: function (animationProgress) { 329 var stepValue = self.animationStartValue * (1 - animationProgress) + v * animationProgress; 330 self.drawFrame(stepValue); 331 el.trigger('circle-animation-progress', [animationProgress, stepValue]); 332 } 333 })) 334 .promise() 335 .always(function() { 336 // trigger on both successful & failure animation end 337 el.trigger('circle-animation-end'); 338 }); 339 }, 340 341 /** 342 * @protected 343 * @returns {number} 344 */ 345 getThickness: function() { 346 return $.isNumeric(this.thickness) ? this.thickness : this.size / 14; 347 }, 348 349 getValue: function() { 350 return this.value; 351 }, 352 353 setValue: function(newValue) { 354 if (this.animation) 355 this.animationStartValue = this.lastFrameValue; 356 this.value = newValue; 357 this.draw(); 358 } 359 }; 360 361 //-------------------------------------------- Initiating jQuery plugin -------------------------------------------- 362 $.circleProgress = { 363 // Default options (you may override them) 364 defaults: CircleProgress.prototype 365 }; 366 367 // ease-in-out-cubic 368 $.easing.circleProgressEasing = function(x, t, b, c, d) { 369 if ((t /= d / 2) < 1) 370 return c / 2 * t * t * t + b; 371 return c / 2 * ((t -= 2) * t * t + 2) + b; 372 }; 373 374 /** 375 * Draw animated circular progress bar. 376 * 377 * Appends <canvas> to the element or updates already appended one. 378 * 379 * If animated, throws 3 events: 380 * 381 * - circle-animation-start(jqEvent) 382 * - circle-animation-progress(jqEvent, animationProgress, stepValue) - multiple event; 383 * animationProgress: from 0.0 to 1.0; 384 * stepValue: from 0.0 to value 385 * - circle-animation-end(jqEvent) 386 * 387 * @param configOrCommand - Config object or command name 388 * Example: { value: 0.75, size: 50, animation: false }; 389 * you may set any public property (see above); 390 * `animation` may be set to false; 391 * you may use .circleProgress('widget') to get the canvas 392 * you may use .circleProgress('value', newValue) to dynamically update the value 393 * 394 * @param commandArgument - Some commands (like 'value') may require an argument 395 */ 396 $.fn.circleProgress = function(configOrCommand, commandArgument) { 397 var dataName = 'circle-progress', 398 firstInstance = this.data(dataName); 399 400 if (configOrCommand == 'widget') { 401 if (!firstInstance) 402 throw Error('Calling "widget" method on not initialized instance is forbidden'); 403 return firstInstance.canvas; 404 } 405 406 if (configOrCommand == 'value') { 407 if (!firstInstance) 408 throw Error('Calling "value" method on not initialized instance is forbidden'); 409 if (typeof commandArgument == 'undefined') { 410 return firstInstance.getValue(); 411 } else { 412 var newValue = arguments[1]; 413 return this.each(function() { 414 $(this).data(dataName).setValue(newValue); 415 }); 416 } 417 } 418 419 return this.each(function() { 420 var el = $(this), 421 instance = el.data(dataName), 422 config = $.isPlainObject(configOrCommand) ? configOrCommand : {}; 423 424 if (instance) { 425 instance.init(config); 426 } else { 427 var initialConfig = $.extend({}, el.data()); 428 if (typeof initialConfig.fill == 'string') 429 initialConfig.fill = JSON.parse(initialConfig.fill); 430 if (typeof initialConfig.animation == 'string') 431 initialConfig.animation = JSON.parse(initialConfig.animation); 432 config = $.extend(initialConfig, config); 433 config.el = el; 434 instance = new CircleProgress(config); 435 el.data(dataName, instance); 436 } 437 }); 438 }; 439})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.