如果元素超出画布,就容易后面找不到了,所以这里要做一些规则 防止元素拖动超过画布,
这里的理解比较简单,就是处理一些阀值情况,让元素不可以超出画布
添加 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 实现画板的元素禁止超出画布外