diff --git a/src/mixins/itext.svg_export.js b/src/mixins/itext.svg_export.js
index 307e77be5c1..5be8ec34586 100644
--- a/src/mixins/itext.svg_export.js
+++ b/src/mixins/itext.svg_export.js
@@ -11,12 +11,11 @@
* @return {String} svg representation of an instance
*/
toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(),
- offsets = this._getSVGLeftTopOffsets(),
- textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
- this._wrapSVGTextAndBg(markup, textAndBg);
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ var offsets = this._getSVGLeftTopOffsets(),
+ textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft),
+ internalMarkup = this._wrapSVGTextAndBg(textAndBg);
+ return this._createBaseSVGMarkup(
+ internalMarkup, { reviver: reviver, noStyle: true, withShadow: true });
},
/**
@@ -33,13 +32,10 @@
/**
* @private
*/
- _wrapSVGTextAndBg: function(markup, textAndBg) {
- var noShadow = true, filter = this.getSvgFilter(),
- style = filter === '' ? '' : ' style="' + filter + '"',
+ _wrapSVGTextAndBg: function(textAndBg) {
+ var noShadow = true,
textDecoration = this.getSvgTextDecoration(this);
- markup.push(
- '\t\n',
+ return [
textAndBg.textBgRects.join(''),
'\t\t',
textAndBg.textSpans.join(''),
- '\n',
- '\t\n'
- );
+ '\n'
+ ];
},
/**
diff --git a/src/mixins/object.svg_export.js b/src/mixins/object.svg_export.js
index 931f5c64eba..47f9058fec1 100644
--- a/src/mixins/object.svg_export.js
+++ b/src/mixins/object.svg_export.js
@@ -29,7 +29,7 @@
*/
getSvgStyles: function(skipShadow) {
- var fillRule = this.fillRule,
+ var fillRule = this.fillRule ? this.fillRule : 'nonzero',
strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',
strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',
@@ -128,45 +128,16 @@
/**
* Returns transform-string for svg-export
+ * @param {Boolean} use the full transform or the single object one.
* @return {String}
*/
- getSvgTransform: function() {
- var angle = this.angle,
- skewX = (this.skewX % 360),
- skewY = (this.skewY % 360),
- center = this.getCenterPoint(),
-
- NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
-
- translatePart = 'translate(' +
- toFixed(center.x, NUM_FRACTION_DIGITS) +
- ' ' +
- toFixed(center.y, NUM_FRACTION_DIGITS) +
- ')',
-
- anglePart = angle !== 0
- ? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')')
- : '',
-
- scalePart = (this.scaleX === 1 && this.scaleY === 1)
- ? '' :
- (' scale(' +
- toFixed(this.scaleX, NUM_FRACTION_DIGITS) +
- ' ' +
- toFixed(this.scaleY, NUM_FRACTION_DIGITS) +
- ')'),
-
- skewXPart = skewX !== 0 ? ' skewX(' + toFixed(skewX, NUM_FRACTION_DIGITS) + ')' : '',
-
- skewYPart = skewY !== 0 ? ' skewY(' + toFixed(skewY, NUM_FRACTION_DIGITS) + ')' : '',
-
- flipXPart = this.flipX ? ' matrix(-1 0 0 1 0 0) ' : '',
-
- flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 0)' : '';
-
- return [
- translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart
- ].join('');
+ getSvgTransform: function(full, additionalTransform) {
+ var transform = full ? this.calcTransformMatrix() : this.calcOwnMatrix(),
+ svgTransform = transform.map(function(value) {
+ return toFixed(value, fabric.Object.NUM_FRACTION_DIGITS);
+ }).join(' ');
+ return 'transform="matrix(' + svgTransform + ')' +
+ (additionalTransform || '') + this.getSvgTransformMatrix() + '" ';
},
/**
@@ -174,7 +145,7 @@
* @return {String}
*/
getSvgTransformMatrix: function() {
- return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ') ' : '';
+ return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ')' : '';
},
_setSVGBg: function(textBgRects) {
@@ -195,12 +166,77 @@
}
},
+ /**
+ * Returns svg representation of an instance
+ * @param {Function} [reviver] Method for further parsing of svg representation.
+ * @return {String} svg representation of an instance
+ */
+ toSVG: function(reviver) {
+ return this._createBaseSVGMarkup(this._toSVG(), { reviver: reviver });
+ },
+
+ /**
+ * Returns svg clipPath representation of an instance
+ * @param {Function} [reviver] Method for further parsing of svg representation.
+ * @return {String} svg representation of an instance
+ */
+ toClipPathSVG: function(reviver) {
+ return '\t' + this._createBaseClipPathSVGMarkup(this._toSVG(), { reviver: reviver });
+ },
+
/**
* @private
*/
- _createBaseSVGMarkup: function() {
- var markup = [], clipPath = this.clipPath;
+ _createBaseClipPathSVGMarkup: function(objectMarkup, options) {
+ options = options || {};
+ var reviver = options.reviver,
+ additionalTransform = options.additionalTransform || '',
+ commonPieces = [
+ this.getSvgTransform(true, additionalTransform),
+ this.getSvgCommons(),
+ ].join(''),
+ // insert commons in the markup, style and svgCommons
+ index = objectMarkup.indexOf('COMMON_PARTS');
+ objectMarkup[index] = commonPieces;
+ return reviver ? reviver(objectMarkup.join('')) : objectMarkup.join('');
+ },
+ /**
+ * @private
+ */
+ _createBaseSVGMarkup: function(objectMarkup, options) {
+ options = options || {};
+ var noStyle = options.noStyle, withShadow = options.withShadow,
+ reviver = options.reviver,
+ styleInfo = noStyle ? '' : 'style="' + this.getSvgStyles() + '" ',
+ shadowInfo = withShadow ? 'style="' + this.getSvgFilter() + '" ' : '',
+ clipPath = this.clipPath,
+ absoluteClipPath = this.clipPath && this.clipPath.absolutePositioned,
+ commonPieces, markup = [], clipPathMarkup,
+ // insert commons in the markup, style and svgCommons
+ index = objectMarkup.indexOf('COMMON_PARTS');
+ if (clipPath) {
+ clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
+ clipPathMarkup = '\n' +
+ this.clipPath.toClipPathSVG(reviver) +
+ '\n';
+ }
+ if (absoluteClipPath) {
+ markup.push(
+ '\n'
+ );
+ }
+ markup.push(
+ '\n'
+ );
+ commonPieces = [
+ styleInfo,
+ noStyle ? '' : this.addPaintOrder(), ' '
+ ].join('');
+ objectMarkup[index] = commonPieces;
if (this.fill && this.fill.toLive) {
markup.push(this.fill.toSVG(this, false));
}
@@ -211,14 +247,12 @@
markup.push(this.shadow.toSVG(this));
}
if (clipPath) {
- clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
- markup.push(
- '\n\t',
- this.clipPath.toSVG(),
- '\n'
- );
+ markup.push(clipPathMarkup);
}
- return markup;
+ markup.push(objectMarkup.join(''));
+ markup.push('\n');
+ absoluteClipPath && markup.push('\n');
+ return reviver ? reviver(markup.join('')) : markup.join('');
},
addPaintOrder: function() {
diff --git a/src/shapes/circle.class.js b/src/shapes/circle.class.js
index 25f7a4fc56c..2cc6a72bd6d 100644
--- a/src/shapes/circle.class.js
+++ b/src/shapes/circle.class.js
@@ -78,26 +78,23 @@
},
/* _TO_SVG_START_ */
+
/**
* Returns svg representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(), x = 0, y = 0,
+ _toSVG: function() {
+ var svgString, x = 0, y = 0,
angle = (this.endAngle - this.startAngle) % ( 2 * pi);
if (angle === 0) {
- markup.push(
- '\n'
- );
+ '" />\n'
+ ];
}
else {
var startX = fabric.util.cos(this.startAngle) * this.radius,
@@ -105,20 +102,14 @@
endX = fabric.util.cos(this.endAngle) * this.radius,
endY = fabric.util.sin(this.endAngle) * this.radius,
largeFlag = angle > pi ? '1' : '0';
-
- markup.push(
+ svgString = [
'\n'
- );
+ '"', 'COMMON_PARTS', ' />\n'
+ ];
}
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ return svgString;
},
/* _TO_SVG_END_ */
diff --git a/src/shapes/ellipse.class.js b/src/shapes/ellipse.class.js
index 0492a3002d6..bad5c55dbba 100644
--- a/src/shapes/ellipse.class.js
+++ b/src/shapes/ellipse.class.js
@@ -105,24 +105,17 @@
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup();
- markup.push(
- '\n'
- );
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ '" />\n'
+ ];
},
/* _TO_SVG_END_ */
diff --git a/src/shapes/group.class.js b/src/shapes/group.class.js
index 95b53f54834..ebdda3e54c8 100644
--- a/src/shapes/group.class.js
+++ b/src/shapes/group.class.js
@@ -521,24 +521,30 @@
* @return {String} svg representation of an instance
*/
toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup();
- markup.push(
- '\n'
- );
+ var svgString = [];
for (var i = 0, len = this._objects.length; i < len; i++) {
- markup.push('\t', this._objects[i].toSVG(reviver));
+ svgString.push('\t', this._objects[i].toSVG(reviver));
}
- markup.push('\n');
+ return this._createBaseSVGMarkup(
+ svgString,
+ { reviver: reviver, noStyle: true, withShadow: true });
+ },
+
+ /**
+ * Returns svg clipPath representation of an instance
+ * @param {Function} [reviver] Method for further parsing of svg representation.
+ * @return {String} svg representation of an instance
+ */
+ toClipPathSVG: function(reviver) {
+ var svgString = [];
+
+ for (var i = 0, len = this._objects.length; i < len; i++) {
+ svgString.push('\t', this._objects[i].toClipPathSVG(reviver));
+ }
- return reviver ? reviver(markup.join('')) : markup.join('');
+ return this._createBaseClipPathSVGMarkup(svgString, { reviver: reviver });
},
/* _TO_SVG_END_ */
});
diff --git a/src/shapes/image.class.js b/src/shapes/image.class.js
index 0ac483b0ed2..1a6c9af3def 100644
--- a/src/shapes/image.class.js
+++ b/src/shapes/image.class.js
@@ -286,53 +286,51 @@
/* _TO_SVG_START_ */
/**
- * Returns SVG representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * Returns svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, clipPath = '';
+ _toSVG: function() {
+ var svgString = [], imageMarkup = [], strokeSvg,
+ x = -this.width / 2, y = -this.height / 2, clipPath = '';
if (this.hasCrop()) {
var clipPathId = fabric.Object.__uid++;
- markup.push(
+ svgString.push(
'\n',
'\t\n',
'\n'
);
clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
}
- markup.push('\n');
- var imageMarkup = ['\t\n'];
- if (this.paintFirst === 'fill') {
- Array.prototype.push.apply(markup, imageMarkup);
- }
+ '>\n');
+
if (this.stroke || this.strokeDashArray) {
var origFill = this.fill;
this.fill = null;
- markup.push(
+ strokeSvg = [
'\t\n'
- );
+ ];
this.fill = origFill;
}
if (this.paintFirst !== 'fill') {
- Array.prototype.push.apply(markup, imageMarkup);
+ svgString = svgString.concat(strokeSvg, imageMarkup);
}
- markup.push('\n');
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ else {
+ svgString = svgString.concat(imageMarkup, strokeSvg);
+ }
+ return svgString;
},
/* _TO_SVG_END_ */
diff --git a/src/shapes/line.class.js b/src/shapes/line.class.js
index 9176c61edaa..26343258ed9 100644
--- a/src/shapes/line.class.js
+++ b/src/shapes/line.class.js
@@ -247,26 +247,20 @@
/* _TO_SVG_START_ */
/**
- * Returns SVG representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * Returns svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(),
- p = this.calcLinePoints();
- markup.push(
- '\n'
- );
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ '" />\n'
+ ];
},
/* _TO_SVG_END_ */
});
diff --git a/src/shapes/path.class.js b/src/shapes/path.class.js
index a81b8964a7a..d4b1b690c77 100644
--- a/src/shapes/path.class.js
+++ b/src/shapes/path.class.js
@@ -8,6 +8,7 @@
extend = fabric.util.object.extend,
_toString = Object.prototype.toString,
drawArc = fabric.util.drawArc,
+ toFixed = fabric.util.toFixed,
commandLengths = {
m: 2,
l: 2,
@@ -466,29 +467,39 @@
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var chunks = [],
- markup = this._createBaseSVGMarkup(), addTransform = '';
-
- for (var i = 0, len = this.path.length; i < len; i++) {
- chunks.push(this.path[i].join(' '));
- }
- var path = chunks.join(' ');
- addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') ';
- markup.push(
- '\n'
- );
+ ];
+ },
- return reviver ? reviver(markup.join('')) : markup.join('');
+ _getOffsetTransform: function() {
+ var digits = fabric.Object.NUM_FRACTION_DIGITS;
+ return ' translate(' + toFixed(-this.pathOffset.x, digits) + ', ' +
+ toFixed(-this.pathOffset.y, digits) + ')';
+ },
+
+ /**
+ * Returns svg clipPath representation of an instance
+ * @param {Function} [reviver] Method for further parsing of svg representation.
+ * @return {String} svg representation of an instance
+ */
+ toClipPathSVG: function(reviver) {
+ var additionalTransform = this._getOffsetTransform();
+ return '\t' + this._createBaseClipPathSVGMarkup(
+ this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform }
+ );
},
/* _TO_SVG_END_ */
diff --git a/src/shapes/polyline.class.js b/src/shapes/polyline.class.js
index 42d7efc29bd..b01601aa33e 100644
--- a/src/shapes/polyline.class.js
+++ b/src/shapes/polyline.class.js
@@ -117,12 +117,11 @@
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
+ _toSVG: function() {
var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y,
- markup = this._createBaseSVGMarkup(),
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
for (var i = 0, len = this.points.length; i < len; i++) {
@@ -131,17 +130,11 @@
toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' '
);
}
- markup.push(
- '<', this.type, ' ', this.getSvgCommons(),
+ return [
+ '<' + this.type + ' ', 'COMMON_PARTS',
'points="', points.join(''),
- '" style="', this.getSvgStyles(),
- '" transform="', this.getSvgTransform(),
- ' ', this.getSvgTransformMatrix(), '"',
- this.addPaintOrder(),
- '/>\n'
- );
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ '" />\n'
+ ];
},
/* _TO_SVG_END_ */
diff --git a/src/shapes/rect.class.js b/src/shapes/rect.class.js
index 2a3dd1e539c..24d7ca6113f 100644
--- a/src/shapes/rect.class.js
+++ b/src/shapes/rect.class.js
@@ -144,23 +144,18 @@
/* _TO_SVG_START_ */
/**
* Returns svg representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2;
- markup.push(
- '\n');
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ '" />\n'
+ ];
},
/* _TO_SVG_END_ */
});
diff --git a/src/shapes/triangle.class.js b/src/shapes/triangle.class.js
index f171b6f5895..e7226d5ad7e 100644
--- a/src/shapes/triangle.class.js
+++ b/src/shapes/triangle.class.js
@@ -73,31 +73,23 @@
/* _TO_SVG_START_ */
/**
- * Returns SVG representation of an instance
- * @param {Function} [reviver] Method for further parsing of svg representation.
- * @return {String} svg representation of an instance
+ * Returns svg representation of an instance
+ * @return {Array} an array of strings with the specific svg representation
+ * of the instance
*/
- toSVG: function(reviver) {
- var markup = this._createBaseSVGMarkup(),
- widthBy2 = this.width / 2,
+ _toSVG: function() {
+ var widthBy2 = this.width / 2,
heightBy2 = this.height / 2,
points = [
-widthBy2 + ' ' + heightBy2,
'0 ' + -heightBy2,
widthBy2 + ' ' + heightBy2
- ]
- .join(',');
-
- markup.push(
- ''
- );
-
- return reviver ? reviver(markup.join('')) : markup.join('');
+ '" />'
+ ];
},
/* _TO_SVG_END_ */
});
diff --git a/src/static_canvas.class.js b/src/static_canvas.class.js
index a3a82af732d..9e05f8d50fc 100644
--- a/src/static_canvas.class.js
+++ b/src/static_canvas.class.js
@@ -1288,7 +1288,7 @@
*/
toSVG: function(options, reviver) {
options || (options = { });
-
+ options.reviver = reviver;
var markup = [];
this._setSVGPreamble(markup, options);
@@ -1296,9 +1296,13 @@
this._setSVGBgOverlayColor(markup, 'backgroundColor');
this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);
-
+ if (this.clipPath) {
+ markup.push('\n');
+ }
this._setSVGObjects(markup, reviver);
-
+ if (this.clipPath) {
+ markup.push('\n');
+ }
this._setSVGBgOverlayColor(markup, 'overlayColor');
this._setSVGBgOverlayImage(markup, 'overlayImage', reviver);
@@ -1361,10 +1365,22 @@
'\n',
this.createSVGFontFacesMarkup(),
this.createSVGRefElementsMarkup(),
+ this.createSVGClipPathMarkup(options),
'\n'
);
},
+ createSVGClipPathMarkup: function(options) {
+ var clipPath = this.clipPath;
+ if (clipPath) {
+ clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;
+ return '\n' +
+ this.clipPath.toClipPathSVG(options.reviver) +
+ '\n';
+ }
+ return '';
+ },
+
/**
* Creates markup containing SVG referenced elements like patterns, gradients etc.
* @return {String}
diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js
index 97b6e9d55dc..e730bad81d1 100644
--- a/test/unit/canvas_static.js
+++ b/test/unit/canvas_static.js
@@ -155,6 +155,7 @@
QUnit.module('fabric.StaticCanvas', {
beforeEach: function() {
+ fabric.Object.__uid = 0;
canvas.clear();
canvas.backgroundColor = fabric.StaticCanvas.prototype.backgroundColor;
canvas.backgroundImage = fabric.StaticCanvas.prototype.backgroundImage;
@@ -866,6 +867,15 @@
canvas.renderOnAddRemove = true;
});
+ QUnit.test('toSVG with a clipPath', function(assert) {
+ var canvasClip = new fabric.StaticCanvas(null, { width: 400, height: 400 });
+ canvasClip.clipPath = new fabric.Rect({ width: 200, height: 200 });
+ canvasClip.add(new fabric.Circle({ radius: 200 }));
+ var svg = canvasClip.toSVG();
+ var expectedSVG = '\n\n';
+ assert.equal(svg, expectedSVG, 'SVG with clipPath should match');
+ });
+
QUnit.test('toSVG with exclude from export background', function(assert) {
var image = fabric.document.createElement('img'),
imageBG = new fabric.Image(image, {width: 0, height: 0}),
@@ -874,7 +884,7 @@
canvas.renderOnAddRemove = false;
canvas.backgroundImage = imageBG;
canvas.overlayImage = imageOL;
- var expectedSVG = '\n\n';
+ var expectedSVG = '\n\n';
var svg1 = canvas.toSVG();
assert.equal(svg1, expectedSVG, 'svg with bg and overlay do not match');
imageBG.excludeFromExport = true;
diff --git a/test/unit/circle.js b/test/unit/circle.js
index 73f5f0e5c9e..a11d51e796f 100644
--- a/test/unit/circle.js
+++ b/test/unit/circle.js
@@ -140,15 +140,17 @@
QUnit.test('toSVG with full circle', function(assert) {
var circle = new fabric.Circle({ width: 100, height: 100, radius: 10 });
var svg = circle.toSVG();
-
- assert.equal(svg, '\n');
+ var svgClipPath = circle.toClipPathSVG();
+ assert.equal(svg, '\n\n\n');
+ assert.equal(svgClipPath, '\t\n', 'circle as clipPath');
});
QUnit.test('toSVG with half circle', function(assert) {
var circle = new fabric.Circle({ width: 100, height: 100, radius: 10, endAngle: Math.PI });
var svg = circle.toSVG();
-
- assert.equal(svg, '\n');
+ var svgClipPath = circle.toClipPathSVG();
+ assert.equal(svg, '\n\n\n');
+ assert.equal(svgClipPath, '\t\n', 'half circle as clipPath');
});
QUnit.test('fromElement', function(assert) {
diff --git a/test/unit/ellipse.js b/test/unit/ellipse.js
index b57203f499a..03c8d6ce36f 100644
--- a/test/unit/ellipse.js
+++ b/test/unit/ellipse.js
@@ -1,6 +1,10 @@
(function(){
- QUnit.module('fabric.Ellipse');
+ QUnit.module('fabric.Ellipse', {
+ beforeEach: function() {
+ fabric.Object.__uid = 0;
+ }
+ });
QUnit.test('constructor', function(assert) {
assert.ok(fabric.Ellipse);
@@ -93,6 +97,25 @@
assert.equal(wasRenderCalled, false, 'should not render when rx/ry are 0');
});
+ QUnit.test('toSVG', function(assert) {
+ var ellipse = new fabric.Ellipse({ rx: 100, ry: 12, fill: 'red', stroke: 'blue' });
+ assert.equal(ellipse.toSVG(), '\n\n\n', 'SVG should match');
+ assert.equal(ellipse.toClipPathSVG(), '\t\n', 'SVG clippath should match');
+ });
+
+ QUnit.test('toSVG with a clipPath', function(assert) {
+ var ellipse = new fabric.Ellipse({ rx: 100, ry: 12, fill: 'red', stroke: 'blue' });
+ ellipse.clipPath = new fabric.Ellipse({ rx: 12, ry: 100, left: 60, top: -50 });
+ assert.equal(ellipse.toSVG(), '\n\n\t\n\n\n\n', 'SVG with clipPath should match');
+ });
+
+ QUnit.test('toSVG with a clipPath absolute positioned', function(assert) {
+ var ellipse = new fabric.Ellipse({ rx: 100, ry: 12, fill: 'red', stroke: 'blue' });
+ ellipse.clipPath = new fabric.Ellipse({ rx: 12, ry: 100, left: 60, top: -50 });
+ ellipse.clipPath.absolutePositioned = true;
+ assert.equal(ellipse.toSVG(), '\n\n\n\t\n\n\n\n\n', 'SVG with clipPath should match');
+ });
+
QUnit.test('fromElement', function(assert) {
assert.ok(typeof fabric.Ellipse.fromElement === 'function');
diff --git a/test/unit/group.js b/test/unit/group.js
index ffadb914456..88f95b7cd9f 100644
--- a/test/unit/group.js
+++ b/test/unit/group.js
@@ -26,6 +26,7 @@
QUnit.module('fabric.Group', {
afterEach: function() {
+ fabric.Object.__uid = 0;
canvas.clear();
canvas.backgroundColor = fabric.Canvas.prototype.backgroundColor;
canvas.calcOffset();
@@ -414,7 +415,32 @@
var group = makeGroupWith2Objects();
assert.ok(typeof group.toSVG === 'function');
- var expectedSVG = '\n\t\n\t\n\n';
+ var expectedSVG = '\n\t\n\n\n\t\n\n\n\n';
+ assert.equal(group.toSVG(), expectedSVG);
+ });
+
+ QUnit.test('toSVG with a clipPath', function(assert) {
+ var group = makeGroupWith2Objects();
+ assert.ok(typeof group.toSVG === 'function');
+ group.clipPath = new fabric.Rect({ width: 100, height: 100 });
+ var expectedSVG = '\n\n\t\n\n\t\n\n\n\t\n\n\n\n';
+ assert.equal(group.toSVG(), expectedSVG);
+ });
+
+ QUnit.test('toSVG with a clipPath absolutePositioned', function(assert) {
+ var group = makeGroupWith2Objects();
+ assert.ok(typeof group.toSVG === 'function');
+ group.clipPath = new fabric.Rect({ width: 100, height: 100 });
+ group.clipPath.absolutePositioned = true;
+ var expectedSVG = '\n\n\n\t\n\n\t\n\n\n\t\n\n\n\n\n';
+ assert.equal(group.toSVG(), expectedSVG);
+ });
+
+ QUnit.test('toSVG with a group as a clipPath', function(assert) {
+ var group = makeGroupWith2Objects();
+ assert.ok(typeof group.toSVG === 'function');
+ group.clipPath = makeGroupWith2Objects();
+ var expectedSVG = '\n\n\t\t\n\t\t\n\n\t\n\n\n\t\n\n\n\n';
assert.equal(group.toSVG(), expectedSVG);
});
diff --git a/test/unit/header.js b/test/unit/header.js
new file mode 100644
index 00000000000..d7afcbc0600
--- /dev/null
+++ b/test/unit/header.js
@@ -0,0 +1,17 @@
+(function() {
+ QUnit.module('fabric header.js');
+
+ QUnit.test('default values', function(assert) {
+ assert.ok(typeof fabric.document !== 'undefined', 'document is set');
+ assert.ok(typeof fabric.window !== 'undefined', 'window is set');
+ assert.ok(typeof fabric.isTouchSupported !== 'undefined', 'isTouchSupported is set');
+ assert.ok(typeof fabric.isLikelyNode !== 'undefined', 'isLikelyNode is set');
+ assert.equal(fabric.SHARED_ATTRIBUTES.length, 17, 'SHARED_ATTRIBUTES is set');
+ });
+
+ QUnit.test('initFilterBackend', function(assert) {
+ assert.ok(typeof fabric.initFilterBackend === 'function', 'initFilterBackend is a function');
+ assert.ok(typeof fabric.maxTextureSize === 'undefined', 'maxTextureSize is not set yet');
+ fabric.initFilterBackend();
+ });
+})();
diff --git a/test/unit/image.js b/test/unit/image.js
index 7b12f1864a8..90f86cdefdb 100644
--- a/test/unit/image.js
+++ b/test/unit/image.js
@@ -220,7 +220,7 @@
});
});
- QUnit.test('toSVG wit crop', function(assert) {
+ QUnit.test('toSVG with crop', function(assert) {
var done = assert.async();
createImageObject(function(image) {
image.cropX = 1;
@@ -228,7 +228,7 @@
image.width -= 2;
image.height -= 2;
fabric.Object.__uid = 1;
- var expectedSVG = '\n\t\n\n\n\t\n\n';
+ var expectedSVG = '\n\n\t\n\n\t\n\n';
assert.equal(image.toSVG(), expectedSVG);
done();
});
@@ -257,7 +257,7 @@
var done = assert.async();
createImageObject(function(image) {
assert.ok(typeof image.toSVG === 'function');
- var expectedSVG = '\n\t\n\n';
+ var expectedSVG = '\n\t\n\n';
assert.equal(image.toSVG(), expectedSVG);
done();
});
diff --git a/test/unit/line.js b/test/unit/line.js
index dda60283d34..667df52d155 100644
--- a/test/unit/line.js
+++ b/test/unit/line.js
@@ -67,6 +67,12 @@
assert.ok(typeof line.complexity === 'function');
});
+ QUnit.test('toSVG', function(assert) {
+ var line = new fabric.Line([11, 12, 13, 14]);
+ var EXPECTED_SVG = '\n\n\n';
+ assert.equal(line.toSVG(), EXPECTED_SVG);
+ });
+
QUnit.test('toObject', function(assert) {
var line = new fabric.Line([11, 12, 13, 14]);
assert.ok(typeof line.toObject === 'function');
diff --git a/test/unit/path.js b/test/unit/path.js
index c21ec004bd0..a7395c2721a 100644
--- a/test/unit/path.js
+++ b/test/unit/path.js
@@ -55,7 +55,11 @@
getPathObject('M 100 100 L 300 100 L 200 300 z', callback);
}
- QUnit.module('fabric.Path');
+ QUnit.module('fabric.Path', {
+ beforeEach: function() {
+ fabric.Object.__uid = 0;
+ }
+ });
QUnit.test('constructor', function(assert) {
var done = assert.async();
@@ -124,11 +128,35 @@
var done = assert.async();
makePathObject(function(path) {
assert.ok(typeof path.toSVG === 'function');
- assert.deepEqual(path.toSVG(), '\n');
+ assert.deepEqual(path.toSVG(), '\n\n\n');
done();
});
});
+ QUnit.test('toSVG with a clipPath path', function(assert) {
+ var done = assert.async();
+ makePathObject(function(path) {
+ makePathObject(function(path2) {
+ path.clipPath = path2;
+ assert.deepEqual(path.toSVG(), '\n\n\t\n\n\n\n', 'path clipPath toSVG should match');
+ done();
+ });
+ });
+ });
+
+
+ QUnit.test('toSVG with a clipPath path absolutePositioned', function(assert) {
+ var done = assert.async();
+ makePathObject(function(path) {
+ makePathObject(function(path2) {
+ path.clipPath = path2;
+ path.clipPath.absolutePositioned = true;
+ assert.deepEqual(path.toSVG(), '\n\n\n\t\n\n\n\n\n', 'path clipPath toSVG absolute should match');
+ done();
+ });
+ });
+ });
+
QUnit.test('path array not shared when cloned', function(assert) {
var done = assert.async();
makePathObject(function(originalPath) {
diff --git a/test/unit/polygon.js b/test/unit/polygon.js
index bc3c4bb61fe..4dbc115bd20 100644
--- a/test/unit/polygon.js
+++ b/test/unit/polygon.js
@@ -80,6 +80,13 @@
assert.deepEqual(objectWithOriginalPoints, REFERENCE_OBJECT);
});
+ QUnit.test('toSVG', function(assert) {
+ var polygon = new fabric.Polygon(getPoints(), { fill: 'red', stroke: 'blue' });
+ assert.ok(typeof polygon.toSVG === 'function');
+ var EXPECTED_SVG = '\n\n\n';
+ assert.deepEqual(polygon.toSVG(), EXPECTED_SVG);
+ });
+
QUnit.test('fromObject', function(assert) {
var done = assert.async();
assert.ok(typeof fabric.Polygon.fromObject === 'function');
diff --git a/test/unit/polyline.js b/test/unit/polyline.js
index cd8e6d01425..0d93bcb6875 100644
--- a/test/unit/polyline.js
+++ b/test/unit/polyline.js
@@ -79,6 +79,13 @@
assert.deepEqual(objectWithOriginalPoints, REFERENCE_OBJECT);
});
+ QUnit.test('toSVG', function(assert) {
+ var polyline = new fabric.Polygon(getPoints(), { fill: 'red', stroke: 'blue' });
+ assert.ok(typeof polyline.toSVG === 'function');
+ var EXPECTED_SVG = '\n\n\n';
+ assert.deepEqual(polyline.toSVG(), EXPECTED_SVG);
+ });
+
QUnit.test('fromObject', function(assert) {
var done = assert.async();
assert.ok(typeof fabric.Polyline.fromObject === 'function');
diff --git a/test/unit/rect.js b/test/unit/rect.js
index 1a23ce5a727..02d8ea9e5c9 100644
--- a/test/unit/rect.js
+++ b/test/unit/rect.js
@@ -172,31 +172,31 @@
var rect = new fabric.Rect({ width: 100, height: 100, rx: 20, ry: 30, strokeWidth: 0 });
var svg = rect.toSVG();
- assert.equal(svg, '\n');
+ assert.equal(svg, '\n\n\n');
});
QUnit.test('toSVG with alpha colors fill', function(assert) {
var rect = new fabric.Rect({ width: 100, height: 100, strokeWidth: 0, fill: 'rgba(255, 0, 0, 0.5)' });
var svg = rect.toSVG();
- assert.equal(svg, '\n');
+ assert.equal(svg, '\n\n\n');
});
QUnit.test('toSVG with id', function(assert) {
var rect = new fabric.Rect({id: 'myRect', width: 100, height: 100, strokeWidth: 0, fill: 'rgba(255, 0, 0, 0.5)' });
var svg = rect.toSVG();
- assert.equal(svg, '\n');
+ assert.equal(svg, '\n\n\n');
});
QUnit.test('toSVG with alpha colors stroke', function(assert) {
var rect = new fabric.Rect({ width: 100, height: 100, strokeWidth: 0, fill: '', stroke: 'rgba(255, 0, 0, 0.5)' });
var svg = rect.toSVG();
- assert.equal(svg, '\n');
+ assert.equal(svg, '\n\n\n');
});
QUnit.test('toSVG with paintFirst set to stroke', function(assert) {
var rect = new fabric.Rect({ width: 100, height: 100, paintFirst: 'stroke' });
var svg = rect.toSVG();
- assert.equal(svg, '\n');
+ assert.equal(svg, '\n\n\n');
});
QUnit.test('toObject without default values', function(assert) {
diff --git a/test/unit/text_to_svg.js b/test/unit/text_to_svg.js
index 590aa6932af..d7d46cada97 100644
--- a/test/unit/text_to_svg.js
+++ b/test/unit/text_to_svg.js
@@ -1,17 +1,17 @@
(function() {
function removeTranslate(str) {
- return str.replace(/translate\(.*?\)/, '');
+ return str.replace(/matrix\(.*?\)/, '');
}
QUnit.module('fabric.Text');
QUnit.test('toSVG', function(assert) {
- var TEXT_SVG = '\t\n\t\tx\n\t\n';
+ var TEXT_SVG = '\n\t\tx\n\n';
var text = new fabric.Text('x');
assert.equal(removeTranslate(text.toSVG()), removeTranslate(TEXT_SVG));
text.set('fontFamily', 'Arial');
assert.equal(removeTranslate(text.toSVG()), removeTranslate(TEXT_SVG.replace('font-family="Times New Roman"', 'font-family="Arial"')));
});
QUnit.test('toSVG justified', function(assert) {
- var TEXT_SVG_JUSTIFIED = '\t\n\t\txxxxxxx y\n\t\n';
+ var TEXT_SVG_JUSTIFIED = '\n\t\txxxxxxx y\n\n';
var text = new fabric.Text('xxxxxx\nx y', {
textAlign: 'justify',
});
@@ -19,13 +19,13 @@
assert.equal(removeTranslate(text.toSVG()), removeTranslate(TEXT_SVG_JUSTIFIED));
});
QUnit.test('toSVG with multiple spaces', function(assert) {
- var TEXT_SVG_MULTIPLESPACES = '\t\n\t\tx y\n\t\n';
+ var TEXT_SVG_MULTIPLESPACES = '\n\t\tx y\n\n';
var text = new fabric.Text('x y');
assert.equal(removeTranslate(text.toSVG()), removeTranslate(TEXT_SVG_MULTIPLESPACES));
});
QUnit.test('toSVG with deltaY', function(assert) {
fabric.Object.NUM_FRACTION_DIGITS = 0;
- var TEXT_SVG = '\t\n\t\txx\n\t\n';
+ var TEXT_SVG = '\n\t\txx\n\n';
var text = new fabric.Text('xx', {
styles: {
0: {
@@ -41,7 +41,7 @@
});
QUnit.test('toSVG with font', function(assert) {
- var TEXT_SVG_WITH_FONT = '\t\n\t\txxxxxxx y\n\t\n';
+ var TEXT_SVG_WITH_FONT = '\n\t\txxxxxxx y\n\n';
var text = new fabric.Text('xxxxxx\nx y', {
textAlign: 'justify',
styles: {0: {
diff --git a/test/visual/svg_export.js b/test/visual/svg_export.js
index fdebbbbc48f..71481268276 100644
--- a/test/visual/svg_export.js
+++ b/test/visual/svg_export.js
@@ -134,7 +134,7 @@
code: clipping3,
golden: 'clipping3.png',
percentage: 0.06,
- disabled: true,
+ disabled: false,
});
function clipping4(canvas, callback) {
@@ -206,7 +206,7 @@
code: clipping5,
golden: 'clipping5.png',
percentage: 0.06,
- disabled: true,
+ disabled: false,
});
function clipping6(canvas, callback) {
@@ -270,7 +270,7 @@
code: clipping7,
golden: 'clipping7.png',
percentage: 0.06,
- disabled: true,
+ disabled: false,
});
function clipping8(canvas, callback) {
@@ -294,7 +294,7 @@
code: clipping8,
golden: 'clipping8.png',
percentage: 0.06,
- disabled: true,
+ disabled: false,
});
function clipping9(canvas, callback) {
@@ -316,7 +316,7 @@
code: clipping9,
golden: 'clipping9.png',
percentage: 0.06,
- disabled: true,
+ disabled: false,
});
tests.forEach(visualTestLoop(fabricCanvas, QUnit));