【问题标题】:Align object to canvas in fabricjs在fabricjs中将对象与画布对齐
【发布时间】:2020-08-04 00:52:45
【问题描述】:

我正在尝试实现对象对齐(即上 - 下 - 左 - 右 - CenterH - CenterV)我的代码运行良好,但我不知道如何在对象旋转时处理对齐(使用代码当角度不为 0 时,如果对象的一部分消失,我想知道如何计算最小左偏移量才能仍然看到整个旋转的对象)。我的代码如下。

var canvas = new fabric.Canvas('a');
canvas.add(new fabric.Rect({
  left: 50,
  top: 50,
  height: 50,
  width: 50,
  fill: 'red'
}));
canvas.add(new fabric.Rect({
  angle: 76,
  left: 180,
  top: 50,
  height: 50,
  width: 50,
  fill: 'green'
}));
canvas.add(new fabric.Rect({
  left: 90,
  top: 130,
  height: 50,
  width: 50,
  fill: 'blue'
}));

canvas.renderAll();

$('.alignment').click(function() {
  var cur_value = $(this).attr('data-action');
  var activeObj = canvas.getActiveObject() || canvas.getActiveGroup();
  if (cur_value != '' && activeObj) {
    process_align(cur_value, activeObj);
    activeObj.setCoords();
    canvas.renderAll();
  } else {
    alert('Please select a item');
    return false;
  }
});

/* Align the selected object */
function process_align(val, activeObj) {
  switch (val) {

    case 'left':
      activeObj.set({
        left: 0
      });
      break;
    case 'right':
      activeObj.set({
        left: canvas.width - (activeObj.width * activeObj.scaleX)
      });
      break;
    case 'top':
      activeObj.set({
        top: 0
      });
      break;
    case 'bottom':
      activeObj.set({
        top: canvas.height - (activeObj.height * activeObj.scaleY)
      });
      break;
    case 'centerH':
      activeObj.set({
        left: (canvas.width / 2) - ((activeObj.width * activeObj.scaleX) / 2)
      });
      break;
    case 'centerV':
      activeObj.set({
        top: (canvas.height / 2) - ((activeObj.height * activeObj.scaleY) / 2)
      });
      break;
  }
}
canvas {
  border: 2px solid black;
}
<script
  src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<button class="alignment" data-action="left">Align Left</button>
<button class="alignment" data-action="centerH">Align CenterH</button>
<button class="alignment" data-action="centerV">Align CenterV</button>
<button class="alignment" data-action="right">Align Right</button>
<button class="alignment" data-action="top">Align Top</button>
<button class="alignment" data-action="bottom">Align Bottom</button>
<canvas id="a" width="400" height="200"></canvas>

如何更新代码以对齐旋转的对象? (检查绿色矩形上的对齐方式)

【问题讨论】:

  • @HelderSepulveda 抱歉,我会解释一下...如果您在尝试对齐时打开任何图形软件,假设在屏幕左侧,对象仍然在画布上可见.使用提供的代码,当角度不同于 0 时,对象的一部分会消失,因为在左对齐的情况下,左坐标设置为 0。所以我想知道如何计算最小左偏移量才能仍然看到整个旋转的对象。
  • 您应该将该描述添加到您的问题中...现在完成类似的操作,调试您的代码并查看您的 activeObj.aCoords ...您需要考虑矩形的所有角落
  • 问题已更新
  • 我正在尝试本地编辑器

标签: javascript canvas fabricjs


【解决方案1】:

看看这种方法,animate 有一个很好的中止选项,如果任何角点超出画布的边界,我会使用它来停止,我刚刚在 chrome 上进行了测试并简化了移除中心对齐,如果需要,您可以稍后添加。

function move(obj, prop, value) {
    obj.saveState();
    obj.animate(prop, value, {
        duration: 1000,
        onChange: canvas.renderAll.bind(canvas),
        onComplete: canvas.renderAll.bind(canvas),
        easing: fabric.util.ease["easeOutQuad"],
        abort: function () {
            obj.setCoords();
            for (const prop in obj.aCoords) {
                point = obj.aCoords[prop]
                if (point.x <= 0 || point.x >= canvas.width ||
                    point.y <= 0 || point.y >= canvas.height) {
                    obj.left = obj._stateProperties.left;
                    obj.top = obj._stateProperties.top;
                    return true
                }
            }
            obj.saveState();
        }
    });
}

function process_align(val, obj) {
    switch (val) {
        case 'left':
            move(obj, 'left', 1);
            break;
        case 'right':
            move(obj, 'left', canvas.width - 1);
            break;
        case 'top':
            move(obj, 'top', 1);
            break;
        case 'bottom':
            move(obj, 'top', canvas.height - 1);
            break;
    }
}

var canvas = new fabric.Canvas('a');
canvas.stateful = true;
canvas.add(new fabric.Rect({ left: 50, top: 50, height: 50, width: 50, fill: 'red' }));
canvas.add(new fabric.Rect({ angle: 76, left: 240, top: 50, height: 50, width: 50, fill: 'green' }));
canvas.add(new fabric.Rect({ left: 120, top: 100, height: 50, width: 50, fill: 'blue' }));
canvas.renderAll();

$('.alignment').click(function () {
    var cur_value = $(this).attr('data-action');
    var activeObj = canvas.getActiveObject() || canvas.getActiveGroup();
    if (cur_value != '' && activeObj) {
        process_align(cur_value, activeObj);
        activeObj.setCoords();
        canvas.renderAll();
    } else {
        alert('Please select a item');
        return false;
    }
});
canvas {
  border: 2px solid black;
}
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>

