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

feat(Group): 2nd Patch of New Group! 🎉 #7859

Merged
merged 70 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 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
97886a6
refactor() change common ancenstors returned data to help isInFrontOf…
asturur Apr 28, 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
7 changes: 6 additions & 1 deletion src/brushes/spray_brush.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,12 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
rects = this._getOptimizedRects(rects);
}

var group = new fabric.Group(rects);
var group = new fabric.Group(rects, {
objectCaching: true,
layout: 'fixed',
subTargetCheck: false,
interactive: false
});
this.shadow && group.set('shadow', new fabric.Shadow(this.shadow));
this.canvas.fire('before:path:created', { path: group });
this.canvas.add(group);
Expand Down
4 changes: 2 additions & 2 deletions src/canvas.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@
}
objsToRender.push.apply(objsToRender, activeGroupObjects);
}
// in case a single object is selected render it's entire above the other objects
// in case a single object is selected render it's entire parent above the other objects
else if (!this.preserveObjectStacking && activeObjects.length === 1) {
var target = activeObjects[0], ancestors = target.getAncestors(true);
var topAncestor = ancestors.length === 0 ? target : ancestors.pop();
Expand Down Expand Up @@ -892,7 +892,7 @@
*/
searchPossibleTargets: function (objects, pointer) {
var target = this._searchPossibleTargets(objects, pointer);
return target;
return target && target.interactive && this.targets[0] ? this.targets[0] : target;
Copy link
Member

Choose a reason for hiding this comment

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

note for myself: check what happens with nested groups

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I understand it correctly it iterates over all objects from last to first, wee it hits an objects it walks down it's objects as well so I expect targets[0] to be the top most target to accept the pointer.

},

/**
Expand Down
8 changes: 4 additions & 4 deletions src/mixins/animation.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati

return fabric.util.animate({
target: this,
startValue: object.left,
startValue: object.getX(),
endValue: this.getCenterPoint().x,
duration: this.FX_DURATION,
onChange: function(value) {
object.set('left', value);
object.setX(value);
_this.requestRenderAll();
onChange();
},
Expand Down Expand Up @@ -58,11 +58,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati

return fabric.util.animate({
target: this,
startValue: object.top,
startValue: object.getY(),
endValue: this.getCenterPoint().y,
duration: this.FX_DURATION,
onChange: function(value) {
object.set('top', value);
object.setY(value);
_this.requestRenderAll();
onChange();
},
Expand Down
16 changes: 13 additions & 3 deletions src/mixins/canvas_events.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,13 @@
}
}
}
var invalidate = shouldRender || shouldGroup;
// we clear `_objectsToRender` in case of a change in order to repopulate it at rendering
// run before firing the `down` event to give the dev a chance to populate it themselves
invalidate && (this._objectsToRender = undefined);
this._handleEvent(e, 'down');
// we must renderAll so that we update the visuals
(shouldRender || shouldGroup) && this.requestRenderAll();
invalidate && this.requestRenderAll();
},

/**
Expand Down Expand Up @@ -900,13 +904,19 @@
*/
_transformObject: function(e) {
var pointer = this.getPointer(e),
transform = this._currentTransform;
transform = this._currentTransform,
target = transform.target,
// transform pointer to target's containing coordinate plane
// both pointer and object should agree on every point
localPointer = target.group ?
fabric.util.sendPointToPlane(pointer, null, target.group.calcTransformMatrix()) :
pointer;

transform.reset = false;
transform.shiftKey = e.shiftKey;
transform.altKey = e[this.centeredKey];

this._performTransformAction(e, transform, pointer);
this._performTransformAction(e, transform, localPointer);
transform.actionPerformed && this.requestRenderAll();
},

Expand Down
31 changes: 22 additions & 9 deletions src/mixins/canvas_grouping.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,19 @@
*/
_shouldGroup: function(e, target) {
var activeObject = this._activeObject;
return activeObject && this._isSelectionKeyPressed(e) && target && target.selectable && this.selection &&
(activeObject !== target || activeObject.type === 'activeSelection') && !target.onSelect({ e: e });
// check if an active object exists on canvas and if the user is pressing the `selectionKey` while canvas supports multi selection.
return !!activeObject && this._isSelectionKeyPressed(e) && this.selection
ShaMan123 marked this conversation as resolved.
Show resolved Hide resolved
// on top of that the user also has to hit a target that is selectable.
&& !!target && target.selectable
// if all pre-requisite pass, the target is either something different from the current
// activeObject or if an activeSelection already exists
// TODO at time of writing why `activeObject.type === 'activeSelection'` matter is unclear.
// is a very old condition uncertain if still valid.
&& (activeObject !== target || activeObject.type === 'activeSelection')
// make sure `activeObject` and `target` aren't ancestors of each other
&& !target.isDescendantOf(activeObject) && !activeObject.isDescendantOf(target)
// target accepts selection
&& !target.onSelect({ e: e });
ShaMan123 marked this conversation as resolved.
Show resolved Hide resolved
},

/**
Expand Down Expand Up @@ -50,7 +61,7 @@
_updateActiveSelection: function(target, e) {
var activeSelection = this._activeObject,
currentActiveObjects = activeSelection._objects.slice(0);
if (activeSelection.contains(target)) {
if (target.group === activeSelection) {
activeSelection.remove(target);
this._hoveredTarget = target;
this._hoveredTargets = this.targets.concat();
Expand Down Expand Up @@ -80,17 +91,19 @@
this._fireSelectionEvents(currentActives, e);
},


/**
* @private
* @param {Object} target
* @returns {fabric.ActiveSelection}
*/
_createGroup: function(target) {
var objects = this._objects,
isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),
groupObjects = isActiveLower
? [this._activeObject, target]
: [target, this._activeObject];
this._activeObject.isEditing && this._activeObject.exitEditing();
var activeObject = this._activeObject;
var groupObjects = target.isInFrontOf(activeObject) ?
[activeObject, target] :
[target, activeObject];
activeObject.isEditing && activeObject.exitEditing();
// handle case: target is nested
return new fabric.ActiveSelection(groupObjects, {
canvas: this
});
Expand Down
24 changes: 12 additions & 12 deletions src/mixins/collection.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fabric.Collection = {
add: function (objects, callback) {
var size = this._objects.push.apply(this._objects, objects);
if (callback) {
for (var i = 0, length = objects.length; i < length; i++) {
for (var i = 0; i < objects.length; i++) {
callback.call(this, objects[i]);
}
}
Expand All @@ -39,7 +39,7 @@ fabric.Collection = {
var args = [index, 0].concat(objects);
this._objects.splice.apply(this._objects, args);
if (callback) {
for (var i = 2, length = args.length; i < length; i++) {
for (var i = 2; i < args.length; i++) {
callback.call(this, args[i]);
}
}
Expand All @@ -50,22 +50,21 @@ fabric.Collection = {
* @private
* @param {fabric.Object[]} objectsToRemove objects to remove
* @param {(object:fabric.Object) => any} [callback] function to call for each object removed
* @returns {boolean} true if objects were removed
* @returns {fabric.Object[]} removed objects
*/
remove: function(objectsToRemove, callback) {
var objects = this._objects,
index, somethingRemoved = false;

for (var i = 0, length = objectsToRemove.length; i < length; i++) {
index = objects.indexOf(objectsToRemove[i]);
var objects = this._objects, removed = [];
for (var i = 0, object, index; i < objectsToRemove.length; i++) {
object = objectsToRemove[i];
index = objects.indexOf(object);
// only call onObjectRemoved if an object was actually removed
if (index !== -1) {
somethingRemoved = true;
objects.splice(index, 1);
callback && callback.call(this, objectsToRemove[i]);
removed.push(object);
callback && callback.call(this, object);
}
}
return somethingRemoved;
return removed;
},

/**
Expand All @@ -82,7 +81,7 @@ fabric.Collection = {
*/
forEachObject: function(callback, context) {
var objects = this.getObjects();
for (var i = 0, len = objects.length; i < len; i++) {
for (var i = 0; i < objects.length; i++) {
callback.call(context, objects[i], i, objects);
}
return this;
Expand Down Expand Up @@ -131,6 +130,7 @@ fabric.Collection = {
/**
* Returns true if collection contains an object.\
* **Prefer using {@link `fabric.Object#isDescendantOf`} for performance reasons**
* instead of a.contains(b) use b.isDescendantOf(a)
* @param {Object} object Object to check against
* @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`
* @return {Boolean} `true` if collection contains an object
Expand Down
28 changes: 8 additions & 20 deletions src/mixins/eraser_brush.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@
/* _TO_SVG_END_ */
});

var __restoreObjectsState = fabric.Group.prototype._restoreObjectsState;
fabric.util.object.extend(fabric.Group.prototype, {
/**
* @private
Expand Down Expand Up @@ -181,15 +180,6 @@
});
}
});
},

/**
* Propagate the group's eraser to its objects, crucial for proper functionality of the eraser within the group and nested objects.
* @private
*/
_restoreObjectsState: function () {
this.erasable === true && this.applyEraserToObjects();
return __restoreObjectsState.call(this);
}
});

Expand Down Expand Up @@ -217,23 +207,21 @@
*/
originY: 'center',

drawObject: function (ctx) {
ctx.save();
ctx.fillStyle = 'black';
ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
ctx.restore();
this.callSuper('drawObject', ctx);
},

/**
* eraser should retain size
* dimensions should not change when paths are added or removed
* handled by {@link fabric.Object#_drawClipPath}
* @override
* @private
*/
_getBounds: function () {
// noop
layout: 'fixed',

drawObject: function (ctx) {
ctx.save();
ctx.fillStyle = 'black';
ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
ctx.restore();
this.callSuper('drawObject', ctx);
},

/* _TO_SVG_START_ */
Expand Down
10 changes: 6 additions & 4 deletions src/mixins/itext_behavior.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
*/
initAddedHandler: function() {
var _this = this;
this.on('added', function() {
var canvas = _this.canvas;
this.on('added', function (opt) {
// make sure we listen to the canvas added event
ShaMan123 marked this conversation as resolved.
Show resolved Hide resolved
var canvas = opt.target;
if (canvas) {
if (!canvas._hasITextHandlers) {
canvas._hasITextHandlers = true;
Expand All @@ -40,8 +41,9 @@

initRemovedHandler: function() {
var _this = this;
this.on('removed', function() {
var canvas = _this.canvas;
this.on('removed', function (opt) {
// make sure we listen to the canvas removed event
var canvas = opt.target;
if (canvas) {
canvas._iTextInstances = canvas._iTextInstances || [];
fabric.util.removeFromArray(canvas._iTextInstances, _this);
Expand Down
3 changes: 2 additions & 1 deletion src/mixins/itext_click_behavior.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
*/
mouseUpHandler: function(options) {
this.__isMousedown = false;
if (!this.editable || this.group ||
if (!this.editable ||
ShaMan123 marked this conversation as resolved.
Show resolved Hide resolved
(this.group && !this.group.interactive) ||
(options.transform && options.transform.actionPerformed) ||
(options.e.button && options.e.button !== 1)) {
return;
Expand Down
Loading