在FabricJS中控制缩小视图端口

问题描述

我正在尝试here上给出的示例,并放大fabric js并使其正常工作。我正在使用缩放来指向缩放光标所在的位置。但是,我面临的问题是,如果我在一个地方放大,在另一个地方放大,则边框和背景之间会产生偏移。即使代码可以将平移区域限制为1000x400像素,但在缩小时,边界也不受限制。

即使缩小时也如何限制边界,以确保没有偏移?

代码在这里

(function(){
var canvas = new fabric.Canvas('canvas1',{backgroundImage:"https://images.unsplash.com/photo-1520299607509-dcd935f9a839?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1489&q=80"});
 viewportTransform=canvas.viewportTransform;
    canvas.add(new fabric.Rect({ width: 50,height: 50,fill: 'blue',angle: 10 }))
    canvas.add(new fabric.Circle({ radius: 50,fill: 'red',top: 44,left: 80 }))
    canvas.add(new fabric.Ellipse({ rx: 50,ry: 10,fill: 'yellow',top: 80,left: 35 }))
    canvas.add(new fabric.Rect({ width: 50,fill: 'purple',angle: -19,top: 70,left: 70 }))
    canvas.add(new fabric.Circle({ radius: 50,fill: 'green',top: 110,left: 30 }))
    canvas.add(new fabric.Ellipse({ rx: 50,fill: 'orange',top: 12,left: 100,angle: 30 }))
    canvas.on('mouse:wheel',(opt) => {
      var delta = opt.e.deltaY;
      var zoom = canvas.getZoom();
      zoom *= 0.999 ** delta;
      if (zoom > 20) zoom = 20;
      if (zoom < 0.01) zoom = 0.01;
      canvas.zoomToPoint(new fabric.Point(opt.e.offsetX,opt.e.offsetY),zoom);
      opt.e.preventDefault();
      opt.e.stopPropagation();
      var vpt = viewportTransform;
      if (zoom < 0.4) {
        vpt[4] = 200 - 1000 * zoom / 2;
        vpt[5] = 200 - 400 * zoom / 2;
      } else {
        if (vpt[4] >= 0) {
          vpt[4] = 0;
        } else if (vpt[4] < canvas.getWidth() - 1000 * zoom) {
          vpt[4] = canvas.getWidth() - 1000 * zoom;
        }
        if (vpt[5] >= 0) {
          vpt[5] = 0;
        } else if (vpt[5] < canvas.getHeight() - 400 * zoom) {
          vpt[5] = canvas.getHeight() - 400 * zoom;
        }
      }
    });
    canvas.on('mouse:down',function (opt) {
      var evt= opt.e;
      if (evt.altKey === true) {
        this.isDragging = true;
        this.selection = false;
        this.lastPosX = evt.clientX;
        this.lastPosY = evt.clientY;
      }
    });
    canvas.on('mouse:move',function (opt) {
      if (this.isDragging) {
        var e = opt.e;
        var zoom = canvas.getZoom();
        var vpt = this.viewportTransform;
        if (zoom < 0.4) {
          vpt[4] = 200 - 1000 * zoom / 2;
          vpt[5] = 200 - 400 * zoom / 2;
        } else {
          vpt[4] += e.clientX - this.lastPosX;
          vpt[5] += e.clientY - this.lastPosY;
          if (vpt[4] >= 0) {
            vpt[4] = 0;
          } else if (vpt[4] < canvas.getWidth() - 1000 * zoom) {
            vpt[4] = canvas.getWidth() - 1000 * zoom;
          }
          if (vpt[5] >= 0) {
            vpt[5] = 0;
          } else if (vpt[5] < canvas.getHeight() - 400 * zoom) {
            vpt[5] = canvas.getHeight() - 400 * zoom;
          }
        }
        this.requestRenderAll();
        this.lastPosX = e.clientX;
        this.lastPosY = e.clientY;
      }
    });
    canvas.on('mouse:up',function (opt) {
      this.setViewportTransform(this.viewportTransform);
      this.isDragging = false;
      this.selection = true;
    });
})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.6/fabric.min.js"></script>
  <canvas id="canvas1" height="300" width="400" style="border:1px solid"></canvas>

问题截图:

enter image description here

解决方法

