防止 Fabric js 对象超出画布边界

Prevent Fabric js Objects from scaling out of the canvas boundary(防止 Fabric js 对象超出画布边界)
本文介绍了防止 Fabric js 对象超出画布边界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图将一个对象(在画布上用织物 js 构建)保持在边界内.它已在移动和旋转它时实现.我得到了 在画布边界限制内移动对象 的帮助来实现这一点.但是当我开始缩放对象时,它只是不断超出边界.我不明白必须做什么才能将其仅保持在边界内,即使在缩放时也是如此.请帮助我编写代码以防止这种行为.如果能附上demo就好了.

I have been trying to keep an object (constructed in fabric js over a canvas) inside the boundaries at all the times. It has been achieved at moving and rotating it. I took help from Move object within canvas boundary limit for achieving this. But when I start to scale the object, it simply keeps on going out of boundary. I do not understand what has to be done to keep it inside the boundary only, even while scaling. Please help me with a code to prevent this behavior. It would be great if you can attach a demo too.

    <html>
<head>
    <title>Basic usage</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>

</head>
<body>
<canvas id="canvas" style= "border: 1px solid black" height= 480 width = 360></canvas>
<script>
 var canvas = new fabric.Canvas('canvas');
  canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));

  canvas.item(0).set({
    borderColor: 'gray',
    cornerColor: 'black',
    cornerSize: 12,
    transparentCorners: true
  });
  canvas.setActiveObject(canvas.item(0));
  canvas.renderAll();


  canvas.on('object:moving', function (e) {
        var obj = e.target;
         // if object is too big ignore
        if(obj.currentHeight > obj.canvas.height || obj.currentWidth > obj.canvas.width){
            return;
        }        
        obj.setCoords();        
        // top-left  corner
        if(obj.getBoundingRect().top < 0 || obj.getBoundingRect().left < 0){
            obj.top = Math.max(obj.top, obj.top-obj.getBoundingRect().top);
            obj.left = Math.max(obj.left, obj.left-obj.getBoundingRect().left);
        }
        // bot-right corner
        if(obj.getBoundingRect().top+obj.getBoundingRect().height  > obj.canvas.height || obj.getBoundingRect().left+obj.getBoundingRect().width  > obj.canvas.width){
            obj.top = Math.min(obj.top, obj.canvas.height-obj.getBoundingRect().height+obj.top-obj.getBoundingRect().top);
            obj.left = Math.min(obj.left, obj.canvas.width-obj.getBoundingRect().width+obj.left-obj.getBoundingRect().left);
        }
});

</script>
</body>
</html>

我的演示附在这里.:https://jsfiddle.net/3v0cLaLk/

推荐答案

如果你想进行实时预防,你应该使用object:scaling事件,作为object:modified 仅在转换结束时触发.

If you want to perform a real time prevention, you should use object:scaling event, as object:modified is only triggered at the end of the transformation.

1) 向画布添加事件处理程序:

1) Add event handler to canvas:

this.canvas.on('object:scaling', (e) => this._handleScaling(e));

2) 在处理函数中,获取新旧对象的边界矩形:

2) In the handler function, get the old and the new object's bounding rect:

_handleScaling(e) {
  var obj = e.target;
  var brOld = obj.getBoundingRect();
  obj.setCoords();
  var brNew = obj.getBoundingRect();

3) 对于每个边框,检查对象是否已超出画布边界并计算其 left、top 和 scale 属性:

3) For each border, check if object has scaled beyond the canvas boundaries and compute its left, top and scale properties:

  // left border
  // 1. compute the scale that sets obj.left equal 0
  // 2. compute height if the same scale is applied to Y (we do not allow non-uniform scaling)
  // 3. compute obj.top based on new height
  if(brOld.left >= 0 && brNew.left < 0) {
    let scale = (brOld.width + brOld.left) / obj.width;
    let height = obj.height * scale;
    let top = ((brNew.top - brOld.top) / (brNew.height - brOld.height) *
      (height - brOld.height)) + brOld.top;
    this._setScalingProperties(0, top, scale);
  } 

4) 其他边框的类似代码:

4) Similar code for the other borders:

  // top border
  if(brOld.top >= 0 && brNew.top < 0) {
    let scale = (brOld.height + brOld.top) / obj.height;
    let width = obj.width * scale;
    let left = ((brNew.left - brOld.left) / (brNew.width - brOld.width) * 
      (width - brOld.width)) + brOld.left;
    this._setScalingProperties(left, 0, scale);
  }
  // right border
  if(brOld.left + brOld.width <= obj.canvas.width 
  && brNew.left + brNew.width > obj.canvas.width) {
    let scale = (obj.canvas.width - brOld.left) / obj.width;
    let height = obj.height * scale;
    let top = ((brNew.top - brOld.top) / (brNew.height - brOld.height) * 
      (height - brOld.height)) + brOld.top;
    this._setScalingProperties(brNew.left, top, scale);
  }
  // bottom border
  if(brOld.top + brOld.height <= obj.canvas.height 
  && brNew.top + brNew.height > obj.canvas.height) {
    let scale = (obj.canvas.height - brOld.top) / obj.height;
    let width = obj.width * scale;
    let left = ((brNew.left - brOld.left) / (brNew.width - brOld.width) * 
      (width - brOld.width)) + brOld.left;
    this._setScalingProperties(left, brNew.top, scale);
  }

5) 如果对象的 BoundingRect 已经越过了画布边界,固定它的位置和比例:

5) If object's BoundingRect has crossed canvas boundaries, fix its position and scale:

  if(brNew.left < 0
  || brNew.top < 0
  || brNew.left + brNew.width > obj.canvas.width
  || brNew.top + brNew.height > obj.canvas.height) {
    obj.left = this.scalingProperties['left'];
    obj.top = this.scalingProperties['top'];
    obj.scaleX = this.scalingProperties['scale'];
    obj.scaleY = this.scalingProperties['scale'];
    obj.setCoords();
  } else {
    this.scalingProperties = null;
  }
}

6) 最后,在设置缩放属性时,我们必须坚持使用最小的缩放,以防对象跨越多个边界:

6) Finally, when setting the scaling properties, we have to stick with the smallest scale in case the object has crossed more than one border:

_setScalingProperties(left, top, scale) {
  if(this.scalingProperties == null 
  || this.scalingProperties['scale'] > scale) {
    this.scalingProperties = {
      'left': left,
      'top': top,
      'scale': scale
    };
  }
}

这篇关于防止 Fabric js 对象超出画布边界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Update another component when Formik form changes(当Formik表单更改时更新另一个组件)
Formik validation isSubmitting / isValidating not getting set to true(Formik验证正在提交/isValiating未设置为True)
React Validation Max Range Using Formik(使用Formik的Reaction验证最大范围)
Validation using Yup to check string or number length(使用YUP检查字符串或数字长度的验证)
Updating initialValues prop on Formik Form does not update input value(更新Formik表单上的初始值属性不会更新输入值)
password validation with yup and formik(使用YUP和Formick进行密码验证)