javascript - 获取容器的标准方法?

标签 javascript fabricjs

好的,如果我有以下旋转形状然后被选中,您将看到它们的边界框: enter image description here

我正在尝试编写一些代码来使对象相互对齐。所以我想得到每个对象的“包含框”。

我知道 getBoundingRect 但是,对于上述形状,这给了我以下信息: enter image description here

因此,这些盒子对我来说用处不大。是否有一种标准方法来获取我称之为所有形状的“包含框”?例如,我希望能够将以下箱子退还给我: enter image description here

因此,对于任何给定的形状,我希望能够获得红色边界矩形(没有旋转)。

显然,我可以在 fabricJS 中为每种可能的形状编写一个例程,但我不想重新发明轮子!有什么想法吗?

编辑这是一个显示当前边界框(红色)的交互式片段:

$(function () 
{
    canvas = new fabric.Canvas('c');

    canvas.add(new fabric.Triangle({
      left: 50,
      top: 50,
      fill: '#FF0000',
      width: 50,
      height: 50,
      angle : 30
    }));

    canvas.add(new fabric.Circle({
      left: 250,
      top: 50,
      fill: '#00ff00',
      radius: 50,
      angle : 30
    }));

    canvas.add(new fabric.Polygon([
      {x: 185, y: 0},
      {x: 250, y: 100},
      {x: 385, y: 170},
      {x: 0, y: 245} ], {
        left: 450,
        top: 50,
        fill: '#0000ff',
        angle : 30
      }));

    canvas.on("after:render", function(opt) 
    { 
        canvas.contextContainer.strokeStyle = '#FF0000';
        canvas.forEachObject(function(obj) 
        {
            var bound = obj.getBoundingRect();

            canvas.contextContainer.strokeRect(
                bound.left + 0.5,
                bound.top + 0.5,
                bound.width,
                bound.height
            );
        });
    });

    canvas.renderAll();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="c" width="800" height="600"></canvas><br/>

最佳答案

所以getBoundingBox是fabricjs的Object类的一个方法。 没有什么能阻止您为您能想到的每种形状重写此方法。

我将从圆形和三 Angular 形开始,让您想象多边形。当形状是路径或将圆缩放为椭圆时,它变得越来越难。

圆形是最难的。 我对所有象限的 30、60、90 度圆进行了采样。仍然不完美。您可能需要增加采样或找到更好的公式(也许每 15 度采样一次就可以解决问题)。

三 Angular 形比较容易,因为它有 3 个兴趣点。

多边形是由三 Angular 形派生出来的,这里没有什么难的。

fabric.Circle.prototype.getBoundingRect = function() {
  var matrix = this.calcTransformMatrix();
  var points = [{x:-this.width/2, y:0}, {x:this.width/2, y:0}, {x:0, y: -this.height/2}, {x: 0, y: this.height/2}, {x: 0, y: -this.height/2}, {x: 0.433 * this.width, y: this.height/4}, {x: -0.433 * this.width, y: this.height/4}, {y: 0.433 * this.height, x: this.width/4}, {y: -0.433 * this.height, x: this.width/4}, {y: -0.433 * this.height, x: -this.width/4}, {y: 0.433 * this.height, x: -this.width/4}, {x: 0.433 * this.width, y: -this.height/4}, {x: -0.433 * this.width, y: -this.height/4}];
  points = points.map(function(p) {
     return fabric.util.transformPoint(p, matrix);
  });
  return fabric.util.makeBoundingBoxFromPoints(points);
}

fabric.Triangle.prototype.getBoundingRect = function() {
  var matrix = this.calcTransformMatrix();
  var points = [{x:-this.width/2, y:this.height/2}, {x:this.width/2, y:this.height/2}, {x:0, y: -this.height/2}, {x: 0, y: 0}];
  points = points.map(function(p) {
     return fabric.util.transformPoint(p, matrix);
  });
  return fabric.util.makeBoundingBoxFromPoints(points);
}

fabric.Polygon.prototype.getBoundingRect = function() {
  var matrix = this.calcTransformMatrix();
  var points = this.points;
  var offsetX = this.pathOffset.x;
  var offsetY = this.pathOffset.y;
      points = points.map(function(p) {
         return fabric.util.transformPoint({x: p.x - offsetX , y: p.y -
 offsetY}, matrix);
      });
      return fabric.util.makeBoundingBoxFromPoints(points);
    }

$(function () 
{
    fabric.util.makeBoundingBoxFromPoints = function(points) {
      var minX = fabric.util.array.min(points, 'x'),
          maxX = fabric.util.array.max(points, 'x'),
          width = Math.abs(minX - maxX),
          minY = fabric.util.array.min(points, 'y'),
          maxY = fabric.util.array.max(points, 'y'),
          height = Math.abs(minY - maxY);

      return {
        left: minX,
        top: minY,
        width: width,
        height: height
      };
    };

    fabric.Circle.prototype.getBoundingRect = function() {
      var matrix = this.calcTransformMatrix();
      var points = [{x:-this.width/2, y:0}, {x:this.width/2, y:0}, {x:0, y: -this.height/2}, {x: 0, y: this.height/2}, {x: 0, y: -this.height/2}, {x: 0.433 * this.width, y: this.height/4}, {x: -0.433 * this.width, y: this.height/4}, {y: 0.433 * this.height, x: this.width/4}, {y: -0.433 * this.height, x: this.width/4}, {y: -0.433 * this.height, x: -this.width/4}, {y: 0.433 * this.height, x: -this.width/4}, {x: 0.433 * this.width, y: -this.height/4}, {x: -0.433 * this.width, y: -this.height/4}];
      points = points.map(function(p) {
         return fabric.util.transformPoint(p, matrix);
      });
      return fabric.util.makeBoundingBoxFromPoints(points);
    }
    
    fabric.Triangle.prototype.getBoundingRect = function() {
      var matrix = this.calcTransformMatrix();
      var points = [{x:-this.width/2, y:this.height/2}, {x:this.width/2, y:this.height/2}, {x:0, y: -this.height/2}, {x: 0, y: 0}];
      points = points.map(function(p) {
         return fabric.util.transformPoint(p, matrix);
      });
      return fabric.util.makeBoundingBoxFromPoints(points);
    }

    fabric.Polygon.prototype.getBoundingRect = function() {
      var matrix = this.calcTransformMatrix();
      var points = this.points;
      var offsetX = this.pathOffset.x;
      var offsetY = this.pathOffset.y;
      points = points.map(function(p) {
         return fabric.util.transformPoint({x: p.x - offsetX , y: p.y -
 offsetY}, matrix);
      });
      return fabric.util.makeBoundingBoxFromPoints(points);
    }

    canvas = new fabric.Canvas('c');

    canvas.add(new fabric.Triangle({
      left: 50,
      top: 50,
      fill: '#FF0000',
      width: 50,
      height: 50,
      angle : 30
    }));

    canvas.add(new fabric.Circle({
      left: 250,
      top: 50,
      fill: '#00ff00',
      radius: 50,
      angle : 30
    }));

    canvas.add(new fabric.Polygon([
      {x: 185, y: 0},
      {x: 250, y: 100},
      {x: 385, y: 170},
      {x: 0, y: 245} ], {
        left: 450,
        top: 50,
        fill: '#0000ff',
        angle : 30
      }));

    canvas.on("after:render", function(opt) 
    { 
        canvas.contextContainer.strokeStyle = '#FF0000';
        canvas.forEachObject(function(obj) 
        {
            var bound = obj.getBoundingRect();
            if(bound)
            {
                canvas.contextContainer.strokeRect(
                    bound.left + 0.5,
                    bound.top + 0.5,
                    bound.width,
                    bound.height
                );
            }                
        });
    });

    canvas.renderAll();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="c" width="800" height="600"></canvas><br/>

关于javascript - 获取容器的标准方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42800125/

相关文章:

javascript - Dynamics CRM 2011 - 更改相关实体列表的 View

javascript - jQuery 和 AJAX。 POST 只给出 NULL

javascript - 如何构建 Fabric.js 进行单元测试

fabricjs - Fabric.js - 重建和商业用途

javascript - 为什么 FabricJS 在不同设备/浏览器上的缩放模式不同?

javascript - 对象捕捉到 Fabric.js 上的自定义网格

javascript - 将日期转换为文本

javascript - Three.js - 让用户上传 .gltf/.glb 3d 模型

javascript - 如何为将 gmail 作为默认邮件处理程序的用户在新选项卡中打开 mailto 链接?

javascript - 如何在fabricjs中将 Canvas 原点设置为中心?