添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

如果元素超出画布,就容易后面找不到了,所以这里要做一些规则 防止元素拖动超过画布,

这里的理解比较简单,就是处理一些阀值情况,让元素不可以超出画布

添加 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 实现画板的元素禁止超出画布外