mouse:wheel处理程序存在两个问题:

  • 您正在更新不正确的viewportTransform对象
  • 您在更新viewportTransform后没有渲染画布

从以下位置更改处理程序:

canvas.on('mouse:wheel',(opt) => {
      ...
      var vpt = viewportTransform;
      ...
    });

canvas.on('mouse:wheel',(opt) => {
      ...
      var vpt = canvas.viewportTransform;
      ...
      canvas.requestRenderAll();
    });

完整代码:

(function(){
var canvas = new fabric.Canvas('canvas1',{backgroundImage:"https://images.unsplash.com/photo-1520299607509-dcd935f9a839?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1489&q=80"});
 viewportTransform=canvas.viewportTransform;
    canvas.add(new fabric.Rect({ width: 50,height: 50,fill: 'blue',angle: 10 }))
    canvas.add(new fabric.Circle({ radius: 50,fill: 'red',top: 44,left: 80 }))
    canvas.add(new fabric.Ellipse({ rx: 50,ry: 10,fill: 'yellow',top: 80,left: 35 }))
    canvas.add(new fabric.Rect({ width: 50,fill: 'purple',angle: -19,top: 70,left: 70 }))
    canvas.add(new fabric.Circle({ radius: 50,fill: 'green',top: 110,left: 30 }))
    canvas.add(new fabric.Ellipse({ rx: 50,fill: 'orange',top: 12,left: 100,angle: 30 }))
    canvas.on('mouse:wheel',(opt) => {
      var delta = opt.e.deltaY;
      var zoom = canvas.getZoom();
      zoom *= 0.999 ** delta;
      if (zoom > 20) zoom = 20;
      if (zoom < 0.01) zoom = 0.01;
      canvas.zoomToPoint(new fabric.Point(opt.e.offsetX,opt.e.offsetY),zoom);
      opt.e.preventDefault();
      opt.e.stopPropagation();
      var vpt = canvas.viewportTransform;
      if (zoom < 0.4) {
        vpt[4] = 200 - 1000 * zoom / 2;
        vpt[5] = 200 - 400 * zoom / 2;
      } else {
        if (vpt[4] >= 0) {
          vpt[4] = 0;
        } else if (vpt[4] < canvas.getWidth() - 1000 * zoom) {
          vpt[4] = canvas.getWidth() - 1000 * zoom;
        }
        if (vpt[5] >= 0) {
          vpt[5] = 0;
        } else if (vpt[5] < canvas.getHeight() - 400 * zoom) {
          vpt[5] = canvas.getHeight() - 400 * zoom;
        }
      }
      canvas.requestRenderAll();
    });
    canvas.on('mouse:down',function (opt) {
      var evt= opt.e;
      if (evt.altKey === true) {
        this.isDragging = true;
        this.selection = false;
        this.lastPosX = evt.clientX;
        this.lastPosY = evt.clientY;
      }
    });
    canvas.on('mouse:move',function (opt) {
      if (this.isDragging) {
        var e = opt.e;
        var zoom = canvas.getZoom();
        var vpt = this.viewportTransform;
        if (zoom < 0.4) {
          vpt[4] = 200 - 1000 * zoom / 2;
          vpt[5] = 200 - 400 * zoom / 2;
        } else {
          vpt[4] += e.clientX - this.lastPosX;
          vpt[5] += e.clientY - this.lastPosY;
          if (vpt[4] >= 0) {
            vpt[4] = 0;
          } else if (vpt[4] < canvas.getWidth() - 1000 * zoom) {
            vpt[4] = canvas.getWidth() - 1000 * zoom;
          }
          if (vpt[5] >= 0) {
            vpt[5] = 0;
          } else if (vpt[5] < canvas.getHeight() - 400 * zoom) {
            vpt[5] = canvas.getHeight() - 400 * zoom;
          }
        }
        this.requestRenderAll();
        this.lastPosX = e.clientX;
        this.lastPosY = e.clientY;
      }
    });
    canvas.on('mouse:up',function (opt) {
      this.setViewportTransform(this.viewportTransform);
      this.isDragging = false;
      this.selection = true;
    });
})()
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.6/fabric.min.js"></script>
  <canvas id="canvas1" height="300" width="400" style="border:1px solid"></canvas>