From a0c71a6cdc25c66f8368d28780fdec2d5454f27a Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Fri, 1 Sep 2017 10:42:13 +0300 Subject: [PATCH 01/12] Test was failing on Firefox 55 / Linux Mint The test "Test circle with value = 0.5 and default fill" was failing on my machine because of color smoothing (maybe antialias?), as the color detected by the test at pixel 1 was #fe0000 instead of #ff0000. However, the visual result was correct. Sampling the second pixel instead fixed the test. --- tests/tests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests.js b/tests/tests.js index 9db3ee3..7223e49 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -55,8 +55,8 @@ }).circleProgress('widget'); var defaultSize = $.circleProgress.defaults.size; - assert.pixelHex(canvas, 1, defaultSize / 2 - 1, color); - assert.pixelHex(canvas, defaultSize - 1, defaultSize / 2 - 1, color); + assert.pixelHex(canvas, 2, defaultSize / 2 - 1, color); + assert.pixelHex(canvas, defaultSize - 2, defaultSize / 2 - 1, color); }); QUnit.module("Layout tests with animation"); From ce9500ba1bad1a1cf732aacfd6054b2c6353473e Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Fri, 1 Sep 2017 11:21:57 +0300 Subject: [PATCH 02/12] Initial implementation for empty thickness parameter --- dist/circle-progress.js | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index 7a19213..27a5712 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -67,6 +67,14 @@ */ thickness: 'auto', + /** + * Width of the empty arc (under the filled one) in pixels. + * If it's `'auto'`, it falls back to the value of the `thickness` property. + * @type {number|string} + * @default 'auto' + */ + emptyThickness: 'auto', + /** * Fill of the arc. You may set it to: * @@ -369,24 +377,27 @@ drawEmptyArc: function(v) { var ctx = this.ctx, r = this.radius, - t = this.getThickness(), + tFill = this.getThickness(), + tEmpty = this.getEmptyThickness(), a = this.startAngle; + console.log(tFill, tEmpty); + if (v < 1) { ctx.save(); ctx.beginPath(); if (v <= 0) { - ctx.arc(r, r, r - t / 2, 0, Math.PI * 2); + ctx.arc(r, r, r - tFill / 2, 0, Math.PI * 2); } else { if (!this.reverse) { - ctx.arc(r, r, r - t / 2, a + Math.PI * 2 * v, a); + ctx.arc(r, r, r - tFill / 2, a + Math.PI * 2 * v, a); } else { - ctx.arc(r, r, r - t / 2, a, a - Math.PI * 2 * v); + ctx.arc(r, r, r - tFill / 2, a, a - Math.PI * 2 * v); } } - ctx.lineWidth = t; + ctx.lineWidth = tEmpty; ctx.strokeStyle = this.emptyFill; ctx.stroke(); ctx.restore(); @@ -441,6 +452,16 @@ return $.isNumeric(this.thickness) ? this.thickness : this.size / 14; }, + /** + * Get the empty arc thickness. + * @see CircleProgress#emptyThickness + * @protected + * @returns {number} + */ + getEmptyThickness: function() { + return $.isNumeric(this.emptyThickness) ? this.emptyThickness : this.getThickness(); + }, + /** * Get current value. * @protected From 12d09928b6b6cb092616bbdee736b931161caed1 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Thu, 7 Sep 2017 11:40:45 +0300 Subject: [PATCH 03/12] Make sure that thicker empty arcs don't break the circle aspect --- dist/circle-progress.js | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index 27a5712..f75a861 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -350,6 +350,7 @@ var ctx = this.ctx, r = this.radius, + arcR = this.getArcRadius(), t = this.getThickness(), a = this.startAngle; @@ -357,9 +358,9 @@ ctx.beginPath(); if (!this.reverse) { - ctx.arc(r, r, r - t / 2, a, a + Math.PI * 2 * v); + ctx.arc(r, r, arcR, a, a + Math.PI * 2 * v); } else { - ctx.arc(r, r, r - t / 2, a - Math.PI * 2 * v, a); + ctx.arc(r, r, arcR, a - Math.PI * 2 * v, a); } ctx.lineWidth = t; @@ -377,27 +378,21 @@ drawEmptyArc: function(v) { var ctx = this.ctx, r = this.radius, - tFill = this.getThickness(), - tEmpty = this.getEmptyThickness(), + arcR = this.getArcRadius(), + t = this.getEmptyThickness(), a = this.startAngle; - console.log(tFill, tEmpty); - if (v < 1) { ctx.save(); ctx.beginPath(); - if (v <= 0) { - ctx.arc(r, r, r - tFill / 2, 0, Math.PI * 2); + if (this.reverse) { + ctx.arc(r, r, arcR, 0, Math.PI * 2); } else { - if (!this.reverse) { - ctx.arc(r, r, r - tFill / 2, a + Math.PI * 2 * v, a); - } else { - ctx.arc(r, r, r - tFill / 2, a, a - Math.PI * 2 * v); - } + ctx.arc(r, r, arcR, Math.PI * 2, 0); } - ctx.lineWidth = tEmpty; + ctx.lineWidth = t; ctx.strokeStyle = this.emptyFill; ctx.stroke(); ctx.restore(); @@ -462,6 +457,15 @@ return $.isNumeric(this.emptyThickness) ? this.emptyThickness : this.getThickness(); }, + /** + * Returns the real arc radius, after the thickness has been accounted for. + * @private + * @returns {number} + */ + getArcRadius: function() { + return this.radius - Math.max(this.getThickness(), this.getEmptyThickness()) / 2; + }, + /** * Get current value. * @protected From db508b766dd33169d658223a409e1bc567b76cf6 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Thu, 7 Sep 2017 11:41:56 +0300 Subject: [PATCH 04/12] Update docs --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2aa7702..b37a48a 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Specify options like in example above. | startAngle | Initial angle (for `0` value)
Default: `-Math.PI` | | reverse | Reverse animation and arc draw
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
Default: `"auto"` | +| emptyThickness | Width of the empty arc. By default it falls back to the `thickness` parameter
Default: `"auto"` | | lineCap | Arc line cap: `"butt"`, `"round"` or `"square"` - [read more](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.lineCap)
Default: `"butt"` | fill | The arc fill config. You may specify next:
- `"#ff1e41"`
- `{ color: "#ff1e41" }`
- `{ color: 'rgba(255, 255, 255, .3)' }`
- `{ gradient: ["red", "green", "blue"] }`
- `{ gradient: [["red", .2], ["green", .3], ["blue", .8]] }`
- `{ gradient: [ ... ], gradientAngle: Math.PI / 4 }`
- `{ gradient: [ ... ], gradientDirection: [x0, y0, x1, y1] }`
- `{ image: "http://i.imgur.com/pT0i89v.png" }`
- `{ image: imageInstance }`
- `{ color: "lime", image: "http://i.imgur.com/pT0i89v.png" }`
Default: `{ gradient: ["#3aeabb", "#fdd250"] }` | | emptyFill | Color of the "empty" arc. Only a color fill supported by now
Default: `"rgba(0, 0, 0, .1)"` | @@ -255,7 +256,7 @@ npm install ### Modify You need to update `dist/circle-progress.min.js` after any change to `dist/circle-progress.js`: - + ```sh npm run build-min ``` @@ -298,5 +299,5 @@ They will be generated in `docs/api/`. * release on Bower: just create a Git tag (e.g.): `git tag v1.2.3 && git push --tags` * release on GitHub - add release notes to the Git tag * release on NPM: `npm publish`, but be aware: - + > Once a package is published with a given name and version, that specific name and version combination can never be used again - [NPM docs](https://docs.npmjs.com/cli/publish) From 28b7a5361e2a483c4f4531e6d7719672b8bcc1dd Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Thu, 7 Sep 2017 12:06:20 +0300 Subject: [PATCH 05/12] Add different thicknesses example --- docs/examples.js | 16 ++++++++++++++++ docs/index.html | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/examples.js b/docs/examples.js index 5de8ec3..4266e69 100644 --- a/docs/examples.js +++ b/docs/examples.js @@ -79,4 +79,20 @@ // "data-" attributes are taken into account only on init (not on update/redraw) // "data-fill" (and other object options) should be in valid JSON format }); + + /* + * Example 6: + * + * - custom gradient + * - different thicknesses + */ + var c6 = $('.sixth.circle'); + + c6.circleProgress({ + value: 0.75, + lineCap: 'round', + emptyThickness: 15, + thickness: 5, + fill: {gradient: ['#f4ad60', '#fffaaa']} + }); })(jQuery); diff --git a/docs/index.html b/docs/index.html index 1de1609..de45460 100644 --- a/docs/index.html +++ b/docs/index.html @@ -33,6 +33,10 @@

