防止 Fabric js 对象向外扩展画布边界

新手上路,请多包涵

我一直试图将一个对象(在画布上用 fabric js 构建)始终保持在边界内。它已经在移动和旋转它时实现了。我从 Move object within canvas boundary limit 那里获得了帮助来实现这一点。但是当我开始缩放对象时,它只是不断超出边界。我不明白必须做些什么才能将它保持在边界内,即使在缩放时也是如此。请帮我提供一个代码来防止这种行为。如果你也能附上一个演示就太好了。

     <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/

原文由 Ankit Joshi 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

如果要执行实时预防,则应使用 object:scaling 事件,因为 object:modified 仅在转换结束时触发。

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

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

  1. 在处理函数中,获取新旧对象的边界矩形:
 _handleScaling(e) {
  var obj = e.target;
  var brOld = obj.getBoundingRect();
  obj.setCoords();
  var brNew = obj.getBoundingRect();

  1. 对于每个边框,检查对象是否缩放超出了画布边界并计算其左、上和缩放属性:
   // 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)其他边界的类似代码:

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

  1. 如果对象的 BoundingRect 已经越过画布边界,固定它的位置和比例:
   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;
  }
}

  1. 最后,在设置缩放属性时,我们必须坚持使用最小的比例,以防对象跨越多个边界:
 _setScalingProperties(left, top, scale) {
  if(this.scalingProperties == null
  || this.scalingProperties['scale'] > scale) {
    this.scalingProperties = {
      'left': left,
      'top': top,
      'scale': scale
    };
  }
}

原文由 William Dias 发布,翻译遵循 CC BY-SA 3.0 许可协议

我能够按如下方式解决问题:

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

    var left1 = 0;
    var top1 = 0 ;
    var scale1x = 0 ;
    var scale1y = 0 ;
    var width1 = 0 ;
    var height1 = 0 ;
  canvas.on('object:scaling', function (e){
    var obj = e.target;
    obj.setCoords();
    var brNew = obj.getBoundingRect();

    if (((brNew.width+brNew.left)>=obj.canvas.width) || ((brNew.height+brNew.top)>=obj.canvas.height) || ((brNew.left<0) || (brNew.top<0))) {
    obj.left = left1;
    obj.top=top1;
    obj.scaleX=scale1x;
    obj.scaleY=scale1y;
    obj.width=width1;
    obj.height=height1;
  }
    else{
      left1 =obj.left;
      top1 =obj.top;
      scale1x = obj.scaleX;
      scale1y=obj.scaleY;
      width1=obj.width;
      height1=obj.height;
    }
 });
 <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>
</body>
</html>

原文由 Pedro Paulo 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