<button class="alignment" data-action="left">Align Left</button>
<button class="alignment" data-action="right">Align Right</button>
<button class="alignment" data-action="top">Align Top</button>
<button class="alignment" data-action="bottom">Align Bottom</button>
<canvas id="a" width="400" height="160"></canvas>

您可以从中选择一些动画缓动:
http://fabricjs.com/animation-easing

【讨论】:

  • 我注意到的一个副作用...如果手动将对象移动到画布边界之外,我的中止逻辑将触发并且对象不会移动...我想如果对象将被手动移动
  • 我刚刚找到了一种方法,可以按照您的建议使用 aCoords 进行工作,我刚刚测试了左对齐,所以我需要时间来复制每个案例的逻辑。完成后我会更新答案
  • @Mono.WTF 这个答案使用aCoords:for (const prop in obj.aCoords) {,动画方法不是你能做的吗?
  • ..是的,我不能在我的项目中使用动画
  • 更新了工作代码,非常感谢您的帮助!
【解决方案2】:

所以正如 @HelderSepulveda 建议我使用 aCoords 来动态计算坐标,我将在下面粘贴工作代码以备不时之需。

var canvas = new fabric.Canvas('a');
canvas.add(new fabric.Rect({
  left: 50,
  top: 50,
  height: 50,
  width: 50,
  fill: 'red'
}));
canvas.add(new fabric.Rect({
  angle: 76,
  left: 180,
  top: 50,
  height: 50,
  width: 50,
  fill: 'green'
}));
canvas.add(new fabric.Rect({
  left: 90,
  top: 130,
  height: 50,
  width: 50,
  fill: 'blue'
}));

canvas.renderAll();

$('.alignment').click(function() {
  var cur_value = $(this).attr('data-action');
  var activeObj = canvas.getActiveObject() || canvas.getActiveGroup();
  if (cur_value != '' && activeObj) {
    process_align(cur_value, activeObj);
    activeObj.setCoords();
    canvas.renderAll();
  } else {
    alert('Please select a item');
    return false;
  }
});

/* Align the selected object */
function process_align(val, activeObj) {
  switch (val) {

    case 'left':
      var left;
      if(activeObj.angle <= 90) {
        left = activeObj.aCoords.tl.x - activeObj.aCoords.bl.x;
      }
      if(activeObj.angle > 90 && activeObj.angle <= 180) {
        left = activeObj.aCoords.tl.x - activeObj.aCoords.br.x;
      }
      if(activeObj.angle > 180 && activeObj.angle <= 270) {
        left = activeObj.aCoords.tl.x - activeObj.aCoords.tr.x;
      }
      if(activeObj.angle > 270) {
        left = 0;
      }
      activeObj.set({
        left: left
      });
      break;
    case 'right':
      var left;
      if(activeObj.angle <= 90) {
        left = activeObj.aCoords.tl.x + (canvas.width - activeObj.aCoords.tr.x);
      }
      if(activeObj.angle > 90 && activeObj.angle <= 180) {
        left = canvas.width;
      }
      if(activeObj.angle > 180 && activeObj.angle <= 270) {
        left = activeObj.aCoords.tl.x + (canvas.width - activeObj.aCoords.bl.x);
      }
      if(activeObj.angle > 270) {
        left = activeObj.aCoords.tl.x + (canvas.width - activeObj.aCoords.br.x);
      }
      activeObj.set({
        left: left
      });
      break;
    case 'top':
      var top;
      if(activeObj.angle <= 90) {
        top = 0;
      }
      if(activeObj.angle > 90 && activeObj.angle <= 180) {
        top = activeObj.aCoords.tl.y - activeObj.aCoords.bl.y;
      }
      if(activeObj.angle > 180 && activeObj.angle <= 270) {
        top = activeObj.aCoords.tl.y - activeObj.aCoords.br.y;
      }
      if(activeObj.angle > 270) {
        top = activeObj.aCoords.tl.y - activeObj.aCoords.tr.y;
      }
      activeObj.set({
        top: top
      });
      break;
    case 'bottom':
      var top;
      if(activeObj.angle <= 90) {
        top = activeObj.aCoords.tl.y + (canvas.height - activeObj.aCoords.br.y);
      }
      if(activeObj.angle > 90 && activeObj.angle <= 180) {
        top = activeObj.aCoords.tl.y + (canvas.height - activeObj.aCoords.tr.y);
      }
      if(activeObj.angle > 180 && activeObj.angle <= 270) {
        top = canvas.height;
      }
      if(activeObj.angle > 270) {
        top = activeObj.aCoords.tl.y + (canvas.height - activeObj.aCoords.bl.y);
      }
      activeObj.set({
        top: top
      });
      break;
    case 'centerH':
      activeObj.viewportCenterH();
      break;
    case 'centerV':
      activeObj.viewportCenterV();
      break;
  }
}
canvas {
  border: 2px solid black;
}
<script
  src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<button class="alignment" data-action="left">Align Left</button>
<button class="alignment" data-action="centerH">Align CenterH</button>
<button class="alignment" data-action="centerV">Align CenterV</button>
<button class="alignment" data-action="right">Align Right</button>
<button class="alignment" data-action="top">Align Top</button>
<button class="alignment" data-action="bottom">Align Bottom</button>
<canvas id="a" width="400" height="200"></canvas>

【讨论】:

  • 是的,它做到了!不是最有效的代码,但可以这样做
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 2016-01-09
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 2014-02-18
  • 2017-08-08
相关资源
最近更新 更多