custom angle,
value update
+
+ different thicknesses +
+

- + From bd1baa0fff7cdb2bc875a4017965573da91c6579 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Tue, 12 Sep 2017 15:28:32 +0300 Subject: [PATCH 06/12] Add tests for the `emptyThickness` parameter --- tests/tests.js | 75 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/tests/tests.js b/tests/tests.js index 7223e49..7b0a244 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -59,6 +59,47 @@ assert.pixelHex(canvas, defaultSize - 2, defaultSize / 2 - 1, color); }); + QUnit.test("Test circle with emptyThickness < thickness", function(assert) { + var color = '#ff0000'; + var emptyColor = '#00ff00'; + var thickness = 4; + var emptyThickness = 2; + + var canvas = createCircle({ + value: 0.5, + thickness: thickness, + emptyThickness: emptyThickness, + fill: { color: color }, + emptyFill: emptyColor, + animation: false + }).circleProgress('widget'); + var defaultSize = $.circleProgress.defaults.size; + + assert.pixelHex(canvas, defaultSize / 2 - 1, 1, color); + assert.pixelHex(canvas, defaultSize / 2 - 1, defaultSize - thickness / 2, emptyColor); + }); + + QUnit.test("Test circle with emptyThickness > thickness", function(assert) { + var color = '#ff0000'; + var emptyColor = '#00ff00'; + var thickness = 5; + var emptyThickness = 10; + + var canvas = createCircle({ + value: 0.5, + thickness: thickness, + emptyThickness: emptyThickness, + fill: { color: color }, + emptyFill: emptyColor, + animation: false + }).circleProgress('widget'); + var defaultSize = $.circleProgress.defaults.size; + + assert.pixelHex(canvas, defaultSize / 2 - 1, 1, emptyColor); + assert.pixelHex(canvas, defaultSize / 2 - 1, defaultSize - emptyThickness / 2, emptyColor); + assert.pixelHex(canvas, defaultSize / 2 - 1, emptyThickness / 2, color); + }); + QUnit.module("Layout tests with animation"); QUnit.test("Test circle with value = 0.5 and solid fill", function(assert) { @@ -264,4 +305,36 @@ assert.equal(50, $(canvas).height()); assert.equal(50, canvas.width); }); -})(); \ No newline at end of file + + QUnit.module("Value tests"); + + QUnit.test("Test that `emptyThickness` defaults to `thickness`", function (assert) { + var thickness = 10; + var canvas = createCircle({ + value: 0, + thickness: thickness + }); + + assert.strictEqual(canvas.data('circle-progress').getEmptyThickness(), thickness); + }); + + $.each([ + [1, 10], + [6, 6], + [20, 0.1] + ], function (i, testData) { + var thickness = testData[0], + emptyThickness = testData[1], + defaultSize = $.circleProgress.defaults.size;; + + QUnit.test("Test that the arc radius is properly calculated with thickness = " + String(thickness) + " and emptyThickness = " + String(emptyThickness), function (assert) { + var canvas = createCircle({ + thickness: thickness, + emptyThickness: emptyThickness + }); + + assert.strictEqual(canvas.data('circle-progress').getArcRadius(), + (defaultSize - Math.max(emptyThickness, thickness)) / 2); + }); + }); +})(); From fe16684bb56332a3fca7a6767d7f49d2df98d717 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Tue, 12 Sep 2017 15:39:34 +0300 Subject: [PATCH 07/12] Wrap up changes --- dist/circle-progress.js | 3 +-- dist/circle-progress.min.js | 2 +- docs/index.html | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index f75a861..090ba34 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -379,8 +379,7 @@ var ctx = this.ctx, r = this.radius, arcR = this.getArcRadius(), - t = this.getEmptyThickness(), - a = this.startAngle; + t = this.getEmptyThickness(); if (v < 1) { ctx.save(); diff --git a/dist/circle-progress.min.js b/dist/circle-progress.min.js index a4c4053..660ddff 100644 --- a/dist/circle-progress.min.js +++ b/dist/circle-progress.min.js @@ -7,4 +7,4 @@ * @licence MIT * @preserve */ -!function(i){if("function"==typeof define&&define.amd)define(["jquery"],i);else if("object"==typeof module&&module.exports){var t=require("jquery");i(t),module.exports=t}else i(jQuery)}(function(i){function t(i){this.init(i)}t.prototype={value:0,size:100,startAngle:-Math.PI,thickness:"auto",fill:{gradient:["#3aeabb","#fdd250"]},emptyFill:"rgba(0, 0, 0, .1)",animation:{duration:1200,easing:"circleProgressEasing"},animationStartValue:0,reverse:!1,lineCap:"butt",insertMode:"prepend",constructor:t,el:null,canvas:null,ctx:null,radius:0,arcFill:null,lastFrameValue:0,init:function(t){i.extend(this,t),this.radius=this.size/2,this.initWidget(),this.initFill(),this.draw(),this.el.trigger("circle-inited")},initWidget:function(){this.canvas||(this.canvas=i("")["prepend"==this.insertMode?"prependTo":"appendTo"](this.el)[0]);var t=this.canvas;if(t.width=this.size,t.height=this.size,this.ctx=t.getContext("2d"),window.devicePixelRatio>1){var e=window.devicePixelRatio;t.style.width=t.style.height=this.size+"px",t.width=t.height=this.size*e,this.ctx.scale(e,e)}},initFill:function(){function t(){var t=i("")[0];t.width=e.size,t.height=e.size,t.getContext("2d").drawImage(g,0,0,r,r),e.arcFill=e.ctx.createPattern(t,"no-repeat"),e.drawFrame(e.lastFrameValue)}var e=this,a=this.fill,n=this.ctx,r=this.size;if(!a)throw Error("The fill is not specified!");if("string"==typeof a&&(a={color:a}),a.color&&(this.arcFill=a.color),a.gradient){var s=a.gradient;if(1==s.length)this.arcFill=s[0];else if(s.length>1){for(var l=a.gradientAngle||0,o=a.gradientDirection||[r/2*(1-Math.cos(l)),r/2*(1+Math.sin(l)),r/2*(1+Math.cos(l)),r/2*(1-Math.sin(l))],h=n.createLinearGradient.apply(n,o),c=0;c")["prepend"==this.insertMode?"prependTo":"appendTo"](this.el)[0]);var t=this.canvas;if(t.width=this.size,t.height=this.size,this.ctx=t.getContext("2d"),window.devicePixelRatio>1){var e=window.devicePixelRatio;t.style.width=t.style.height=this.size+"px",t.width=t.height=this.size*e,this.ctx.scale(e,e)}},initFill:function(){function t(){var t=i("")[0];t.width=e.size,t.height=e.size,t.getContext("2d").drawImage(g,0,0,n,n),e.arcFill=e.ctx.createPattern(t,"no-repeat"),e.drawFrame(e.lastFrameValue)}var e=this,a=this.fill,s=this.ctx,n=this.size;if(!a)throw Error("The fill is not specified!");if("string"==typeof a&&(a={color:a}),a.color&&(this.arcFill=a.color),a.gradient){var r=a.gradient;if(1==r.length)this.arcFill=r[0];else if(r.length>1){for(var h=a.gradientAngle||0,l=a.gradientDirection||[n/2*(1-Math.cos(h)),n/2*(1+Math.sin(h)),n/2*(1+Math.cos(h)),n/2*(1-Math.sin(h))],o=s.createLinearGradient.apply(s,l),c=0;c

- + From 1d057a44a2e067bd01c283d21977c79551c096d6 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Mon, 4 Dec 2017 14:36:00 +0200 Subject: [PATCH 08/12] Replace `this.radius` with `this.size / 2` --- dist/circle-progress.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index 090ba34..bd1bb94 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -178,13 +178,6 @@ */ 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 @@ -210,7 +203,6 @@ */ init: function(config) { $.extend(this, config); - this.radius = this.size / 2; this.initWidget(); this.initFill(); this.draw(); @@ -349,7 +341,7 @@ return; var ctx = this.ctx, - r = this.radius, + r = this.size / 2, arcR = this.getArcRadius(), t = this.getThickness(), a = this.startAngle; @@ -377,7 +369,7 @@ */ drawEmptyArc: function(v) { var ctx = this.ctx, - r = this.radius, + r = this.size / 2, arcR = this.getArcRadius(), t = this.getEmptyThickness(); @@ -462,7 +454,7 @@ * @returns {number} */ getArcRadius: function() { - return this.radius - Math.max(this.getThickness(), this.getEmptyThickness()) / 2; + return (this.size / 2) - Math.max(this.getThickness(), this.getEmptyThickness()) / 2; }, /** From a03e48112ea44fae68a314e938debe7afb39bbd2 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Mon, 4 Dec 2017 14:37:52 +0200 Subject: [PATCH 09/12] Rename `getArcRadius` to `getRadius` --- dist/circle-progress.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index bd1bb94..ffeb8ea 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -342,7 +342,7 @@ var ctx = this.ctx, r = this.size / 2, - arcR = this.getArcRadius(), + arcR = this.getRadius(), t = this.getThickness(), a = this.startAngle; @@ -370,7 +370,7 @@ drawEmptyArc: function(v) { var ctx = this.ctx, r = this.size / 2, - arcR = this.getArcRadius(), + arcR = this.getRadius(), t = this.getEmptyThickness(); if (v < 1) { @@ -453,7 +453,7 @@ * @private * @returns {number} */ - getArcRadius: function() { + getRadius: function() { return (this.size / 2) - Math.max(this.getThickness(), this.getEmptyThickness()) / 2; }, From 3be50dc3496a87b0e7d4edd2144aab2d8d18b5f6 Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Mon, 4 Dec 2017 14:38:16 +0200 Subject: [PATCH 10/12] Remove unnecessary `if` block --- dist/circle-progress.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index ffeb8ea..3e4befa 100644 --- a/dist/circle-progress.js +++ b/dist/circle-progress.js @@ -377,11 +377,7 @@ ctx.save(); ctx.beginPath(); - if (this.reverse) { - ctx.arc(r, r, arcR, 0, Math.PI * 2); - } else { - ctx.arc(r, r, arcR, Math.PI * 2, 0); - } + ctx.arc(r, r, arcR, 0, Math.PI * 2); ctx.lineWidth = t; ctx.strokeStyle = this.emptyFill; From a9838eb4889e9c0e4a2aa249d4e390a0c9783c8c Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Mon, 4 Dec 2017 14:42:04 +0200 Subject: [PATCH 11/12] Fix failing tests because of renaming --- tests/tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests.js b/tests/tests.js index 7b0a244..623b403 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -333,7 +333,7 @@ emptyThickness: emptyThickness }); - assert.strictEqual(canvas.data('circle-progress').getArcRadius(), + assert.strictEqual(canvas.data('circle-progress').getRadius(), (defaultSize - Math.max(emptyThickness, thickness)) / 2); }); }); From b46a9ba4de78e518e1a72bda7a6a4199c7e7ad0f Mon Sep 17 00:00:00 2001 From: Cosmin Stamate Date: Mon, 4 Dec 2017 14:42:14 +0200 Subject: [PATCH 12/12] Build minified distribution file --- dist/circle-progress.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/circle-progress.min.js b/dist/circle-progress.min.js index 660ddff..4f39f58 100644 --- a/dist/circle-progress.min.js +++ b/dist/circle-progress.min.js @@ -7,4 +7,4 @@ * @licence MIT * @preserve */ -!function(i){if("function"==typeof define&&define.amd)define(["jquery"],i);else if("object"==typeof module&&module.exports){var t=require("jquery");i(t),module.exports=t}else i(jQuery)}(function(i){function t(i){this.init(i)}t.prototype={value:0,size:100,startAngle:-Math.PI,thickness:"auto",emptyThickness:"auto",fill:{gradient:["#3aeabb","#fdd250"]},emptyFill:"rgba(0, 0, 0, .1)",animation:{duration:1200,easing:"circleProgressEasing"},animationStartValue:0,reverse:!1,lineCap:"butt",insertMode:"prepend",constructor:t,el:null,canvas:null,ctx:null,radius:0,arcFill:null,lastFrameValue:0,init:function(t){i.extend(this,t),this.radius=this.size/2,this.initWidget(),this.initFill(),this.draw(),this.el.trigger("circle-inited")},initWidget:function(){this.canvas||(this.canvas=i("")["prepend"==this.insertMode?"prependTo":"appendTo"](this.el)[0]);var t=this.canvas;if(t.width=this.size,t.height=this.size,this.ctx=t.getContext("2d"),window.devicePixelRatio>1){var e=window.devicePixelRatio;t.style.width=t.style.height=this.size+"px",t.width=t.height=this.size*e,this.ctx.scale(e,e)}},initFill:function(){function t(){var t=i("")[0];t.width=e.size,t.height=e.size,t.getContext("2d").drawImage(g,0,0,n,n),e.arcFill=e.ctx.createPattern(t,"no-repeat"),e.drawFrame(e.lastFrameValue)}var e=this,a=this.fill,s=this.ctx,n=this.size;if(!a)throw Error("The fill is not specified!");if("string"==typeof a&&(a={color:a}),a.color&&(this.arcFill=a.color),a.gradient){var r=a.gradient;if(1==r.length)this.arcFill=r[0];else if(r.length>1){for(var h=a.gradientAngle||0,l=a.gradientDirection||[n/2*(1-Math.cos(h)),n/2*(1+Math.sin(h)),n/2*(1+Math.cos(h)),n/2*(1-Math.sin(h))],o=s.createLinearGradient.apply(s,l),c=0;c")["prepend"==this.insertMode?"prependTo":"appendTo"](this.el)[0]);var t=this.canvas;if(t.width=this.size,t.height=this.size,this.ctx=t.getContext("2d"),window.devicePixelRatio>1){var e=window.devicePixelRatio;t.style.width=t.style.height=this.size+"px",t.width=t.height=this.size*e,this.ctx.scale(e,e)}},initFill:function(){function t(){var t=i("")[0];t.width=e.size,t.height=e.size,t.getContext("2d").drawImage(g,0,0,n,n),e.arcFill=e.ctx.createPattern(t,"no-repeat"),e.drawFrame(e.lastFrameValue)}var e=this,a=this.fill,s=this.ctx,n=this.size;if(!a)throw Error("The fill is not specified!");if("string"==typeof a&&(a={color:a}),a.color&&(this.arcFill=a.color),a.gradient){var r=a.gradient;if(1==r.length)this.arcFill=r[0];else if(r.length>1){for(var h=a.gradientAngle||0,l=a.gradientDirection||[n/2*(1-Math.cos(h)),n/2*(1+Math.sin(h)),n/2*(1+Math.cos(h)),n/2*(1-Math.sin(h))],o=s.createLinearGradient.apply(s,l),c=0;c