From d7157d122c0fd26e784f2a54da388fd2e1c84583 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 11 Sep 2016 11:45:25 +0200 Subject: [PATCH 1/5] move backgroundColor to all classes (#3248) --- src/shapes/object.class.js | 28 ++++++++++++++++++++++++++-- src/shapes/text.class.js | 24 +----------------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 2413f46bb77..3c6c68d3628 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -1097,13 +1097,14 @@ if (!noTransform) { this.transform(ctx); } + this._setOpacity(ctx); + this._setShadow(ctx); + this._renderBackground(ctx); this._setStrokeStyles(ctx); this._setFillStyles(ctx); if (this.transformMatrix) { ctx.transform.apply(ctx, this.transformMatrix); } - this._setOpacity(ctx); - this._setShadow(ctx); this.clipTo && fabric.util.clipContext(this, ctx); this._render(ctx, noTransform); this.clipTo && ctx.restore(); @@ -1111,6 +1112,29 @@ ctx.restore(); }, + /** + * Draws a background for the object big as its width and height; + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderBackground: function(ctx) { + if (!this.backgroundColor) { + return; + } + + ctx.fillStyle = this.backgroundColor; + + ctx.fillRect( + -this.width / 2, + -this.height / 2, + this.width, + this.height + ); + // if there is background color no other shadows + // should be casted + this._removeShadow(ctx); + }, + /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index 6575bae1cec..6a9690c9346 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -634,32 +634,10 @@ * @param {CanvasRenderingContext2D} ctx Context to render on */ _renderTextBackground: function(ctx) { - this._renderTextBoxBackground(ctx); + this._renderBackground(ctx); this._renderTextLinesBackground(ctx); }, - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - _renderTextBoxBackground: function(ctx) { - if (!this.backgroundColor) { - return; - } - - ctx.fillStyle = this.backgroundColor; - - ctx.fillRect( - this._getLeftOffset(), - this._getTopOffset(), - this.width, - this.height - ); - // if there is background color no other shadows - // should be casted - this._removeShadow(ctx); - }, - /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on From 5d0bf5a166eefa6de687f59d99ed17d306747a14 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 11 Sep 2016 12:40:57 +0200 Subject: [PATCH 2/5] add custom properties to bg and overlay (#3250) --- src/static_canvas.class.js | 12 ++++++------ test/unit/canvas_static.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/static_canvas.class.js b/src/static_canvas.class.js index 86f4568142a..b87cd9fbc54 100644 --- a/src/static_canvas.class.js +++ b/src/static_canvas.class.js @@ -1066,7 +1066,7 @@ objects: this._toObjects(methodName, propertiesToInclude) }; - extend(data, this.__serializeBgOverlay()); + extend(data, this.__serializeBgOverlay(propertiesToInclude)); fabric.util.populateWithProperties(this, data, propertiesToInclude); @@ -1148,23 +1148,23 @@ /** * @private */ - __serializeBgOverlay: function() { + __serializeBgOverlay: function(propertiesToInclude) { var data = { background: (this.backgroundColor && this.backgroundColor.toObject) - ? this.backgroundColor.toObject() + ? this.backgroundColor.toObject(propertiesToInclude) : this.backgroundColor }; if (this.overlayColor) { data.overlay = this.overlayColor.toObject - ? this.overlayColor.toObject() + ? this.overlayColor.toObject(propertiesToInclude) : this.overlayColor; } if (this.backgroundImage) { - data.backgroundImage = this.backgroundImage.toObject(); + data.backgroundImage = this.backgroundImage.toObject(propertiesToInclude); } if (this.overlayImage) { - data.overlayImage = this.overlayImage.toObject(); + data.overlayImage = this.overlayImage.toObject(propertiesToInclude); } return data; diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js index 49a489ef438..4d16a445bd7 100644 --- a/test/unit/canvas_static.js +++ b/test/unit/canvas_static.js @@ -170,12 +170,23 @@ ok('backgroundImage' in canvas); ok('overlayImage' in canvas); ok('clipTo' in canvas); + ok('includeDefaultValues' in canvas); + ok('stateful' in canvas); + ok('renderOnAddRemove' in canvas); + ok('controlsAboveOverlay' in canvas); + ok('allowTouchScrolling' in canvas); + ok('imageSmoothingEnabled' in canvas); + ok('backgroundVpt' in canvas); + ok('overlayVpt' in canvas); equal(canvas.includeDefaultValues, true); equal(canvas.stateful, true); equal(canvas.renderOnAddRemove, true); equal(canvas.controlsAboveOverlay, false); + equal(canvas.allowTouchScrolling, false); equal(canvas.imageSmoothingEnabled, true); + equal(canvas.backgroundVpt, true); + equal(canvas.overlayVpt, true); notStrictEqual(canvas.viewportTransform, canvas2.viewportTransform); }); @@ -766,6 +777,17 @@ }); }); + asyncTest('toJSON backgroundImage with custom props', function() { + createImageObject(function(image) { + canvas.backgroundImage = image; + image.custom = 'yes'; + var json = canvas.toJSON(['custom']); + equal(json.backgroundImage.custom, 'yes'); + canvas.backgroundImage = null; + start(); + }); + }); + asyncTest('toJSON overlayImage', function() { createImageObject(function(image) { @@ -782,6 +804,17 @@ }); }); + asyncTest('toJSON overlayImage with custom props', function() { + createImageObject(function(image) { + canvas.overlayImage = image; + image.custom = 'yes'; + var json = canvas.toJSON(['custom']); + equal(json.overlayImage.custom, 'yes'); + canvas.overlayImage = null; + start(); + }); + }); + test('toDatalessJSON', function() { var path = new fabric.Path('M 100 100 L 300 100 L 200 300 z', { sourcePath: 'http://example.com/' From 365b257869dca1a33669c05a78736d9f8c2f6f6e Mon Sep 17 00:00:00 2001 From: Asturur Date: Sun, 11 Sep 2016 14:49:54 +0200 Subject: [PATCH 3/5] update function and test --- src/mixins/object_geometry.mixin.js | 17 +++++++++++------ test/unit/object.js | 8 ++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/mixins/object_geometry.mixin.js b/src/mixins/object_geometry.mixin.js index fd78e6a5c36..86af5113199 100644 --- a/src/mixins/object_geometry.mixin.js +++ b/src/mixins/object_geometry.mixin.js @@ -48,7 +48,9 @@ getCoords(other.oCoords) ); - return intersection.status === 'Intersection'; + return intersection.status === 'Intersection' + && !other.isContainedWithinObject(this) + && !this.isContainedWithinObject(other); }, /** @@ -57,11 +59,14 @@ * @return {Boolean} true if object is fully contained within area of another object */ isContainedWithinObject: function(other) { - var boundingRect = other.getBoundingRect(), - point1 = new fabric.Point(boundingRect.left, boundingRect.top), - point2 = new fabric.Point(boundingRect.left + boundingRect.width, boundingRect.top + boundingRect.height); - - return this.isContainedWithinRect(point1, point2); + var points = getCoords(this.oCoords), + i = 0; + for (; i < 4; i++) { + if (!other.containsPoint(points[i])) { + return false; + } + } + return true; }, /** diff --git a/test/unit/object.js b/test/unit/object.js index 4fff8a02d45..83acaf20eae 100644 --- a/test/unit/object.js +++ b/test/unit/object.js @@ -1338,10 +1338,10 @@ }); test('isContainedWithinObject', function() { - var object = new fabric.Object({ left: 20, top: 30, width: 40, height: 50, angle: 230 }), - object1 = new fabric.Object({ left: 25, top: 35, width: 20, height: 20, angle: 50 }), - object2 = new fabric.Object({ left: 20, top: 30, width: 60, height: 30, angle: 10 }), - object3 = new fabric.Object({ left: 50, top: 50, width: 20, height: 20, angle: 0 }); + var object = new fabric.Object({ left: 0, top: 0, width: 40, height: 40, angle: 0 }), + object1 = new fabric.Object({ left: 1, top: 1, width: 40, height: 40, angle: 0 }), + object2 = new fabric.Object({ left: 20, top: 20, width: 40, height: 40, angle: 0 }), + object3 = new fabric.Object({ left: 50, top: 50, width: 40, height: 40, angle: 0 }); object.set({ originX: 'center', originY: 'center' }).setCoords(); object1.set({ originX: 'center', originY: 'center' }).setCoords(); From ff2810a5c0275d4243587353c2a157497da56289 Mon Sep 17 00:00:00 2001 From: Asturur Date: Sun, 11 Sep 2016 15:39:13 +0200 Subject: [PATCH 4/5] fix interset with object and overlap --- src/mixins/object_geometry.mixin.js | 4 +- test/unit/object.js | 64 +++++++++++++++++++---------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/mixins/object_geometry.mixin.js b/src/mixins/object_geometry.mixin.js index 86af5113199..8e1943496fd 100644 --- a/src/mixins/object_geometry.mixin.js +++ b/src/mixins/object_geometry.mixin.js @@ -49,8 +49,8 @@ ); return intersection.status === 'Intersection' - && !other.isContainedWithinObject(this) - && !this.isContainedWithinObject(other); + || other.isContainedWithinObject(this) + || this.isContainedWithinObject(other); }, /** diff --git a/test/unit/object.js b/test/unit/object.js index 83acaf20eae..ae06cfe9ad1 100644 --- a/test/unit/object.js +++ b/test/unit/object.js @@ -719,17 +719,22 @@ test('intersectsWithObject', function() { var cObj = new fabric.Object({ left: 50, top: 50, width: 100, height: 100 }); cObj.setCoords(); - ok(typeof cObj.intersectsWithObject == 'function'); + ok(typeof cObj.intersectsWithObject == 'function', 'has intersectsWithObject method'); var cObj2 = new fabric.Object({ left: -150, top: -150, width: 200, height: 200 }); cObj2.setCoords(); - ok(cObj.intersectsWithObject(cObj2)); - ok(cObj2.intersectsWithObject(cObj)); + ok(cObj.intersectsWithObject(cObj2), 'cobj2 does intersect with cobj'); + ok(cObj2.intersectsWithObject(cObj), 'cobj2 does intersect with cobj'); var cObj3 = new fabric.Object({ left: 392.5, top: 339.5, width: 13, height: 33 }); cObj3.setCoords(); - ok(!cObj.intersectsWithObject(cObj3)); - ok(!cObj3.intersectsWithObject(cObj)); + ok(!cObj.intersectsWithObject(cObj3), 'cobj3 does not intersect with cobj (external)'); + ok(!cObj3.intersectsWithObject(cObj), 'cobj3 does not intersect with cobj (external)'); + + var cObj4 = new fabric.Object({ left: 0, top: 0, width: 200, height: 200 }); + cObj4.setCoords(); + ok(cObj4.intersectsWithObject(cObj), 'overlapping objects are considered intersecting'); + ok(cObj.intersectsWithObject(cObj4), 'overlapping objects are considered intersecting'); }); test('isContainedWithinRect', function() { @@ -1329,31 +1334,46 @@ object2.set({ originX: 'center', originY: 'center' }).setCoords(); object3.set({ originX: 'center', originY: 'center' }).setCoords(); - // object and object1 intersects - equal(object.intersectsWithObject(object1), true); - // object2 is contained in object (no intersection) - equal(object.intersectsWithObject(object2), false); - // object3 is outside of object (no intersection) - equal(object.intersectsWithObject(object3), false); + equal(object.intersectsWithObject(object1), true, 'object and object1 intersects'); + equal(object.intersectsWithObject(object2), true, 'object2 is contained in object'); + equal(object.intersectsWithObject(object3), false, 'object3 is outside of object (no intersection)'); }); test('isContainedWithinObject', function() { var object = new fabric.Object({ left: 0, top: 0, width: 40, height: 40, angle: 0 }), - object1 = new fabric.Object({ left: 1, top: 1, width: 40, height: 40, angle: 0 }), + object1 = new fabric.Object({ left: 1, top: 1, width: 38, height: 38, angle: 0 }), object2 = new fabric.Object({ left: 20, top: 20, width: 40, height: 40, angle: 0 }), object3 = new fabric.Object({ left: 50, top: 50, width: 40, height: 40, angle: 0 }); - object.set({ originX: 'center', originY: 'center' }).setCoords(); - object1.set({ originX: 'center', originY: 'center' }).setCoords(); - object2.set({ originX: 'center', originY: 'center' }).setCoords(); - object3.set({ originX: 'center', originY: 'center' }).setCoords(); + object.setCoords(); + object1.setCoords(); + object2.setCoords(); + object3.setCoords(); + + equal(object1.isContainedWithinObject(object), true, 'object1 is fully contained within object'); + equal(object2.isContainedWithinObject(object), false, 'object2 intersects object (not fully contained)'); + equal(object3.isContainedWithinObject(object), false, 'object3 is outside of object (not fully contained)'); + object1.angle = 45; + object1.setCoords(); + equal(object1.isContainedWithinObject(object), false, 'object1 rotated is not contained within object'); + + var rect1 = new fabric.Rect({ + width: 50, + height: 50, + left: 50, + top: 50 + }); - // object1 is fully contained within object - equal(object1.isContainedWithinObject(object), true); - // object2 intersects object (not fully contained) - equal(object2.isContainedWithinObject(object), false); - // object3 is outside of object (not fully contained) - equal(object3.isContainedWithinObject(object), false); + var rect2 = new fabric.Rect({ + width: 100, + height: 100, + left: 100, + top: 0, + angle: 45, + }); + rect1.setCoords(); + rect2.setCoords(); + equal(rect1.isContainedWithinObject(rect2), false, 'rect1 rotated is not contained within rect2'); }); test('isContainedWithinRect', function() { From e2c908cd2987a5cee26cbda379893d47660f0eac Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 11 Sep 2016 19:50:13 +0200 Subject: [PATCH 5/5] Update canvas_static.js --- test/unit/canvas_static.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js index 636727f6495..9787c5683f3 100644 --- a/test/unit/canvas_static.js +++ b/test/unit/canvas_static.js @@ -172,7 +172,7 @@ ok('clipTo' in canvas); ok('includeDefaultValues' in canvas); ok('stateful' in canvas); - ok('renderOnAddRemove' in canvas); + ok('automaticRender' in canvas); ok('controlsAboveOverlay' in canvas); ok('allowTouchScrolling' in canvas); ok('imageSmoothingEnabled' in canvas);