Fabric.js - Constrain Resize/Scale to Canvas/Object

后端 未结 1 819
梦毁少年i
梦毁少年i 2021-01-06 11:01

How can an object be constrained to being resized/scaled only within the bounds of the canvas (or another object in my case) when using Fabric.js?

C

相关标签:
1条回答
  • 2021-01-06 11:04

    It is not about speed. Events are discrete sampling of something you are doing with the mouse. Even if you move pixel by pixel virtually, the mouse has its own sample rate and the javascript event do not fire every pixel you move when you go fast.

    So if you limit your application to stop scaling when you overcome a limit, when you overcome this limit you will stop your scaling, some pixel after the limit, simply because the last check you were 1 pixel before bound, the event after you are 10 pixel after it.

    I changed the code, that is not perfect at all, but gives you idea for dealing with the issue.

    When you overcome the limit, instead of lock scaling, calculate the correct scaling to be inside the image and apply that scale.

    This logic has problems when you are completely outside the image, so i placed the rect already in, just to demonstrate the different approach.

    var BoundsHelper = (function () {
      function BoundsHelper(asset) {
        this.assetRect = asset.getBoundingRect();
      }
      Object.defineProperty(BoundsHelper.prototype, "left", {
        get: function () {
          return this.assetRect.left;
        },
        enumerable: true,
        configurable: true
      });
      Object.defineProperty(BoundsHelper.prototype, "top", {
        get: function () {
          return this.assetRect.top;
        },
        enumerable: true,
        configurable: true
      });
      Object.defineProperty(BoundsHelper.prototype, "right", {
        get: function () {
          return this.assetRect.left + this.assetRect.width;
        },
        enumerable: true,
        configurable: true
      });
      Object.defineProperty(BoundsHelper.prototype, "bottom", {
        get: function () {
          return this.assetRect.top + this.assetRect.height;
        },
        enumerable: true,
        configurable: true
      });
    
      Object.defineProperty(BoundsHelper.prototype, "height", {
        get: function () {
          return this.assetRect.height;
        },
        enumerable: true,
        configurable: true
      });
      Object.defineProperty(BoundsHelper.prototype, "width", {
        get: function () {
          return this.assetRect.width;
        },
        enumerable: true,
        configurable: true
      });
      return BoundsHelper;
    })();
    
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    
    var canvas = new fabric.Canvas('c');
    var rectangle = new fabric.Rect({
    	fill: 'black',
      originX: 'left',
      originY: 'top',
      stroke: 'false',
      opacity: 1,
      left: 180,
      top: 180,
      height: 50,
      width: 50
    });
    var rectangleBounds = new BoundsHelper(rectangle);
    var image = new fabric.Image(i, {
    	selectable: false,
      borderColor: 'black',
      width: 200,
      height: 200
    });
    
    canvas.on("object:scaling", function (event) {
      var object = event.target;
      var objectBounds = null;
      var imageBounds = null;
      var desiredLength;
      object.setCoords();
      objectBounds = new BoundsHelper(object);
      imageBounds = new BoundsHelper(image);
    
      if (objectBounds.left < imageBounds.left) {
        object.lockScalingX = true;
        // now i have to calculate the right scaleX factor.
        desiredLength =objectBounds.right -  imageBounds.left;
        object.scaleX = desiredLength / object.width;
      }
    
      if (objectBounds.right > imageBounds.right) {
       object.lockScalingX = true;
        desiredLength = imageBounds.right - objectBounds.left;
        object.scaleX = desiredLength / object.width;
      }
    
    
      if (objectBounds.top < imageBounds.top) { 
       object.lockScalingY = true;
        desiredLength = objectBounds.bottom - imageBounds.top;
        object.scaleY = desiredLength / object.height;
      }
    
      if (objectBounds.bottom > imageBounds.bottom) {
        object.lockScalingY = true;
        desiredLength = imageBounds.bottom - objectBounds.top;
        object.scaleY = desiredLength / object.height;
      }
    
    return true;
    });
    
    canvas.onBeforeScaleRotate = function (targetObject) {
      targetObject.lockScalingX = targetObject.lockScalingY = false;
    
      return true;
    };
    
    canvas.on('after:render', function() {
      canvas.contextContainer.strokeStyle = '#555';
    
      var bound = image.getBoundingRect();
    
      canvas.contextContainer.strokeRect(
        bound.left + 0.5,
        bound.top + 0.5,
        bound.width,
        bound.height
      );
    });
    
    canvas.add(image);
    canvas.centerObject(image);
    image.setCoords();
    canvas.add(rectangle);
    canvas.renderAll();
    img {
      display: none;
    }
    
    canvas {
      border: solid black 1px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.12/fabric.min.js"></script>
    <img id="i" src="http://fabricjs.com/assets/ladybug.png" />
    <canvas id="c" width="500" height="500"></canvas>

    https://jsfiddle.net/84zovnek/2/

      if (objectBounds.left < imageBounds.left) {
        //object.lockScalingX = true;
        // now i have to calculate the right scaleX factor.
        desiredLength = imageBounds.left - objectBounds.right;
        object.scaleX = desiredLength / object.width;
      }
    

    Other that, you should update to latest version

    0 讨论(0)
提交回复
热议问题