Fabric.js - 约束调整大小/缩放到画布/对象 [英] Fabric.js - Constrain Resize/Scale to Canvas/Object

查看:7773
本文介绍了Fabric.js - 约束调整大小/缩放到画布/对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用Fabric.js时,如何限制对象仅在画布(或我案例中的另一个对象)的边界内调整大小/缩放?

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

Currently, I'm handling the object:scaling event:

// 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 class只是一个帮助器,用于包装计算对象的边界框的右/底边的数学。

**edit The BoundsHelper class is just a helper for wrapping up the math of calculating the right/bottom sides of the bounding box for an object.

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 回调禁用由上述添加的缩放锁定:

I also make use of the onBeforeScaleRotate callback to disable the scaling lock added by the above:

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

    return true;
}

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

The issue I observe is that it seems like Fabric doesn't redraw the object fast enough for me to accurately detect that scale is passing the image's boundary. In other words, if I scale slowly, then life is good; if I scale quickly, then I can scale outside of the image's bounds.

推荐答案


事件是你正在使用鼠标进行的离散采样。
即使你虚拟移动像素,鼠标也有自己的采样率,javascript事件不会触发你移动时快速移动的每一个像素。

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.

所以如果你限制你的应用程序停止扩展,当你克服了极限,当你克服这个限制,你会停止你的缩放,一些像素的极限,只是因为上一次检查你是1像素前绑定,事件后,你10像素之后。

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.

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

这篇关于Fabric.js - 约束调整大小/缩放到画布/对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