【问题标题】:Set object drag limit in Fabric.js在 Fabric.js 中设置对象拖动限制
【发布时间】:2013-11-27 13:56:32
【问题描述】:

我是fabric js的新手,想设置拖动限制

我也尝试过https://github.com/kangax/fabric.js/wiki/Working-with-events

无法获得解决方案。

请检查附加的图像,对象可以移动任何东西,但它应该只显示在红色区域。我想要这个。帮帮我...提前谢谢!!

【问题讨论】:

  • 我使用的是fabric js,我只需要在拖动过程中显示一个对象的边界框,而不是整个对象。意思是说对象将被固定,直到我停止拖动。

标签: fabricjs


【解决方案1】:

虽然 Orangepill 的答案是正确的,但当您的对象碰到对象边界时,它会产生“卡顿”。如果您有一个矩形边界框(而不是复杂的边界对象),则另一种方法是允许沿边界拖动对象并沿边界框“滑动”。您可以通过限制坐标值并让其他维度照常移动来做到这一点。一个示例 sn-p 如下所示:

var canvas = new fabric.Canvas("bounded");

var boundingBox = new fabric.Rect({
  fill: "none",
  width: 600,
  height: 400,
  hasBorders: false,
  hasControls: false,
  lockMovementX: true,
  lockMovementY: true,
  evented: false,
  stroke: "red"
});

var movingBox = new fabric.Rect({
  width: 100,
  height: 100,
  hasBorders: false,
  hasControls: false
});

canvas.on("object:moving", function() {
  var top = movingBox.top;
  var bottom = top + movingBox.height;
  var left = movingBox.left;
  var right = left + movingBox.width;

  var topBound = boundingBox.top;
  var bottomBound = topBound + boundingBox.height;
  var leftBound = boundingBox.left;
  var rightBound = leftBound + boundingBox.width;

  // capping logic here
  movingBox.setLeft(Math.min(Math.max(left, leftBound), rightBound - movingBox.width));
  movingBox.setTop(Math.min(Math.max(top, topBound), bottomBound - movingBox.height));
});

canvas.add(boundingBox);
canvas.add(movingBox);

See this example in JSFiddle here

【讨论】:

  • 这几乎正是我想要的——除了我需要图像在比画布更大的边界内滑动。您的解决方案通过简单地将 boundingBox 设置为必要的大小来提供此功能。很棒的东西。
  • 初始实现效果很好!只需要针对我的特定实例进行调整。
  • 我必须设置movingBox 的颜色或设置boundingBox.fill "transparent" 才能显示在您的演示中;否则我不知道发生了什么。
  • 这段代码有很多东西没有考虑到;我发布了一个扩展版本,其中考虑了一些这些东西。
  • JSFiddle 中的好例子。适用于 fabric.js v1.5.0。太棒了:)谢谢:)
【解决方案2】:

Felix Fung 的回答是一个起点,但有很多事情需要考虑。这是一个占其中一些的版本。

它处理具有视口变换(即缩放/平移)的画布和中心起源而不是左侧/顶部起源的对象。它还将比视口更宽/更高的对象限制在顶部/左侧而不是底部/右侧。

canvas.on("object:moving", function(e) {
  var obj = e.target;
  var canvas = obj.canvas;
  var top = obj.top;
  var left = obj.left;
  var zoom = canvas.getZoom();
  var pan_x = canvas.viewportTransform[4];
  var pan_y = canvas.viewportTransform[5];

  // width & height we are constraining to must be calculated by applying the inverse of the current viewportTransform
  var c_width = canvas.width / zoom;
  var c_height = canvas.height / zoom;


  var w = obj.width * obj.scaleX
  var left_adjust, right_adjust
  if(obj.originX == "center") {
    left_adjust = right_adjust = w / 2;
  } else {
    left_adjust = 0;
    right_adjust = w;
  }

  var h = obj.height * obj.scaleY;
  var top_adjust, bottom_adjust;
  if(obj.originY == "center") {
    top_adjust = bottom_adjust = h / 2;
  } else {
    top_adjust = 0;
    bottom_adjust = h;
  }

  // if you need margins set them here
  var top_margin = 0;
  var bottom_margin = 0;
  var left_margin = 0;
  var right_margin = 0;


  var top_bound = top_margin + top_adjust - pan_y;
  var bottom_bound = c_height - bottom_adjust - bottom_margin - pan_y;
  var left_bound = left_margin + left_adjust - pan_x;
  var right_bound = c_width - right_adjust - right_margin - pan_x;

  if( w > c_width ) {
    obj.setLeft(left_bound);
  } else {
    obj.setLeft(Math.min(Math.max(left, left_bound), right_bound));          
  }

  if( h > c_height ) {
    obj.setTop(top_bound);
  } else {
    obj.setTop(Math.min(Math.max(top, top_bound), bottom_bound));          
  }
});

【讨论】:

  • 好答案剪切 n' 粘贴,它就像一个魅力:-)
  • 完美运行。在 v. 2.0 中,setLeft(x) 和 setTop(y) 需要更改为 set('left',x) 和 set('top',y)。
【解决方案3】:

对我有用的是为object:moving 事件创建一个事件侦听器。当移动发生时,您更新 goodtop 和 goodleft 变量,一旦超出界限,将对象重新定位到最后的好点。

var goodtop, goodleft, boundingObject;

canvas.on("object:moving", function(){
    var obj = this.relatedTarget;
    var bounds = boundingObject;
    obj.setCoords();
    if(!obj.isContainedWithinObject(bounds)){
        obj.setTop(goodtop);
        obj.setLeft(goodleft);
        canvas.refresh();    
    } else {
        goodtop = obj.top;
        goodleft = obj.left;
    }  
});

