javascript – Fabric.js – 约束调整大小/缩放到Canvas / Object

在使用Fabric.js时,如何将对象限制为仅在画布(或我的情况下的另一个对象)的范围内调整大小/缩放?

目前,我正在处理对象:缩放事件:

// Typescript being used; 

onObjectScaling = (event): boolean => {
    // Prevent scaling object outside of image

    var object = <fabric.IObject>event.target;
    var objectBounds: BoundsHelper;
    var imageBounds: BoundsHelper;

    object.setCoords();
    objectBounds = new BoundsHelper(object);
    imageBounds = new BoundsHelper(this.imageManipulatorContext.getImageObject());

    if (objectBounds.left < imageBounds.left || objectBounds.right > imageBounds.right) {
        console.log('horizontal bounds exceeded');
        object.scaleX = this.selectedObjectLastScaleX;
        object.lockScalingX = true;
        object.setCoords();
    } else {
        this.selectedObjectLastScaleX = object.scaleX;
    }

    if (objectBounds.top < imageBounds.top || objectBounds.bottom > imageBounds.bottom) {
        console.log('vertical bounds exceeded');
        object.scaleY = this.selectedObjectLastScaleY;
        object.lockScalingY = true;
        object.setCoords();
    } else {
        this.selectedObjectLastScaleY = object.scaleY;
    }

    return true;
}

**编辑BoundsHelper类只是一个帮助程序,用于包装计算对象边界框右侧/底侧的数学运算.

import fabric = require('fabric');

class BoundsHelper {
    private assetRect: { left: number; top: number; width: number; height: number; };

    get left(): number { return this.assetRect.left; }
    get top(): number { return this.assetRect.top; }
    get right(): number { return this.assetRect.left + this.assetRect.width; }
    get bottom(): number { return this.assetRect.top + this.assetRect.height; }

    get height(): number { return this.assetRect.height; }
    get width(): number { return this.assetRect.width; }

    constructor(asset: fabric.IObject) {
        this.assetRect = asset.getBoundingRect();
    }
}

export = BoundsHelper;

我还使用onBeforeScaleRotate回调来禁用上面添加的缩放锁定:

onObjectBeforeScaleRotate = (targetObject: fabric.IObject): boolean => {
    targetObject.lockScalingX = targetObject.lockScalingY = false;

    return true;
}

我观察到的问题是,似乎Fabric不能足够快地重绘对象,以便我准确地检测到比例正在通过图像的边界.换句话说,如果我慢慢扩展,那么生活就是好的;如果我快速缩放,那么我可以在图像边界之外缩放.

最佳答案 这不是关于速度.

事件是您使用鼠标执行某些操作的离散采样.

即使您虚拟地逐像素移动,鼠标也有自己的采样率,并且当您快速移动时,javascript事件不会触发您移动的每个像素.

因此,如果您在克服限制时限制应用程序停止缩放,当您克服此限制时,您将停止缩放,在限制之后的某个像素,仅仅因为最后一次检查您在绑定前是1像素,在您是10之后的事件它之后的像素.

我改变了代码,这根本不是完美的,但是让你有机会处理这个问题.

当您克服限制时,而不是锁定缩放,计算图像内部的正确缩放并应用该比例.

当你完全处于图像之外时,这个逻辑会出现问题,因此我已将rect放入其中,只是为了演示不同的方法.

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;
  }

其他,你应该更新到最新版本

点赞