简体   繁体   中英

Fabricjs selection or hover based on mouse location on object bounding rectangle for inner objects

I want to achieve selection based on the bounding rectangle but with a different approach.

Scenario: If I draw object inside object, like first text, then rectangle over it, then ellipse and then triangle. Now I should be able to select the text or rectangle or ellipse OR the reverse order anyhow. As I start hovering the triangle's bounding rect, the selection or active object should be triangle, but as I move my mouse over ellipse's bounding rect, the current object should be shown as ellipse and so on, irrespective of the order I have added the objects on canvas.

I tried with perPixelTargetFind and following solution Fabricjs - selection only via border , both the solutions are not working meeting my requirement. I am using FabricJS version 3.6.3

Please help out. Thanks in advance. 在此处输入图像描述

Yaaay!! First you need to set perPixelTargetFind: true and targetFindTolerance:5 . Now you will face the issue for selection.

Issue: If you mousedown and drag on empty space, the object was getting selected.

Solution: Found a way to do that. I debugged through the fabric's mechanism to get objects on current mouse pointer location. There is a function _collectObjects which checks for intersectsWithRect (intersect with boundingRect points of the current object), isContainedWithinRect (do the points come inside the boundingRect), containsPoint (current mouse pointer points come in the current object location). So you need to override the _collectObjects function and remove containsPoint check. That will work.

Overridden function:

_collectObjects: function(e) {
      var group = [],
          currentObject,
          x1 = this._groupSelector.ex,
          y1 = this._groupSelector.ey,
          x2 = x1 + this._groupSelector.left,
          y2 = y1 + this._groupSelector.top,
          selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),
          selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),
          allowIntersect = !this.selectionFullyContained,
          isClick = x1 === x2 && y1 === y2;
      // we iterate reverse order to collect top first in case of click.
      for (var i = this._objects.length; i--; ) {
        currentObject = this._objects[i];

        if (!currentObject || !currentObject.selectable || !currentObject.visible) {
          continue;
        }

        if ((allowIntersect && currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2)) ||
            currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2))
        ) {
          group.push(currentObject);
          // only add one object if it's a click
          if (isClick) {
            break;
          }
        }
      }
      if (group.length > 1) {
        group = group.filter(function(object) {
          return !object.onSelect({ e: e });
        });
      }
      return group;
    }

Please upvote if you find this useful for your requirement. thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM