From 715f866959963b56dc8c745830c6e7153764b5d7 Mon Sep 17 00:00:00 2001 From: maxwellito Date: Wed, 8 Nov 2017 00:38:16 +0000 Subject: [PATCH] Fix #180 : Implement rounded corners on rect element --- dist/vivus.js | 28 +++++++++++++++++++++++----- dist/vivus.min.js | 4 ++-- package.json | 2 +- src/pathformer.js | 26 ++++++++++++++++++++++---- test/unit/pathformer.spec.js | 28 ++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 12 deletions(-) diff --git a/dist/vivus.js b/dist/vivus.js index f63a4b4..e33e15c 100644 --- a/dist/vivus.js +++ b/dist/vivus.js @@ -1,6 +1,6 @@ /** * vivus - JavaScript library to make drawing animation on SVG - * @version v0.4.1 + * @version v0.4.2 * @link https://github.com/maxwellito/vivus * @license MIT */ @@ -123,10 +123,28 @@ Pathformer.prototype.rectToPath = function (element) { width = parseFloat(element.width) || 0, height = parseFloat(element.height) || 0; - newElement.d = 'M' + x + ' ' + y + ' '; - newElement.d += 'L' + (x + width) + ' ' + y + ' '; - newElement.d += 'L' + (x + width) + ' ' + (y + height) + ' '; - newElement.d += 'L' + x + ' ' + (y + height) + ' Z'; + if (element.rx || element.ry) { + var rx = parseInt(element.rx, 10) || -1, + ry = parseInt(element.ry, 10) || -1; + rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2); + ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2); + + newElement.d = 'M ' + (x + rx) + ',' + y + ' ' + + 'L ' + (x + width - rx) + ',' + y + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' + + 'L ' + (x + width) + ',' + (y + height - ry) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' + + 'L ' + (x + rx) + ',' + (y + height) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' + + 'L ' + x + ',' + (y + ry) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y; + } + else { + newElement.d = 'M' + x + ' ' + y + ' ' + + 'L' + (x + width) + ' ' + y + ' ' + + 'L' + (x + width) + ' ' + (y + height) + ' ' + + 'L' + x + ' ' + (y + height) + ' Z'; + } return newElement; }; diff --git a/dist/vivus.min.js b/dist/vivus.min.js index db2d87d..68977de 100644 --- a/dist/vivus.min.js +++ b/dist/vivus.min.js @@ -1,7 +1,7 @@ /** * vivus - JavaScript library to make drawing animation on SVG - * @version v0.4.1 + * @version v0.4.2 * @link https://github.com/maxwellito/vivus * @license MIT */ -"use strict";!function(){function t(t){if("undefined"==typeof t)throw new Error('Pathformer [constructor]: "element" parameter is required');if(t.constructor===String&&(t=document.getElementById(t),!t))throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID');if(!(t instanceof window.SVGElement||t instanceof window.SVGGElement||/^svg$/i.test(t.nodeName)))throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement');this.el=t,this.scan(t)}function e(t,e,n){r(),this.isReady=!1,this.setElement(t,e),this.setOptions(e),this.setCallback(n),this.isReady&&this.init()}t.prototype.TYPES=["line","ellipse","circle","polygon","polyline","rect"],t.prototype.ATTR_WATCH=["cx","cy","points","r","rx","ry","x","x1","x2","y","y1","y2"],t.prototype.scan=function(t){for(var e,r,n,i,a=t.querySelectorAll(this.TYPES.join(",")),o=0;o=this.duration)throw new Error("Vivus [constructor]: delay must be shorter than duration")},e.prototype.setCallback=function(t){if(t&&t.constructor!==Function)throw new Error('Vivus [constructor]: "callback" parameter must be a function');this.callback=t||function(){}},e.prototype.mapping=function(){var t,e,r,n,i,o,s,h;for(h=o=s=0,e=this.el.querySelectorAll("path"),t=0;t1?e.length-1:1),this.reverseStack&&this.map.reverse(),t=0;t=this.frameLength))return this.trace(),this.handle=n(function(){t.drawer()}),void 0;this.stop(),this.currentFrame=this.frameLength,this.trace(),this.selfDestroy&&this.destroy()}this.callback(this),this.instanceCallback&&(this.instanceCallback(this),this.instanceCallback=null)},e.prototype.trace=function(){var t,e,r,n;for(n=this.animTimingFunction(this.currentFrame/this.frameLength)*this.frameLength,t=0;t=o+a*e&&s>=r},e.prototype.getViewportH=function(){var t=this.docElem.clientHeight,e=window.innerHeight;return e>t?e:t},e.prototype.scrollY=function(){return window.pageYOffset||this.docElem.scrollTop},r=function(){e.prototype.docElem||(e.prototype.docElem=window.document.documentElement,n=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),i=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t)}}())},a=function(t,e){var r=parseInt(t,10);return r>=0?r:e},"function"==typeof define&&define.amd?define([],function(){return e}):"object"==typeof exports?module.exports=e:window.Vivus=e}(); \ No newline at end of file +"use strict";!function(){function t(t){if("undefined"==typeof t)throw new Error('Pathformer [constructor]: "element" parameter is required');if(t.constructor===String&&(t=document.getElementById(t),!t))throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID');if(!(t instanceof window.SVGElement||t instanceof window.SVGGElement||/^svg$/i.test(t.nodeName)))throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement');this.el=t,this.scan(t)}function e(t,e,n){r(),this.isReady=!1,this.setElement(t,e),this.setOptions(e),this.setCallback(n),this.isReady&&this.init()}t.prototype.TYPES=["line","ellipse","circle","polygon","polyline","rect"],t.prototype.ATTR_WATCH=["cx","cy","points","r","rx","ry","x","x1","x2","y","y1","y2"],t.prototype.scan=function(t){for(var e,r,n,i,a=t.querySelectorAll(this.TYPES.join(",")),o=0;oo?s:o,0),i/2),s=Math.min(Math.max(0>s?o:s,0),a/2),e.d="M "+(r+o)+","+n+" L "+(r+i-o)+","+n+" A "+o+","+s+",0,0,1,"+(r+i)+","+(n+s)+" L "+(r+i)+","+(n+a-s)+" A "+o+","+s+",0,0,1,"+(r+i-o)+","+(n+a)+" L "+(r+o)+","+(n+a)+" A "+o+","+s+",0,0,1,"+r+","+(n+a-s)+" L "+r+","+(n+s)+" A "+o+","+s+",0,0,1,"+(r+o)+","+n}else e.d="M"+r+" "+n+" L"+(r+i)+" "+n+" L"+(r+i)+" "+(n+a)+" L"+r+" "+(n+a)+" Z";return e},t.prototype.polylineToPath=function(t){var e,r,n={},i=t.points.trim().split(" ");if(-1===t.points.indexOf(",")){var a=[];for(e=0;e=this.duration)throw new Error("Vivus [constructor]: delay must be shorter than duration")},e.prototype.setCallback=function(t){if(t&&t.constructor!==Function)throw new Error('Vivus [constructor]: "callback" parameter must be a function');this.callback=t||function(){}},e.prototype.mapping=function(){var t,e,r,n,i,o,s,h;for(h=o=s=0,e=this.el.querySelectorAll("path"),t=0;t1?e.length-1:1),this.reverseStack&&this.map.reverse(),t=0;t=this.frameLength))return this.trace(),this.handle=n(function(){t.drawer()}),void 0;this.stop(),this.currentFrame=this.frameLength,this.trace(),this.selfDestroy&&this.destroy()}this.callback(this),this.instanceCallback&&(this.instanceCallback(this),this.instanceCallback=null)},e.prototype.trace=function(){var t,e,r,n;for(n=this.animTimingFunction(this.currentFrame/this.frameLength)*this.frameLength,t=0;t=o+a*e&&s>=r},e.prototype.getViewportH=function(){var t=this.docElem.clientHeight,e=window.innerHeight;return e>t?e:t},e.prototype.scrollY=function(){return window.pageYOffset||this.docElem.scrollTop},r=function(){e.prototype.docElem||(e.prototype.docElem=window.document.documentElement,n=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),i=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t)}}())},a=function(t,e){var r=parseInt(t,10);return r>=0?r:e},"function"==typeof define&&define.amd?define([],function(){return e}):"object"==typeof exports?module.exports=e:window.Vivus=e}(); \ No newline at end of file diff --git a/package.json b/package.json index c3a6db6..cbfcd80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vivus", - "version": "0.4.2", + "version": "0.4.3", "description": "JavaScript library to make drawing animation on SVG", "main": "dist/vivus.js", "scripts": { diff --git a/src/pathformer.js b/src/pathformer.js index ec0e9ad..0674713 100755 --- a/src/pathformer.js +++ b/src/pathformer.js @@ -112,10 +112,28 @@ Pathformer.prototype.rectToPath = function (element) { width = parseFloat(element.width) || 0, height = parseFloat(element.height) || 0; - newElement.d = 'M' + x + ' ' + y + ' '; - newElement.d += 'L' + (x + width) + ' ' + y + ' '; - newElement.d += 'L' + (x + width) + ' ' + (y + height) + ' '; - newElement.d += 'L' + x + ' ' + (y + height) + ' Z'; + if (element.rx || element.ry) { + var rx = parseInt(element.rx, 10) || -1, + ry = parseInt(element.ry, 10) || -1; + rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2); + ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2); + + newElement.d = 'M ' + (x + rx) + ',' + y + ' ' + + 'L ' + (x + width - rx) + ',' + y + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' + + 'L ' + (x + width) + ',' + (y + height - ry) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' + + 'L ' + (x + rx) + ',' + (y + height) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' + + 'L ' + x + ',' + (y + ry) + ' ' + + 'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y; + } + else { + newElement.d = 'M' + x + ' ' + y + ' ' + + 'L' + (x + width) + ' ' + y + ' ' + + 'L' + (x + width) + ' ' + (y + height) + ' ' + + 'L' + x + ' ' + (y + height) + ' Z'; + } return newElement; }; diff --git a/test/unit/pathformer.spec.js b/test/unit/pathformer.spec.js index a07ec16..109f4b1 100644 --- a/test/unit/pathformer.spec.js +++ b/test/unit/pathformer.spec.js @@ -130,6 +130,34 @@ describe('Pathformer', function () { expect(output.d.indexOf('0')).not.toEqual(-1); expect(output.d.indexOf('undefined')).toEqual(-1); }); + + it('should apply rounded corners', function () { + var result = 'M 50,10 ' + + 'L 50,10 A 40,20,0,0,1,90,30 ' + + 'L 90,50 A 40,20,0,0,1,50,70 ' + + 'L 50,70 A 40,20,0,0,1,10,50 ' + + 'L 10,30 A 40,20,0,0,1,50,10'; + + var output = Pathformer.prototype.rectToPath({ + x:10, y:10, width:80, height:60, rx:100, ry:20 + }); + + expect(output.d).toEqual(result); + }); + + it('should apply rounded corners even when a value is missing', function () { + var result = 'M 30,10 ' + + 'L 70,10 A 20,20,0,0,1,90,30 ' + + 'L 90,50 A 20,20,0,0,1,70,70 ' + + 'L 30,70 A 20,20,0,0,1,10,50 ' + + 'L 10,30 A 20,20,0,0,1,30,10'; + + var output = Pathformer.prototype.rectToPath({ + x:10, y:10, width:80, height:60, ry:20 + }); + + expect(output.d).toEqual(result); + }); }); // Polyline object