fabricjs禁止元素超出画布

1,388 阅读2分钟

目前现状

默认情况下,fabricjs允许元素拖到画布之外的,即fabric objectlefttop为负值。在实际的使用过程中,有两个地方需要控制

  1. 在元素拖入画布中时,这时候,被拖入的元素时可以拖入到画布之外的,这时候触发是的canvasdrop事件,如图1所示。
  2. 已经在画布中的元素,可以通过拖动移到画布之外。这时候触发是的canvasobject:moving事件,如图2所示。

image.png

image.png

图一 添加元素

image.png

图二 移动元素

问题分解

在解决这个问题之前,需要参考之前的文章 fabricjs获取真实宽高 ,在fabricjs中获得元素的宽高和topleft是有问题的,需要叠加scale因素的影响,所以需要使用getBoundingRect(),而不能使用fabric object本身的数据。要不然经过拖拽变大的元素控制不住。

解决方案

一般的操作,首先联想到的是事件体系,js本来就是事件驱动的语言。所以针对二个问题使用不同的事件处理掉。

  • 添加元素时:在canvasdrop 事件去处理,在拿到真实绘制的元素时,去判断上下左右的界限范围,这是没有scale因素影响,可以完全借助于元素本身的数据去处理。代码示例如下:
      canvas.on('drop', (event: fabric.IEvent<MouseEvent>) => {
        const dragEvent = event.e as DragEvent;
        const dataTransfer = dragEvent.dataTransfer;
        if (dataTransfer) {
          let data = dataTransfer.getData('text/plain');
          const drawItemObj: API.EquipmentInfo = JSON.parse(data);
          if (drawItemObj) {
            const fabricItem = dropDragObject(canvas, dragEvent, drawItemObj);
            // 判断上下左右界限范围
            if (
              fabricItem.left !== undefined &&
              fabricItem.left > 0 &&
              fabricItem.left < canvas.getWidth() - fabricItem.getScaledWidth() &&
              fabricItem.top !== undefined &&
              fabricItem.top > 0 &&
              fabricItem.top < canvas.getHeight() - fabricItem.getScaledHeight()
            ) {
              // 可以执行添加操作
              canvas.add(fabricItem);
              insertEquipment(drawItemObj);
              addRemoteFabricObject(fabricItem);
            }
          }
        }
      });
  • 移动元素时:移动元素时,可以监听object:moving事件,根据换算的值在去限定边界范围,注意这时候需要考虑 getBoundingRect()和元素topleft的差别了。
      canvas.on('object:moving', (event: any) => {
        // console.log('canvas object:moving event', event);
        // 阻止对象移动到画布之外
        let moveObj = event.target as fabric.Object;
        moveObj.setCoords();
        if (moveObj.left !== undefined) {
          if (moveObj.getBoundingRect().left < 0) {
            // moveObj.left = 0
            moveObj.left = Math.max(moveObj.left, moveObj.left - moveObj.getBoundingRect().left);
          } else if (moveObj.getBoundingRect().left + moveObj.getBoundingRect().width > canvas.getWidth()) {
            // moveObj.left = canvas.getWidth() - 200;
            moveObj.left = Math.min(
              moveObj.left,
              canvas.getWidth() - moveObj.getBoundingRect().width + moveObj.left - moveObj.getBoundingRect().left,
            );
          }
        }

        if (moveObj.top !== undefined) {
          if (moveObj.getBoundingRect().top < 0) {
            // moveObj.top = 0;
            moveObj.top = Math.max(moveObj.top, moveObj.top - moveObj.getBoundingRect().top);
          } else if (moveObj.getBoundingRect().top + moveObj.getBoundingRect().height > canvas.getHeight()) {
            // moveObj.top = canvas.getHeight() - 200;
            moveObj.top = Math.min(
              moveObj.top,
              canvas.getHeight() - moveObj.getBoundingRect().height + moveObj.top - moveObj.getBoundingRect().top,
            );
          }
        }
      });

结语

至此我们通过两种场景完全限制了元素活动范围