diff --git a/CHANGELOG.md b/CHANGELOG.md index e0efbdcdfe8..6b0a69b3ec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [next] + +- fix(fabric.EraserBrush): test eraser intersection with objects taking into account canvas viewport transform [#7147](https://github.com/fabricjs/fabric.js/pull/7147) +- fix(fabric.Object): support `excludeFromExport` set on `clipPath` [#7148](https://github.com/fabricjs/fabric.js/pull/7148). +- fix(fabric.Group): support `excludeFromExport` set on objects [#7148](https://github.com/fabricjs/fabric.js/pull/7148). +- fix(fabric.StaticCanvas): support `excludeFromExport` set on `backgroundColor`, `overlayColor`, `clipPath` [#7148](https://github.com/fabricjs/fabric.js/pull/7148). + ## [4.5.1] - fix(fabric.Text): fixes decoration rendering when there is a single rendering for full text line [#7104](https://github.com/fabricjs/fabric.js/pull/7104) diff --git a/src/shapes/group.class.js b/src/shapes/group.class.js index 572e024a8b8..f16091e1129 100644 --- a/src/shapes/group.class.js +++ b/src/shapes/group.class.js @@ -240,13 +240,17 @@ */ toObject: function(propertiesToInclude) { var _includeDefaultValues = this.includeDefaultValues; - var objsToObject = this._objects.map(function(obj) { - var originalDefaults = obj.includeDefaultValues; - obj.includeDefaultValues = _includeDefaultValues; - var _obj = obj.toObject(propertiesToInclude); - obj.includeDefaultValues = originalDefaults; - return _obj; - }); + var objsToObject = this._objects + .filter(function (obj) { + return !obj.excludeFromExport; + }) + .map(function (obj) { + var originalDefaults = obj.includeDefaultValues; + obj.includeDefaultValues = _includeDefaultValues; + var _obj = obj.toObject(propertiesToInclude); + obj.includeDefaultValues = originalDefaults; + return _obj; + }); var obj = fabric.Object.prototype.toObject.call(this, propertiesToInclude); obj.objects = objsToObject; return obj; diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 5b4c5903b0f..7c1a754bf6e 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -868,7 +868,7 @@ skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS), }; - if (this.clipPath) { + if (this.clipPath && !this.clipPath.excludeFromExport) { object.clipPath = this.clipPath.toObject(propertiesToInclude); object.clipPath.inverted = this.clipPath.inverted; object.clipPath.absolutePositioned = this.clipPath.absolutePositioned; diff --git a/src/static_canvas.class.js b/src/static_canvas.class.js index 6ffd756f250..872f32f06c2 100644 --- a/src/static_canvas.class.js +++ b/src/static_canvas.class.js @@ -1159,7 +1159,7 @@ version: fabric.version, objects: this._toObjects(methodName, propertiesToInclude), }; - if (clipPath) { + if (clipPath && !clipPath.excludeFromExport) { data.clipPath = this._toObject(this.clipPath, methodName, propertiesToInclude); } extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude)); @@ -1202,24 +1202,32 @@ * @private */ __serializeBgOverlay: function(methodName, propertiesToInclude) { - var data = { }, bgImage = this.backgroundImage, overlay = this.overlayImage; + var data = {}, bgImage = this.backgroundImage, overlayImage = this.overlayImage, + bgColor = this.backgroundColor, overlayColor = this.overlayColor; - if (this.backgroundColor) { - data.background = this.backgroundColor.toObject - ? this.backgroundColor.toObject(propertiesToInclude) - : this.backgroundColor; + if (bgColor && bgColor.toObject) { + if (!bgColor.excludeFromExport) { + data.background = bgColor.toObject(propertiesToInclude); + } + } + else if (bgColor) { + data.background = bgColor; } - if (this.overlayColor) { - data.overlay = this.overlayColor.toObject - ? this.overlayColor.toObject(propertiesToInclude) - : this.overlayColor; + if (overlayColor && overlayColor.toObject) { + if (!overlayColor.excludeFromExport) { + data.overlay = overlayColor.toObject(propertiesToInclude); + } + } + else if (overlayColor) { + data.overlay = overlayColor; } + if (bgImage && !bgImage.excludeFromExport) { data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude); } - if (overlay && !overlay.excludeFromExport) { - data.overlayImage = this._toObject(overlay, methodName, propertiesToInclude); + if (overlayImage && !overlayImage.excludeFromExport) { + data.overlayImage = this._toObject(overlayImage, methodName, propertiesToInclude); } return data; diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js index d99c18751c0..ed52518d2db 100644 --- a/test/unit/canvas_static.js +++ b/test/unit/canvas_static.js @@ -1040,31 +1040,57 @@ }); QUnit.test('toObject excludeFromExport', function(assert) { - var rect = makeRect(), rect2 = makeRect(), rect3 = makeRect(); + var rect = makeRect(), rect2 = makeRect(), rect3 = makeRect(), clipPath = makeRect(); canvas.clear(); canvas.add(rect, rect2, rect3); - assert.equal(canvas.toObject().objects.length, 3, 'all objects get exported'); + canvas.clipPath = clipPath; + var canvasObj = canvas.toObject(); + assert.equal(canvasObj.objects.length, 3, 'all objects get exported'); + assert.deepEqual(canvasObj.clipPath, clipPath.toObject(), 'clipPath exported'); rect.excludeFromExport = true; rect2.excludeFromExport = true; - assert.equal(canvas.toObject().objects.length, 1, 'only one object gets exported'); + clipPath.excludeFromExport = true; + canvasObj = canvas.toObject(); + assert.equal(canvasObj.objects.length, 1, 'only one object gets exported'); + assert.equal(canvasObj.clipPath, undefined, 'clipPath not exported'); }); - QUnit.test('toObject excludeFromExport bgImage overlay', function(assert) { + QUnit.test('toObject excludeFromExport bg overlay', function(assert) { var rect = makeRect(), rect2 = makeRect(), rect3 = makeRect(); + var bgColor = new fabric.Gradient({ + type: 'linear', + colorStops: [ + { offset: 0, color: 'black' }, + { offset: 1, color: 'white' }, + ], + coords: { + x1: 0, + x2: 300, + y1: 0, + y2: 0, + }, + }); canvas.clear(); canvas.backgroundImage = rect; canvas.overlayImage = rect2; + canvas.backgroundColor = bgColor; + canvas.setOverlayColor('red'); canvas.add(rect3); var rectToObject = rect.toObject(); var rect2ToObject = rect2.toObject(); + var bgc2ToObject = bgColor.toObject(); var canvasToObject = canvas.toObject(); - assert.deepEqual(canvasToObject.backgroundImage, rectToObject, 'background exported'); - assert.deepEqual(canvasToObject.overlayImage, rect2ToObject, 'overlay exported'); + assert.deepEqual(canvasToObject.backgroundImage, rectToObject, 'background image exported'); + assert.deepEqual(canvasToObject.overlayImage, rect2ToObject, 'overlay image exported'); + assert.deepEqual(canvasToObject.background, bgc2ToObject, 'background color exported'); + assert.equal(canvasToObject.overlay, 'red', 'overlay color exported'); rect.excludeFromExport = true; rect2.excludeFromExport = true; + bgColor.excludeFromExport = true; canvasToObject = canvas.toObject(); - assert.equal(canvasToObject.backgroundImage, undefined, 'background not exported'); - assert.equal(canvasToObject.overlayImage, undefined, 'overlay not exported'); + assert.equal(canvasToObject.backgroundImage, undefined, 'background image not exported'); + assert.equal(canvasToObject.overlayImage, undefined, 'overlay image not exported'); + assert.equal(canvasToObject.background, undefined, 'background color not exported'); }); diff --git a/test/unit/group.js b/test/unit/group.js index 839ec49312f..87359715b22 100644 --- a/test/unit/group.js +++ b/test/unit/group.js @@ -15,6 +15,13 @@ return new fabric.Group([rect1, rect2], {strokeWidth: 0}); } + function makeGroupWith2ObjectsAndNoExport() { + var rect1 = new fabric.Rect({ top: 100, left: 100, width: 30, height: 10, strokeWidth: 0 }), + rect2 = new fabric.Rect({ top: 120, left: 50, width: 10, height: 40, strokeWidth: 0, excludeFromExport: true }); + + return new fabric.Group([rect1, rect2], { strokeWidth: 0 }); + } + function makeGroupWith4Objects() { var rect1 = new fabric.Rect({ top: 100, left: 100, width: 30, height: 10 }), rect2 = new fabric.Rect({ top: 120, left: 50, width: 10, height: 40 }), @@ -226,6 +233,18 @@ assert.deepEqual(clone, expectedObject); }); + + QUnit.test('toObject with excludeFromExport set on an object', function (assert) { + var group = makeGroupWith2Objects(); + var group2 = makeGroupWith2ObjectsAndNoExport(); + var clone = group.toObject(); + var clone2 = group2.toObject(); + assert.deepEqual(clone2.objects, group2._objects.filter(obj => !obj.excludeFromExport).map(obj => obj.toObject())); + delete clone.objects; + delete clone2.objects; + assert.deepEqual(clone, clone2); + }); + QUnit.test('render', function(assert) { var group = makeGroupWith2Objects(); assert.ok(typeof group.render === 'function'); diff --git a/test/unit/object_clipPath.js b/test/unit/object_clipPath.js index fe8ab29d1e2..90033311016 100644 --- a/test/unit/object_clipPath.js +++ b/test/unit/object_clipPath.js @@ -61,6 +61,8 @@ }); expected.clipPath = expectedClipPath; assert.deepEqual(expected, cObj.toObject()); + cObj.clipPath.excludeFromExport = true; + assert.true(cObj.toObject().clipPath === undefined); }); QUnit.test('from object with clipPath', function(assert) {