Fabric.js: Group selection Resize and Rotate not working when canvas has perPixelTargetFind true

Created on 4 Oct 2020  路  12Comments  路  Source: fabricjs/fabric.js

Version

4.2.0

  • fails from 4.0.0
  • works until 4.0.0-rc.1

Test Case

http://jsfiddle.net/s0tn3e15/

Information about environment

  • Chrome Browser - Ubuntu Linux
  • Firefox Browser - Ubuntu Linux

Steps to reproduce

  • create a fabric.Canvas with perPixelTargetFind=true
  • create and select multiple objects on the canvas
  • try to resize or rotate the selection

Expected Behavior

  • allow resize and rotate the group selection
    image

Actual Behavior

  • does not recognize mouse pointer at resize and rotation points of the group
  • works only when in the upper left corner of the canvas
    image
bug

Most helpful comment

Glad it helped you @linrz

I just came up with an alternative solution that might be slightly better. The issue with overriding the _checkTarget(pointer, obj, globalPointer) function in fabric.Canvas is it changes the select behaviour of the whole object, not just the selection points.

If you just want to make the selection points available to ActiveSelections, then try this:

fabric.Canvas.prototype.findTarget = (function (findTarget) {
    return function (e, skipGroup) {
        var result = findTarget.apply(this, [e, skipGroup]);
        if (!(result && (skipGroup || this.skipTargetFind))) {
            var obj = this._activeObject;
            if (obj && obj.type === "activeSelection" && obj._findTargetCorner(this.getPointer(e, true), fabric.util.isTouchEvent(e))) {
                result = obj;
            }
        }
        return result
    };
})(fabric.Canvas.prototype.findTarget);

Cheers

All 12 comments

does it work with normal objects?

Yes, it works fine with a single object.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

That's still an issue, I don't think it should be closed

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Unfortunately still a problem on linux environment.

I do not have any linux machine to test it out.
@phil-r does this happen on every OS?

No the problem is clearly on macOS too.

Tested on windows - seems to be fine, but on Mac OS there is an issue.

I think I have seen similar behaviour on windows using 4.2 but with ActiveSelection.

The grab handles are only available where the selection intersects with an object within the group (hence why in the original example. top-left works).

After some experimentation, the issue is that ActiveSelection is transparent and, with per-pixel target set, this causes the area inside the selection (including the corners) to be ignored.

This check is performed in the _checkTarget(pointer, obj, globalPointer) function in fabric.Canvas

My workaround is to remove the per-pixel target find check by overriding the default implementation as follows:

fabric.Canvas.prototype._checkTarget = (function (_checkTarget) {
    return function (pointer, obj, _globalPointer) {
        return obj && obj.visible && obj.evented && (obj.containsPoint(pointer) || !!obj._findTargetCorner(pointer));
    };
})(fabric.Canvas.prototype._checkTarget);

This makes the entire area of an ActiveSelection selectable and all control points accessible.

Hope this helps someone!

I debug this problem for a long time, your patch helped me, thanks very much! @marshall76963

Glad it helped you @linrz

I just came up with an alternative solution that might be slightly better. The issue with overriding the _checkTarget(pointer, obj, globalPointer) function in fabric.Canvas is it changes the select behaviour of the whole object, not just the selection points.

If you just want to make the selection points available to ActiveSelections, then try this:

fabric.Canvas.prototype.findTarget = (function (findTarget) {
    return function (e, skipGroup) {
        var result = findTarget.apply(this, [e, skipGroup]);
        if (!(result && (skipGroup || this.skipTargetFind))) {
            var obj = this._activeObject;
            if (obj && obj.type === "activeSelection" && obj._findTargetCorner(this.getPointer(e, true), fabric.util.isTouchEvent(e))) {
                result = obj;
            }
        }
        return result
    };
})(fabric.Canvas.prototype.findTarget);

Cheers

Was this page helpful?
0 / 5 - 0 ratings

Related issues

semiadam picture semiadam  路  3Comments

guettli picture guettli  路  4Comments

vleandersson picture vleandersson  路  4Comments

keanass picture keanass  路  5Comments

bevacqua picture bevacqua  路  4Comments