diff --git a/src/gradient.class.js b/src/gradient.class.js index 0488d748d84..6d57d73ef6a 100644 --- a/src/gradient.class.js +++ b/src/gradient.class.js @@ -135,7 +135,7 @@ for (var position in colorStops) { var color = new fabric.Color(colorStops[position]); this.colorStops.push({ - offset: position, + offset: parseFloat(position), color: color.toRgb(), opacity: color.getAlpha() }); @@ -170,8 +170,8 @@ */ toSVG: function(object) { var coords = fabric.util.object.clone(this.coords), - markup, commonAttributes; - + markup, commonAttributes, colorStops = this.colorStops, + needsSwap = coords.r1 > coords.r2; // colorStops must be sorted ascending this.colorStops.sort(function(a, b) { return a.offset - b.offset; @@ -179,7 +179,7 @@ if (!(object.group && object.group.type === 'path-group')) { for (var prop in coords) { - if (prop === 'x1' || prop === 'x2' || prop === 'r2') { + if (prop === 'x1' || prop === 'x2') { coords[prop] += this.offsetX - object.width / 2; } else if (prop === 'y1' || prop === 'y2') { @@ -205,24 +205,45 @@ ]; } else if (this.type === 'radial') { + // svg radial gradient has just 1 radius. the biggest. markup = [ '\n' ]; } - for (var i = 0; i < this.colorStops.length; i++) { + if (this.type === 'radial') { + if (needsSwap) { + // svg goes from internal to external radius. if radius are inverted, swap color stops. + colorStops = colorStops.concat().reverse(); + for (var i = 0; i < colorStops.length; i++) { + colorStops[i].offset = 1 - colorStops[i].offset; + } + } + var minRadius = Math.min(coords.r1, coords.r2); + if (minRadius > 0) { + // i have to shift all colorStops and add new one in 0. + var maxRadius = Math.max(coords.r1, coords.r2), + percentageShift = minRadius / maxRadius; + for (var i = 0; i < colorStops.length; i++) { + colorStops[i].offset += percentageShift * (1 - colorStops[i].offset); + } + } + } + + for (var i = 0; i < colorStops.length; i++) { + var colorStop = colorStops[i]; markup.push( '\n' ); } @@ -274,7 +295,7 @@ if (typeof opacity !== 'undefined') { color = new fabric.Color(color).setAlpha(opacity).toRgba(); } - gradient.addColorStop(parseFloat(offset), color); + gradient.addColorStop(offset, color); } return gradient; diff --git a/src/parser.js b/src/parser.js index 5918f00a5a1..9ad08962ccf 100644 --- a/src/parser.js +++ b/src/parser.js @@ -615,7 +615,7 @@ var svgUid = fabric.Object.__uid++, options = applyViewboxTransform(doc), descendants = fabric.util.toArray(doc.getElementsByTagName('*')); - options.crossOrigin = parsingOptions.crossOrigin; + options.crossOrigin = parsingOptions && parsingOptions.crossOrigin; options.svgUid = svgUid; if (descendants.length === 0 && fabric.isLikelyNode) { diff --git a/test/unit/gradient.js b/test/unit/gradient.js index fb5a92f852f..12bc6d161bf 100644 --- a/test/unit/gradient.js +++ b/test/unit/gradient.js @@ -36,6 +36,47 @@ }); } + function createRadialGradientWithInternalRadius() { + return new fabric.Gradient({ + type: 'radial', + coords: { + x1: 0, + y1: 10, + x2: 100, + y2: 200, + r1: 10, + r2: 50 + }, + colorStops: [ + { offset: 0, color: 'red' }, + { offset: 1, color: 'green', opacity: 0 } + ] + }); + } + + function createRadialGradientSwapped() { + return new fabric.Gradient({ + type: 'radial', + coords: { + x1: 0, + y1: 10, + x2: 100, + y2: 200, + r1: 50, + r2: 10 + }, + colorStops: [ + { offset: 0, color: 'red' }, + { offset: 1, color: 'green', opacity: 0 } + ] + }); + } + + var SVG_LINEAR = '\n\n\n\n'; + var SVG_RADIAL = '\n\n\n\n'; + var SVG_INTERNALRADIUS = '\n\n\n\n'; + var SVG_SWAPPED = '\n\n\n\n'; + test('constructor linearGradient', function() { ok(fabric.Gradient); @@ -634,10 +675,35 @@ test('toSVG', function() { var gradient = createLinearGradient(); - ok(typeof gradient.toSVG == 'function'); + }); + + test('toSVG linear', function() { + fabric.Object.__uid = 0; + var gradient = createLinearGradient(); + var obj = new fabric.Object({ width: 100, height: 100 }); + equal(gradient.toSVG(obj), SVG_LINEAR); + }); + + test('toSVG radial', function() { + fabric.Object.__uid = 0; + var gradient = createRadialGradient(); + var obj = new fabric.Object({ width: 100, height: 100 }); + equal(gradient.toSVG(obj), SVG_RADIAL); + }); + + test('toSVG radial with r1 > 0', function() { + fabric.Object.__uid = 0; + var gradient = createRadialGradientWithInternalRadius(); + var obj = new fabric.Object({ width: 100, height: 100 }); + equal(gradient.toSVG(obj), SVG_INTERNALRADIUS); + }); - // TODO: test toSVG + test('toSVG radial with r1 > 0', function() { + fabric.Object.__uid = 0; + var gradient = createRadialGradientSwapped(); + var obj = new fabric.Object({ width: 100, height: 100 }); + equal(gradient.toSVG(obj), SVG_SWAPPED); }); })();