Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ActiveSelection): 🔃 preserveObjectStacking 📌 #7878

Closed
wants to merge 86 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
1a191a7
apply 7744 patch (no binaries)
ShaMan123 Apr 3, 2022
26e8392
apply 7744 patch (binaries)
ShaMan123 Apr 3, 2022
7d793b3
commit #7744 review
ShaMan123 Apr 3, 2022
2708029
patch2
ShaMan123 Apr 4, 2022
02a8ffa
Update spray_brush.class.js
ShaMan123 Apr 4, 2022
0d3690f
enable text editing under group
ShaMan123 Apr 4, 2022
ff0346a
migrate back to isDescendantOf
ShaMan123 Apr 4, 2022
812f02a
render bg
ShaMan123 Apr 4, 2022
053946c
fix(): clear canvas from entire object tree
ShaMan123 Apr 4, 2022
db76c44
fix(): center object in case object is nested
ShaMan123 Apr 4, 2022
04aad5b
Update eraser_brush.mixin.js
ShaMan123 Apr 4, 2022
8c1c535
Update canvas.class.js
ShaMan123 Apr 4, 2022
3fd4af2
Update canvas_events.mixin.js
ShaMan123 Apr 4, 2022
58e9be2
lint
ShaMan123 Apr 4, 2022
c2ef2f5
safeguard from adding group to itself
ShaMan123 Apr 4, 2022
f0145b5
Update object_ancestry.mixin.js
ShaMan123 Apr 4, 2022
cb20b81
patch tests from v6!
ShaMan123 Apr 4, 2022
347f80d
Update canvas_grouping.mixin.js
ShaMan123 Apr 4, 2022
a56d55e
Update canvas.class.js
ShaMan123 Apr 4, 2022
2a426e7
Update group_layout.js
ShaMan123 Apr 4, 2022
5e3fc1f
Update group_layout.js
ShaMan123 Apr 4, 2022
2b1f680
remove redundant logic
ShaMan123 Apr 4, 2022
1ad5cc8
Update canvas_grouping.mixin.js
ShaMan123 Apr 4, 2022
11c828f
fix(): calling sendPointToPlane
ShaMan123 Apr 4, 2022
b6fa3dc
Update group.class.js
ShaMan123 Apr 4, 2022
e9afc89
refactor `enterGroup`
ShaMan123 Apr 4, 2022
d8f8251
invalidate groups after active selection change
ShaMan123 Apr 4, 2022
c58a274
_shouldSetNestedCoords
ShaMan123 Apr 4, 2022
c0f5571
perf(): refrain from `contains`
ShaMan123 Apr 4, 2022
9a223d0
Update canvas_events.mixin.js
ShaMan123 Apr 4, 2022
2d5cc75
Update canvas.class.js
ShaMan123 Apr 4, 2022
01c4a87
Update canvas.class.js
ShaMan123 Apr 4, 2022
2164161
fix(): export svg backgroundColor
ShaMan123 Apr 4, 2022
a5575bd
Update group.js
ShaMan123 Apr 4, 2022
5c56124
backport collection fix to test
ShaMan123 Apr 4, 2022
5e3aaf5
Update group.class.js
ShaMan123 Apr 4, 2022
d53d6b6
lint
ShaMan123 Apr 4, 2022
8e907bb
fix(): target prop on canvas added/removed event
ShaMan123 Apr 5, 2022
f082fc9
fix(): modify handlers strictly on canvas events
ShaMan123 Apr 5, 2022
c2d93db
Merge branch 'master' into v6-group-patch2
ShaMan123 Apr 5, 2022
2f346b0
Update group_layout.js
ShaMan123 Apr 5, 2022
9931a3c
Merge branch 'master' into v6-group-patch2
ShaMan123 Apr 5, 2022
d6f1950
Merge branch 'master' into v6-group-patch1
ShaMan123 Apr 5, 2022
5cb64af
Merge branch 'v6-group-patch1' into v6-group-patch2
ShaMan123 Apr 5, 2022
63cab25
Merge branch 'master' into v6-group-patch2
asturur Apr 7, 2022
21110d3
Update spray_brush.class.js
ShaMan123 Apr 8, 2022
6c141e1
remove merge error
ShaMan123 Apr 9, 2022
465ea96
add some comment
asturur Apr 9, 2022
ffafe66
more comments
asturur Apr 9, 2022
e2d03f0
only a comment and removed an extra negation by swapping a ternary
asturur Apr 9, 2022
3e09114
better invalidation + comment
ShaMan123 Apr 10, 2022
af3430c
fix(): text enterEditing in interactive group
ShaMan123 Apr 10, 2022
67abe2f
fix(): strict ancestors
ShaMan123 Apr 10, 2022
b8477f2
test `findCommonAncestors`
ShaMan123 Apr 10, 2022
d039d04
add strict option + fixes
ShaMan123 Apr 10, 2022
2c49f67
Revert "fix(): strict ancestors"
ShaMan123 Apr 10, 2022
7ba7fa4
fix test
ShaMan123 Apr 10, 2022
de96660
better comments
ShaMan123 Apr 10, 2022
b566158
better comment
ShaMan123 Apr 10, 2022
beaa331
JSDOC
ShaMan123 Apr 10, 2022
c0aea33
remove redundant `len` variable
ShaMan123 Apr 10, 2022
3ec53b4
fix(Collection): `remove` return value
ShaMan123 Apr 10, 2022
1c414cf
typo
ShaMan123 Apr 10, 2022
2c65a5c
adjust tests
ShaMan123 Apr 10, 2022
785433a
Update group.class.js
ShaMan123 Apr 10, 2022
56a2b73
Update collection.mixin.js
ShaMan123 Apr 10, 2022
3df9435
fix(): safegurad from circular refs
ShaMan123 Apr 10, 2022
d49baac
Update group.js
ShaMan123 Apr 10, 2022
31d2107
Update group.js
ShaMan123 Apr 10, 2022
e3f5887
fix(): call super
ShaMan123 Apr 15, 2022
bc91251
fix(): exclude `ActiveSelection` from ancestors
ShaMan123 Apr 15, 2022
1cd9fee
fix(ActiveSelection): `preserveObjectStacking`
ShaMan123 Apr 15, 2022
0d1ee11
fire `object:added` `object:removed
ShaMan123 Apr 15, 2022
0d260d1
rename
ShaMan123 Apr 15, 2022
e80c5c6
test `getParent`
ShaMan123 Apr 16, 2022
456ba51
test added/removed events
ShaMan123 Apr 16, 2022
79b2cb1
test `_updateActiveSelection` stack ordering
ShaMan123 Apr 16, 2022
12f7415
Update canvas.js
ShaMan123 Apr 16, 2022
8e5e3b0
typo
ShaMan123 Apr 16, 2022
f340395
JSDOC
ShaMan123 Apr 16, 2022
23b8d13
Merge branch 'master' into v6-group-patch7
ShaMan123 May 1, 2022
0db189a
Merge branch 'master' into v6-group-patch7
ShaMan123 May 2, 2022
4fed70c
Merge branch 'master' into v6-group-patch7
ShaMan123 Jun 13, 2022
bd0d9f7
Merge branch 'master' into v6-group-patch7
ShaMan123 Jun 16, 2022
9a1cff5
Update group.js
ShaMan123 Jun 16, 2022
9cc3b18
Update group.js
ShaMan123 Jun 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/mixins/canvas_grouping.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,14 @@
}
}
else {
activeSelection.add(target);
// preserveObjectStacking in ActiveSelection
// perf enhancement for large ActiveSelection: consider a binary search of `isInFrontOf`
var insertAt = activeSelection._objects.findIndex(function (obj) {
return obj.isInFrontOf(target);
});
// target might be in front of all other objects
insertAt = insertAt === -1 ? activeSelection._objects.length : insertAt;
activeSelection.insertAt(target, insertAt);
this._hoveredTarget = activeSelection;
this._hoveredTargets = this.targets.concat();
}
Expand Down
22 changes: 18 additions & 4 deletions src/mixins/object_ancestry.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,32 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
},

/**
*
* Returns instance's parent **EXCLUDING** `ActiveSelection`
* @param {boolean} [strict] exclude canvas as well
* @returns {fabric.Object | fabric.StaticCanvas | undefined}
*/
getParent: function (strict) {
return (
this.group && this.group.type === 'activeSelection' ?
this.__owningGroup :
this.group
) || (strict ? undefined : this.canvas);
},

/**
* Returns an array of ancestors **EXCLUDING** `ActiveSelection`
*
* @typedef {fabric.Object[] | [...fabric.Object[], fabric.StaticCanvas]} Ancestors
*
*
* @param {boolean} [strict] returns only ancestors that are objects (without canvas)
* @returns {Ancestors} ancestors from bottom to top
*/
getAncestors: function (strict) {
var ancestors = [];
var parent = this.group || (strict ? undefined : this.canvas);
var parent = this.getParent(strict);
while (parent) {
ancestors.push(parent);
parent = parent.group || (strict ? undefined : parent.canvas);
parent = parent.getParent && parent.getParent(strict);
}
return ancestors;
},
Expand Down
1 change: 1 addition & 0 deletions src/shapes/active_selection.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
* @param {fabric.Object[]} targets
*/
_onAfterObjectsChange: function (type, targets) {
this.callSuper('_onAfterObjectsChange', type, targets);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ported

var groups = [];
targets.forEach(function (object) {
object.group && !groups.includes(object.group) && groups.push(object.group);
Expand Down
5 changes: 5 additions & 0 deletions src/shapes/group.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
* @class fabric.Group
* @extends fabric.Object
* @mixes fabric.Collection
* @fires object:added
* @fires object:removed
* @fires layout once layout completes
* @see {@link fabric.Group#initialize} for constructor definition
*/
Expand Down Expand Up @@ -352,6 +354,7 @@
*/
_onObjectAdded: function (object) {
this.enterGroup(object, true);
this.fire('object:added', { target: object });
object.fire('added', { target: this });
},

Expand All @@ -361,6 +364,7 @@
*/
_onRelativeObjectAdded: function (object) {
this.enterGroup(object, false);
this.fire('object:added', { target: object });
object.fire('added', { target: this });
},

Expand All @@ -371,6 +375,7 @@
*/
_onObjectRemoved: function (object, removeParentTransform) {
this.exitGroup(object, removeParentTransform);
this.fire('object:removed', { target: object });
object.fire('removed', { target: this });
},

Expand Down
50 changes: 50 additions & 0 deletions test/unit/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,56 @@
assert.equal(selection.getObjects().indexOf(rect2), 1, 'rect2 is the second object in the active selection');
});

QUnit.test('update active selection respects order of objects', function (assert) {
var rect1 = new fabric.Rect();
var rect2 = new fabric.Rect();
var rect3 = new fabric.Rect();
var rect3 = new fabric.Rect();
canvas.add(rect1, rect2, rect3);

function assertObjectsInOrder(init, added) {
var activeSelection = new fabric.ActiveSelection(init);
canvas.setActiveObject(activeSelection);
canvas._updateActiveSelection(added, {});
assert.deepEqual(canvas.getActiveObjects(), [rect1, rect2, rect3]);
activeSelection.removeAll();
}

function assertObjectsInOrderOnCanvas(init, added) {
assert.deepEqual(canvas.getObjects(), [rect1, rect2, rect3]);
assertObjectsInOrder(init, added);
assert.deepEqual(canvas.getObjects(), [rect1, rect2, rect3]);
}

assertObjectsInOrderOnCanvas([rect1, rect2], rect3);
assertObjectsInOrderOnCanvas([rect1, rect3], rect2);
assertObjectsInOrderOnCanvas([rect2, rect3], rect1);

canvas.remove(rect2, rect3);
var group = new fabric.Group([rect2, rect3], { subTargetCheck: true, interactive: true });
canvas.add(group);

function assertNestedObjectsInOrder(init, added) {
assert.deepEqual(canvas.getObjects(), [rect1, group]);
assert.deepEqual(group.getObjects(), [rect2, rect3]);
assertObjectsInOrder(init, added);
assert.deepEqual(canvas.getObjects(), [rect1, group]);
assert.deepEqual(group.getObjects(), [rect2, rect3]);
}

assertNestedObjectsInOrder([rect1, rect2], rect3);
assertNestedObjectsInOrder([rect1, rect3], rect2);
assertNestedObjectsInOrder([rect2, rect3], rect1);

canvas.remove(rect1);
group.insertAt(rect1, 0);
group.remove(rect3);
canvas.add(rect3);
assertNestedObjectsInOrder([rect1, rect2], rect3);
assertNestedObjectsInOrder([rect1, rect3], rect2);
assertNestedObjectsInOrder([rect2, rect3], rect1);
});

QUnit.test('_groupSelectedObjects fires selected for objects', function(assert) {
var fired = 0;
var rect1 = new fabric.Rect();
Expand Down
24 changes: 20 additions & 4 deletions test/unit/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,14 @@
});
var removed = group.remove(rect2);
assert.deepEqual(removed, [rect2], 'should return removed objects');
assert.deepEqual(targets, [rect2], 'should contain removed objects');
assert.deepEqual(group.getObjects(), [rect1, rect3], 'should remove object properly');

var removed = group.remove(rect1, rect3);
assert.deepEqual(removed, [rect1, rect3], 'should return removed objects');
assert.equal(group.isEmpty(), true, 'group should be empty');
assert.ok(fired, 'should have fired removed event on rect1');
//assert.deepEqual(targets, [rect2, rect1, rect3], 'should contain removed objects');
assert.deepEqual(targets, [rect2, rect1, rect3], 'should contain removed objects');
});

QUnit.test('size', function(assert) {
Expand Down Expand Up @@ -573,6 +574,7 @@
group = new fabric.Group(),
control = [],
fired = [],
firedOnGroup = [],
firingControl = [];

group.add(rect1, rect2);
Expand All @@ -585,6 +587,7 @@
assert.deepEqual(group.getObjects(), control, 'should equal control array ' + description);
assert.deepEqual(fired.map(o => o.id), firingControl.map(o => o.id), 'fired events should equal control array ' + description);
assert.deepEqual(fired, firingControl, 'fired events should equal control array ' + description);
assert.deepEqual(firedOnGroup, firingControl, 'fired events should equal control array ' + description);
}

assert.ok(typeof group._onObjectAdded === 'function', 'has a standard _onObjectAdded method');
Expand All @@ -594,6 +597,9 @@
fired.push(obj);
});
});
group.on('object:added', (e) => {
firedOnGroup.push(e.target);
});

group.insertAt(rect3, 1);
control.splice(1, 0, rect3);
Expand Down Expand Up @@ -738,12 +744,22 @@
});

QUnit.test('group remove', function(assert) {
var rect1 = new fabric.Rect({ top: 1, left: 1, width: 2, height: 2, strokeWidth: 0, fill: 'red', opacity: 1, objectCaching: false}),
rect2 = new fabric.Rect({ top: 5, left: 5, width: 2, height: 2, strokeWidth: 0, fill: 'red', opacity: 1, objectCaching: false}),
group = new fabric.Group([rect1, rect2]);
var rect1 = new fabric.Rect({ top: 1, left: 1, width: 2, height: 2, strokeWidth: 0, fill: 'red', opacity: 1, objectCaching: false }),
rect2 = new fabric.Rect({ top: 5, left: 5, width: 2, height: 2, strokeWidth: 0, fill: 'red', opacity: 1, objectCaching: false }),
group = new fabric.Group([rect1, rect2]),
fired = [];

var coords = group.oCoords;
group.on('object:removed', (e) => {
assert.equal(e.target, rect2);
fired.push(group);
});
rect2.on('removed', (e) => {
assert.equal(e.target, group);
fired.push(rect2);
});
group.remove(rect2);
assert.deepEqual(fired, [group, rect2], 'should fire removed in correct order');
var newCoords = group.oCoords;
assert.notEqual(coords, newCoords, 'object coords have been recalculated - remove');
});
Expand Down
15 changes: 15 additions & 0 deletions test/unit/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,21 @@
assert.ok(object.isDescendantOf(object) === false);
});

QUnit.test('getParent', function (assert) {
var object = new fabric.Object();
var parent = new fabric.Object();
var activeSelection = new fabric.Object({ type: 'activeSelection' });
assert.ok(typeof object.getParent === 'function');
assert.equal(object.getParent(), undefined);
object.group = parent;
object.canvas = canvas;
assert.equal(object.getParent(), parent);
parent.canvas = canvas;
assert.equal(parent.getParent(), canvas);
parent.group = activeSelection;
assert.equal(parent.getParent(), canvas, 'should not consider active selection as parent');
});

QUnit.test('getAncestors', function (assert) {
var object = new fabric.Object();
var parent = new fabric.Object();
Expand Down