2

I have a canvas with images that are placed with a rect trough which the image is shown. Outside the rect the background is shown instead of the image (so it's cropping the image). I'm trying to prevent the image not covering the cropping rect, the image should always be bigger and totally covering the rect. I got this working on straight images/rects but I can't get it to work when a rotation is involved.

I've used the code in this question to get it working on straight images: Prevent Fabric js Objects from scaling out of the canvas boundary

canvas.on('object:moving', (event: any) => {
        // this eventlistener makes sure that a moving image won't leave it's placeholder area uncovered
        //
        const activeObject = event.target;

        // the cropping Rect
        const containerRect = retrieveObjectFromCanvas(this.state.canvas, `${this.selectedImage.value.id}-container`);

        // apply new coords of current move action
        activeObject.setCoords();
        const newCoords = activeObject.getCoords();
        const containerCoords = containerRect.getCoords();

        // left
        if (newCoords[0].x >= containerCoords[0].x) {
          activeObject.left = (containerRect.left - (containerRect.width / 2) + ((activeObject.width * activeObject.scaleX) / 2));
        }

        // top
        if (newCoords[0].y >= containerCoords[0].y) {
          activeObject.top = (containerRect.top - (containerRect.height / 2) + ((activeObject.height * activeObject.scaleY) / 2));
        }

        // right
        if (newCoords[2].x <= containerCoords[2].x) {
          activeObject.left = (containerRect.left + (containerRect.width / 2) - ((activeObject.width * activeObject.scaleX) / 2));
        }

        // bottom
        if (newCoords[2].y <= containerCoords[2].y) {
          activeObject.top = (containerRect.top + (containerRect.height / 2) - ((activeObject.height * activeObject.scaleY) / 2));
        }

        activeObject.setCoords();

      });

      canvas.on('object:scaling', (event:any) => {
        // this eventlistener makes sure that a scaling image won't leave it's placeholder area uncovered
        //
        const activeObject = event.target;
        activeObject.set({ lockScalingFlip: true });
        const boundingRect = activeObject.getBoundingRect();

        // the cropping Rect
        const containerRect = retrieveObjectFromCanvas(this.state.canvas, `${this.selectedImage.value.id}-container`);

        // apply new coords of current move action
        activeObject.setCoords();
        const newCoords = activeObject.getCoords();
        const containerCoords = containerRect.getCoords();

        // left
        let corners = ['tl', 'ml', 'bl'];
        if ((includes(corners, event.transform.corner)) && newCoords[0].x >= containerCoords[0].x) {
          const newScale = (boundingRect.width) / activeObject.width;
          activeObject.scaleX = newScale;
          activeObject.left = (containerRect.left - (containerRect.width / 2) + ((activeObject.width * activeObject.scaleX) / 2));
        }

        // top
        corners = ['tl', 'mt', 'tr'];
        if (includes(corners, event.transform.corner) && newCoords[0].y >= containerCoords[0].y) {
          const newScale = (boundingRect.height) / activeObject.height;
          activeObject.scaleY = newScale;
          activeObject.top = (containerRect.top - (containerRect.height / 2) + ((activeObject.height * activeObject.scaleY) / 2));
        }

        // right
        corners = ['tr', 'mr', 'br'];
        if (includes(corners, event.transform.corner) && newCoords[2].x <= containerCoords[2].x) {
          const newScale = (boundingRect.width) / activeObject.width;
          activeObject.scaleX = newScale;
          activeObject.left = (containerRect.left + (containerRect.width / 2) - ((activeObject.width * activeObject.scaleX) / 2));
        }

        // bottom
        corners = ['bl', 'mb', 'br'];
        if (includes(corners, event.transform.corner) && newCoords[2].y <= containerCoords[2].y) {
          const newScale = (boundingRect.height) / activeObject.height;
          activeObject.scaleY = newScale;
          activeObject.top = (containerRect.top + (containerRect.height / 2) - ((activeObject.height * activeObject.scaleY) / 2));
        }
        activeObject.setCoords();
      });
    }

There are no error messages, but the image will not stop at the borders of the rect, but scale and move unpredictable. I'm not sure if it's related but the Coords calculate from the center of the object/rect to the top-left of the canvas.

Edit: A clarification. Checking if the rect is contained within the picture can be done with .isContainedWithinObject(). The hard part is calculating the values for the image so it's just outside the boundary. In the code above I calculate the top, left, and scale but those calculations only work on images with no skew or rotation.

Ruben
  • 31
  • 4

0 Answers0