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

patch(): Control#shouldActivate #8934

Merged
merged 2 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- patch(): expose `Control#shouldActivate` [#8934](https://github.com/fabricjs/fabric.js/pull/8934)
- feat(Color) Improve regex for new standards, more documentation and code cleanup [#8916](https://github.com/fabricjs/fabric.js/pull/8916)
- fix(TS): extending canvas and object event types (`type` => `interface`) [#8926](https://github.com/fabricjs/fabric.js/pull/8926)
- chore(build) simple deps update [#8929](https://github.com/fabricjs/fabric.js/pull/8929)
Expand Down
8 changes: 8 additions & 0 deletions src/controls/Control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ export class Control {
*/
declare mouseUpHandler?: ControlActionHandler;

shouldActivate(controlKey: string, fabricObject: InteractiveFabricObject) {
// TODO: locking logic can be handled here instead of in the control handler logic
Copy link
Member

Choose a reason for hiding this comment

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

You mean we could look at actionName and the relevant lockProperties?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

or better off, move the lock property to the control

Copy link
Member

Choose a reason for hiding this comment

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

well lock is by object and controls could be generic.
That is the same issue we have with visibility.

return (
fabricObject.canvas?.getActiveObject() === fabricObject &&
fabricObject.isControlVisible(controlKey)
);
}

/**
* Returns control actionHandler
* @param {Event} eventData the native mouse event
Expand Down
34 changes: 15 additions & 19 deletions src/shapes/Object/InteractiveObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,31 +184,27 @@ export class InteractiveFabricObject<
* @param {boolean} forTouch indicates if we are looking for interaction area with a touch action
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or 0 if nothing is found.
*/
_findTargetCorner(pointer: Point, forTouch = false): 0 | string {
if (
!this.hasControls ||
!this.canvas ||
(this.canvas._activeObject as unknown as this) !== this
) {
return 0;
_findTargetCorner(pointer: Point, forTouch = false): string {
if (!this.hasControls || !this.canvas) {
return '';
}

this.__corner = undefined;
// had to keep the reverse loop because was breaking tests
const cornerEntries = Object.entries(this.oCoords);
for (let i = cornerEntries.length - 1; i >= 0; i--) {
const [cornerKey, corner] = cornerEntries[i];
if (!this.isControlVisible(cornerKey)) {
continue;
}
const lines = this._getImageLines(
forTouch ? corner.touchCorner : corner.corner
);
const xPoints = this._findCrossPoints(pointer, lines);
if (xPoints !== 0 && xPoints % 2 === 1) {
this.__corner = cornerKey;
return cornerKey;
const [key, corner] = cornerEntries[i];
if (this.controls[key].shouldActivate(key, this)) {
const lines = this._getImageLines(
forTouch ? corner.touchCorner : corner.corner
);
const xPoints = this._findCrossPoints(pointer, lines);
if (xPoints !== 0 && xPoints % 2 === 1) {
this.__corner = key;
return key;
}
Copy link
Member

@asturur asturur May 19, 2023

Choose a reason for hiding this comment

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

looks like that both getImageLines and findCrossPoints are object method that are more utils than anyhitng else.
Take some parameter in, do not used this at all and give a result.

If you want to have the control class being the owner of the decision if the cursor is in the control, you can do that moving those to utils and exposing a method that uses the utils.

}

// // debugging
//
// this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
Expand All @@ -223,7 +219,7 @@ export class InteractiveFabricObject<
// this.canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);
// this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);
}
return 0;
return '';
}

/**
Expand Down
26 changes: 24 additions & 2 deletions test/unit/object_interactivity.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
assert.ok(typeof cObj._findTargetCorner === 'function', '_findTargetCorner should exist');
cObj.setCoords();
cObj.canvas = {
_activeObject: cObj
getActiveObject() { return cObj }
};
assert.equal(cObj._findTargetCorner(cObj.oCoords.br), 'br');
assert.equal(cObj._findTargetCorner(cObj.oCoords.tl), 'tl');
Expand All @@ -223,7 +223,7 @@
var cObj = new fabric.Object({ top: 10, left: 10, width: 30, height: 30, strokeWidth: 0 });
cObj.setCoords();
cObj.canvas = {
_activeObject: cObj
getActiveObject() { return cObj }
};
var pointNearBr = {
x: cObj.oCoords.br.x + cObj.cornerSize / 3,
Expand All @@ -239,6 +239,28 @@
assert.equal(cObj._findTargetCorner(pointNearBr, false), false, 'not touch event touchCornerSize/3 near br returns false');
});


QUnit.test('_findTargetCorner for non active object', function (assert) {
var cObj = new fabric.Object({ top: 10, left: 10, width: 30, height: 30, strokeWidth: 0 });
assert.ok(typeof cObj._findTargetCorner === 'function', '_findTargetCorner should exist');
cObj.setCoords();
cObj.canvas = {
getActiveObject() { return }
};
assert.equal(cObj._findTargetCorner(cObj.oCoords.mtr), '', 'object is not active');
});

QUnit.test('_findTargetCorner for non visible control', function (assert) {
var cObj = new fabric.Object({ top: 10, left: 10, width: 30, height: 30, strokeWidth: 0 });
assert.ok(typeof cObj._findTargetCorner === 'function', '_findTargetCorner should exist');
cObj.setCoords();
cObj.canvas = {
getActiveObject() { return cObj }
};
cObj.isControlVisible = () => false;
assert.equal(cObj._findTargetCorner(cObj.oCoords.mtr), '', 'object is not active');
});

QUnit.test('_calculateCurrentDimensions', function(assert) {
var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 0 }), dim;
assert.ok(typeof cObj._calculateCurrentDimensions === 'function', '_calculateCurrentDimensions should exist');
Expand Down