目前现状
默认情况下,fabricjs
允许元素拖到画布之外的,即fabric object
的 left 和top为负值。在实际的使用过程中,有两个地方需要控制
- 在元素拖入画布中时,这时候,被拖入的元素时可以拖入到画布之外的,这时候触发是的canvas的
drop
事件,如图1所示。 - 已经在画布中的元素,可以通过拖动移到画布之外。这时候触发是的canvas的
object:moving
事件,如图2所示。
图一 添加元素
图二 移动元素
问题分解
在解决这个问题之前,需要参考之前的文章 fabricjs获取真实宽高 ,在fabricjs中获得元素的宽高和top
、left
是有问题的,需要叠加scale因素的影响,所以需要使用getBoundingRect()
,而不能使用fabric object本身的数据。要不然经过拖拽变大的元素控制不住。
解决方案
一般的操作,首先联想到的是事件体系,js本来就是事件驱动的语言。所以针对二个问题使用不同的事件处理掉。
- 添加元素时:在canvas 的
drop
事件去处理,在拿到真实绘制的元素时,去判断上下左右的界限范围,这是没有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()
和元素top
、left
的差别了。
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,
);
}
}
});
结语
至此我们通过两种场景完全限制了元素活动范围