一开始我也是被这个问题困扰,认为是一个很复杂的数学运算问题,什么向量啊,坐标现象啊,各种胡思乱想,看了下别人的博文也是写非常复杂,看上去就令人怯步,其实细想一下,就是一个偏移量的问题。

首先声明一个变量,记录x,y的偏移量,一个变量记录最后一次的缩放比例:

// 定义变量记录最后一次的偏移量和缩放比例
const relationship = {x: 0, y: 0, zoom: 1};

放大缩小时计算的偏移量

// 按住ctrl + 滚轮实现放大缩小
const mouseWheelEvent = (e: any) => {
  if (e.ctrlKey) {
    e.preventDefault();
    let zoom = (e.deltaY > 0 ? 0.1 : -0.1) + canvas.getZoom();
    zoom = Math.max(0.1, zoom);
    zoom = Math.min(5, zoom);
    if (zoom === relationship.zoom) return;
    const [x, y] = [e.offsetX, e.offsetY];
    // 计算缩放时产生的偏移量 这是重点代码
    relationship.x += x / zoom - x / relationship.zoom;
    relationship.y += y / zoom - y / relationship.zoom;
    const zoomPoint = new fabric.Point(x, y);
    canvas.zoomToPoint(zoomPoint, zoom);
    relationship.zoom = zoom;
  }
}

上面的x / y 的取值看你是监听在什么元素上,不一定要按照我的,你也可以用 e.pointer.x,e.pointer.y 或者是 e.pageX, e.pageY等

下面我们看看平移的代码时的偏移量,平移其实是最简单的了,以为它不用计算缩放时产生的平移量:

canvas.on("mouse:move", e => {
  if (panning && e && e.e) { // padding 表示是否允许拖动画布
    const delta = new fabric.Point(e.e.movementX, e.e.movementY);
    canvas.relativePan(delta);
    //累计每一次移动时候的偏移量
    relationship.x += e.e.movementX / relationship.zoom;
    relationship.y += e.e.movementY / relationship.zoom;
  }
})

好了,完事之后就可以去愉快地随意的放大缩小移动N百次再添加图形看看效果了,添加对象的方法如下:

canvas.on('mouse:dblclick', e => {
  const [left, top] = [
    e.pointer.x / relationship.zoom - relationship.x
    e.pointer.y / relationship.zoom - relationship.y
  ];
  const rect = new fabric.Rect({
    left,
    top,
    width: 100,
    height: 100,
    fill: 'red'
  });
  canvas.add(rect).renderAll();
})

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