FabricJS - How to prevent leaving object from the given object?

Viewed 23

I was able to prevent leaving objects from the canvas but I was not able to prevent leaving child objects from the given object.

I tried to do it in this way (see code example below) but this locks the object leaving in the same size (width, height) of the locked object but positioned absolutely (top, left). I need to prevent leaving in the same coords there the parent object is positioned (see please the attached image).

Any ideas are welcome.

enter image description here

preventLeavingInsideBox(e: IEvent) {
    let activeObject = e.target;
    if ((activeObject.get('left') - (activeObject.get('width') * activeObject.get('scaleX')  / 2) < 0))
      activeObject.set('left', activeObject.get('width') * activeObject.get('scaleX')  / 2);
    if ((activeObject.get('top') - (activeObject.get('height') * activeObject.get('scaleY')  / 2) < 0))
      activeObject.set('top', activeObject.get('height') * activeObject.get('scaleY')  / 2);
    if (activeObject.get('left') + (activeObject.get('width') * activeObject.get('scaleX')  / 2) > this.rect.width)
    {
      var positionX = this.rect.width - (activeObject.get('width') * activeObject.get('scaleX'))  / 2;
      activeObject.set('left', positionX > this.rect.width / 2 ? positionX : this.rect.width / 2);
    }
    if (activeObject.get('top') + (activeObject.get('height') * activeObject.get('scaleY') / 2) > this.rect.height)
    {
      var positionY = this.rect.height - (activeObject.get('height') * activeObject.get('scaleY') / 2);
      activeObject.set('top', positionY > this.rect.height / 2 ? positionY : this.rect.height / 2);
    }

    //below just prevention for object from getting width or height greater than canvas width and height
    if (activeObject.get('width')  * activeObject.get('scaleX') > this.rect.width)
    {
      activeObject.set('scaleX', this.rect.width / activeObject.get('width'));
    }
    if (activeObject.get('height') * activeObject.get('scaleY') > this.rect.height)
    {
      activeObject.set('scaleY', this.rect.height / activeObject.get('height'));
    }
  }
1 Answers

I was trying to achieve the same result. I had an object with an image inside that I didn't want to be able to be moved outside of it and I also did the resize too.

So I had to get the object that frame which held the image originally and then adds the image after.

What you need to take into account is the top & left of the holding object and the movable object.

So I have a ID on my object of feature image so I get access to it from that. and get the original top, left, height & width.

const featureImageBoxDetails = {
    top: featureImageBox.top,
    left: featureImageBox.left,
    right: featureImageBox.left + featureImageBox.width * featureImageBox.scaleX,
    bottom: featureImageBox.top + featureImageBox.height * featureImageBox.scaleY,
    width: featureImageBox.width * featureImageBox.scaleX,
    height: featureImageBox.height * featureImageBox.scaleY,
};

Then I have my preventLeavingInsideBox function:

const preventLeavingInsideBox = (e: IEvent) => {
    const activeObject = e.target;
    const activeObjectDetails = {
        top: activeObject.top,
        left: activeObject.left,
        right: activeObject.left + activeObject.width * activeObject.scaleX,
        bottom: activeObject.top + activeObject.height * activeObject.scaleY,
        width: activeObject.width * activeObject.scaleX,
        height: activeObject.height * activeObject.scaleY,
    };
    // right
    if (activeObjectDetails.right <= featureImageBoxDetails.right) {
        activeObject.set({
            left: featureImageBoxDetails.right - activeObjectDetails.width,
        });
    }
    // left
    if (activeObjectDetails.left >= featureImageBoxDetails.left) {
        activeObject.set({
            left: featureImageBoxDetails.left,
        });
    }
    // bottom
    if (activeObjectDetails.bottom <= featureImageBoxDetails.bottom) {
        activeObject.set({
            top: featureImageBoxDetails.top + featureImageBoxDetails.height - activeObjectDetails.height,
        });
    }
    // Top
    if (activeObjectDetails.top >= featureImageBoxDetails.top) {
        activeObject.set({
            top: featureImageBoxDetails.top,
        });
    }
};

Then you just need to add in the:

canvas.on('object:moving', preventLeavingInsideBox);
Related