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) diff --git a/dist/circle-progress.js b/dist/circle-progress.js index 7a19213..3e4befa 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: * @@ -170,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 @@ -202,7 +203,6 @@ */ init: function(config) { $.extend(this, config); - this.radius = this.size / 2; this.initWidget(); this.initFill(); this.draw(); @@ -341,7 +341,8 @@ return; var ctx = this.ctx, - r = this.radius, + r = this.size / 2, + arcR = this.getRadius(), t = this.getThickness(), a = this.startAngle; @@ -349,9 +350,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; @@ -368,23 +369,15 @@ */ drawEmptyArc: function(v) { var ctx = this.ctx, - r = this.radius, - t = this.getThickness(), - a = this.startAngle; + r = this.size / 2, + arcR = this.getRadius(), + t = this.getEmptyThickness(); 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.arc(r, r, arcR, 0, Math.PI * 2); ctx.lineWidth = t; ctx.strokeStyle = this.emptyFill; @@ -441,6 +434,25 @@ 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(); + }, + + /** + * Returns the real arc radius, after the thickness has been accounted for. + * @private + * @returns {number} + */ + getRadius: function() { + return (this.size / 2) - Math.max(this.getThickness(), this.getEmptyThickness()) / 2; + }, + /** * Get current value. * @protected diff --git a/dist/circle-progress.min.js b/dist/circle-progress.min.js index a4c4053..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",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 custom angle,
value update
+
+ different thicknesses +
+
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"); @@ -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').getRadius(), + (defaultSize - Math.max(emptyThickness, thickness)) / 2); + }); + }); +})();