如果元素超出画布,就容易后面找不到了,所以这里要做一些规则 防止元素拖动超过画布,
这里的理解比较简单,就是处理一些阀值情况,让元素不可以超出画布
添加 object:moving 对象拖动事件
this.canvas.on('object:moving', (e) => {
const padding = 10; // 内容距离画布的空白宽度,主动设置
const obj = e.target;
if (obj.currentHeight > obj.canvas.height - (padding * 2) ||
obj.currentWidth > obj.canvas.width - (padding * 2)) {
return;
}
obj.setCoords();
// zoom 是指画布是否有经过放大缩小,如未经过放大缩小可以理解为 zoom 为 1
// 如果画布没有设置 zoom,则可以去掉这里面的所有zoom
const zoom = store.state.zoom;
// 处理条件, 如果元素距离听小于 padding 或者距离 左侧小于 padding
if (obj.getBoundingRect().top < padding || obj.getBoundingRect().left < padding) {
const toTop = (obj.top - (obj.getBoundingRect().top / zoom)) + padding;
const toLeft = (obj.left - (obj.getBoundingRect().left / zoom)) + padding;
// 如果元素只有一个条件在阀值,则另外一个条件正常处理
obj.top = Math.max(obj.top, toTop);
obj.left = Math.max(obj.left, toLeft);
}
// 元素距离左侧的距离 + 元素的宽度 , 计算元素距离右边的距离
const toWidth = obj.getBoundingRect().left + obj.getBoundingRect().width;
// 元素距离上侧的距离 + 元素的高度, 计算元素距离底部的距离
const toHeight = obj.getBoundingRect().top + obj.getBoundingRect().height;
// 处理条件 如果元素距离底部小于 padding, 或者距离右边小于padding
if (toHeight > obj.canvas.height - padding || toWidth > obj.canvas.width - padding) {
const toLeft = obj.left - ((toWidth - (obj.canvas.width - padding)) / zoom);
const toTop = obj.top - ((toHeight - (obj.canvas.height - padding)) / zoom);
obj.left = Math.min(obj.left, toLeft);
obj.top = Math.min(obj.top, toTop);
}
});
到这里,我们的元素已经不能拖出到画布外面了,但是又出现一个问题了,元素除了放大缩小还是可以超出画布
继续解决下个问题 利用object:scaling 事件,监听元素 scale 的时候的事件
最初考虑这个问题,觉得应该和拖动画布一样,只需要监听阀值就可以了,事实并非如此
- 考虑这个问题,需要考虑2个因素,距离边界的距离,和元素的起点位置
2. 在元素进行拖动放大缩小的时候,可能会更改元素的 scaleX, scaleY, left, top, 所以需要考虑这些元素
3. 需要考虑单独的向2侧放大和单独上下放大,和整体缩放,(单独更改 scaleX ,和单独更改scaleX, 同时更改scaleX,scaleX和left,top)
this.pointerLeft = 0; // 记录上次鼠标的left 位置
this.pointerTop = 0; // 记录上次鼠标的top 位置
this.selectLeft = 0; // 记录上一次选择元素的left
this.selectTop = 0; // 记录上一次原则元素的top
const paddding = 10; // 边界阀值
this.canvas.on('object:scaling', (event) => {
const { target, pointer } = event;
// 画布放大缩小,如果画布没有放大缩小,则该值为 1,或者去掉该函数中的zoom
const zoom = store.state.zoom;
// 画布宽度
const canvasWidth = target.canvas.width;
// 画布高度
const canvasHeight = target.canvas.height;
// 元素的属性,高度,宽度,距离左边距,距离上边距
const {wi dth, height, left, top } = target.getBoundingRect();
// 如果鼠标x 小与上一次 鼠标的left值, 说明是缩小元素,或者左侧放大元素
if (pointer.x < this.pointerLeft) {
// 判断是否在左侧边界
if (left < 10) {
const right = canvasWidth - left - width;
target.left = this.selectLeft;
target.scaleX = (canvasWidth - (right + 10)) / (target.width * zoom);
// 判断是否同时在上侧的边界
if (top < 10) {
const bottom = canvasHeight - top - height;
target.top = this.selectTop;
// scaleY = 画布高度 - 距离底部的大小 - 元素高度 - 边界阀值 / * (元素高度 * 发布放大缩小比例)
target.scaleY = (canvasHeight - (bottom + 10)) / (target.height * zoom);
return;
}
// 如果不在上侧边界,先记录一下之前的值
this.selectTop = target.top;
return;
} else {
// 如果不在左侧边界,先记录一下左侧的值
this.selectLeft = target.left;
}
}
if (pointer.y < this.pointerTop) {
if (top < 10) {
const bottom = canvasHeight - top - height;
target.top = this.selectTop;
target.scaleY = (canvasHeight - (bottom + 10)) / (target.height * zoom);
if (left < 10) {
const right = canvasWidth - left - width;
target.left = this.selectLeft;
target.scaleX = (canvasWidth - (right + 10)) / (target.width * zoom);
} else {
this.selectLeft = target.left;
}
return;
}
this.selectTop = target.top;
}
if (pointer.x > this.pointerLeft) {
if (left + width + 20 > canvasWidth) {
target.scaleX = (canvasWidth - (left + 20)) / (target.width * zoom);
target.left = this.selectLeft;
if (top + height + 50 > canvasHeight) {
target.scaleY = (canvasHeight - (top + 50)) / (target.height * zoom);
target.top = this.selectTop;
return;
}
this.selectTop = target.top;
return;
}
this.selectLeft = target.left;
}
if (pointer.y > this.pointerTop) {
if (top + height + 50 > canvasHeight) {
target.scaleY = (canvasHeight - (top + 50)) / (target.height * zoom);
target.top = this.selectTop;
if (left + width + 20 > canvasWidth) {
target.scaleX = (canvasWidth - (left + 20)) / (target.width * zoom);
target.left = this.selectLeft;
return;
}
this.selectLeft = target.left;
return;
}
this.selectTop = target.top;
}
this.pointerLeft = pointer.x;
this.pointerTop = pointer.y;
});
至此,就完成了fabric.js 实现画板的元素禁止超出画布外