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