【讨论】:

  • 感谢您的回复,请您提供更多信息或任何示例
  • 我使用的是fabric js,我只需要在拖动过程中显示一个对象的边界框,而不是整个对象。意思是说对象将被固定,直到我停止拖动。
  • 好主意!我试图在我的案例中使用这个想法。它运作良好。
【解决方案4】:

我使用 Michael Johnston 的剪辑作为起点来为旋转元素添加边界控制。此片段仅涵盖以下情况: (obj.centerX && obj.centerY == "center") || (obj.centerX && obj.centerY != "center")

canvasRef.current.on("object:moving", function (e) {
      var obj = e.target;
      var canvas = obj.canvas;
      var zoom = canvas.getZoom();
      var pan_x = canvas.viewportTransform[4];
      var pan_y = canvas.viewportTransform[5];

      // get left, top, width, and height of object
      var left = obj.left;
      var top = obj.top;
      var width = obj.width * obj.scaleX;
      var height = obj.height * obj.scaleY;

      // width & height we are constraining to must be calculated by applying the inverse of the current viewportTransform
      var c_width = canvas.width / zoom;
      var c_height = canvas.height / zoom;

      // calculate values that define the origin of the object, when it is centered in the center or not
      var left_adjust, right_adjust;
      if (obj.originX == "center") {
        left_adjust = right_adjust = width / 2;
      } else {
        left_adjust = 0;
        right_adjust = width;
      }
      var top_adjust, bottom_adjust;
      if (obj.originY == "center") {
        top_adjust = bottom_adjust = height / 2;
      } else {
        top_adjust = 0;
        bottom_adjust = height;
      }

      // support for rotated objects
      if (obj.angle) {
        var angle = obj.angle;
        if (angle > 270) {
          angle -= 270;
        } else if (angle > 180) {
          angle -= 180;
        } else if (angle > 90) {
          angle -= 90;
        }
        const radians = angle * (Math.PI / 180);
        const w_opposite = width * Math.sin(radians);
        const w_adjacent = width * Math.cos(radians);
        const h_opposite = height * Math.sin(radians);
        const h_adjacent = height * Math.cos(radians);

        if (obj.originX != "center" && obj.originY != "center") {
          if (obj.angle <= 90) {
            left_adjust = h_opposite;
            top_adjust = 0;
            right_adjust = w_adjacent;
            bottom_adjust = h_adjacent + w_opposite;
          } else if (obj.angle > 90 && obj.angle <= 180) {
            left_adjust = h_adjacent + w_opposite;
            top_adjust = h_opposite;
            right_adjust = 0;
            bottom_adjust = w_adjacent;
          } else if (obj.angle > 180 && obj.angle <= 270) {
            left_adjust = w_adjacent;
            top_adjust = w_opposite + h_adjacent;
            right_adjust = h_opposite;
            bottom_adjust = 0;
          } else {
            left_adjust = 0;
            top_adjust = w_adjacent;
            right_adjust = w_opposite + h_adjacent;
            bottom_adjust = h_opposite;
          }
        }

        if (obj.originX == "center" && obj.originY == "center") {
          if (obj.angle <= 90 || (obj.angle > 180 && obj.angle <= 270)) {
            left_adjust = (w_adjacent + h_opposite) / 2;
            right_adjust = (w_adjacent + h_opposite) / 2;
            top_adjust = (h_adjacent + w_opposite) / 2;
            bottom_adjust = (h_adjacent + w_opposite) / 2;
          } else {
            left_adjust = (h_adjacent + w_opposite) / 2;
            right_adjust = (h_adjacent + w_opposite) / 2;
            top_adjust = (w_adjacent + h_opposite) / 2;
            bottom_adjust = (w_adjacent + h_opposite) / 2;
          }
        }
      }

      // if you need margins set them here
      var top_margin = 0;
      var bottom_margin = 0;
      var left_margin = 0;
      var right_margin = 0;

      var top_bound = top_margin + top_adjust - pan_y;
      var bottom_bound = c_height - bottom_adjust - bottom_margin - pan_y;
      var left_bound = left_margin + left_adjust - pan_x;
      var right_bound = c_width - right_adjust - right_margin - pan_x;

      if (width > c_width) {
        obj.set("left", left_bound);
      } else {
        obj.set("left", Math.min(Math.max(left, left_bound), right_bound));
      }

      if (height > c_height) {
        obj.set("top", top_bound);
      } else {
        obj.set("top", Math.min(Math.max(top, top_bound), bottom_bound));
      }
});

【讨论】:

    【解决方案5】:

    SEE THE WORKING EXAMPLE 像水一样简单试试这个

    就用这个js

    <script type="text/javascript">
       //use global variable for canvas object
    
    
      var canvas;
      var ctx;
     function onLoad() {
      //get fabric canvas with id mycanvas
    
    
       canvas = new fabric.Canvas('mycanvas');
    
    
       canvas.on("mouse : down",function{
    
       //get canvas 2d context
       ctx = canvas.getContext("2d");
    
       ctx.beginPath();
       ctx.rect(115,60,221,390);//specify bounded rectangle
       ctx.closePath();
       ctx.clip();
       ctx.save();
      });
        //now restore the context on mouse up
    
        canvas.on("mouse : up",function(){
             ctx.restore();//restore the context
        });
    }
    
    
    
     </script>
    

    希望这会对您有所帮助。 Njoy编码:) 现在,您可以为 Fabric.js 支持的每个对象使用相同的剪切区域,以进行转换和移动。 试试看:)。

    【讨论】:

    • 这甚至没有接近回答上面的问题
    猜你喜欢
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多