放大 Canvas 然后在不同的鼠标位置缩小会破坏背景显示

Zoom In Canvas And Then Zooming Out in a different mouse position Breaks Background Display

我正在尝试在 canvas 上实现缩放功能,使鼠标位置相对于之前的位置保持不变。

这个功能差不多就完成了。这是一个完整的例子: https://codepen.io/PJEstrada006/pen/dyRxVXE?editors=0011

  public zoom_wheel_canvas_translate(event): void {
    // this is the illusionary point on UI that we wish to stay locked on
    let point = this.mouse_position;
    const wheel = event.deltaY < 0 ? 1 : -1;

    // Compute zoom factor.
    let zoomIntensity = 0.2;
    let zoom = Math.exp(wheel * zoomIntensity);
    this.scale = this.scale * zoom;

    if (this.scale <= 1) {
      this.canvas_ctx.setTransform(1, 0, 0, 1, 0, 0);
      this.scale = 1;
      return
    }
    if (this.scale >= 30) {
      this.scale = 30
    }
    this.canvas_ctx.clearRect(
      0,
      0,
      this.canvas_elm.width,
      this.canvas_elm.height
    );

    let transform = this.canvas_ctx.getTransform();
    this.canvas_ctx.resetTransform();
    this.canvas_ctx.translate(point.x, point.y);
    this.canvas_ctx.scale(zoom, zoom);
    this.canvas_ctx.translate(-point.x, -point.y);
    this.canvas_ctx.transform(transform.a, transform.b, transform.c, transform.d, transform.e, transform.f)
    let transform_new = this.canvas_ctx.getTransform();
    console.log('a', transform.a, 'd', transform.d)
    console.log('e', transform.e, 'f', transform.f)



  }

我有一个图像设置为 canvas 的背景,它是这样绘制的:

    ctx.drawImage(
      this.image,
      0,
      0
    )

问题是,如果我执行以下操作:

  1. 将鼠标放在屏幕中央。
  2. 放大(效果很好)
  3. 将鼠标移到另一个地方。
  4. 继续放大
  5. 一直缩小到 1

缩小最终以错误的方式翻译 canvas 而我的 canvas 图像由于不正确的翻译或比例而出现“切片”或不完整。这发生在比例变为 1 之前,然后它会自行修复,因为当比例 = 1 时我有一个 resetTransform() 调用。

我希望无论我如何移动鼠标,我最终都会缩小并得到原始变换矩阵(单位矩阵)。

任何人都可以帮助我发现我在转换时做错了什么。我不太明白为什么如果我不移动鼠标它会完美运行,但如果我在放大状态下移动鼠标然后再缩小它就会停止工作。

您希望“了解为什么此鼠标移开算法不起作用”,我不会说它不起作用,因为没有错误,我在您的 codepen 上测试了缩放功能,我感觉很好。 ..
您的缩放是相对于鼠标位置的,与之交互感觉直观流畅。

我对你的代码做了一些清理:
https://codepen.io/heldersepu/pen/LYjYEyL?editors=0010

我看到的唯一问题是在翻译时没有考虑到图像可能超出范围,
看到这段代码:

  context.translate(x, y);
  context.scale(zoom, zoom);
  context.translate(-x, -y);

该代码在图像非常大且环绕的世界地图中会很好,我相信 google 地图使用类似的逻辑,这是一个完美的用例,但你没有考虑图像的局限性。

放大你的图像我们不会看到问题,因为图像总是被填充,但如果我们在边缘,你可能会移出图像的边界。
这是一个例子:

  • 将鼠标移至左下方
  • 放大几次
  • 将鼠标移至右下方
  • 缩小

结果 canvas 看起来像:

遇到这种情况怎么办?
一个选项可能是当我们缩小时不翻译:

  if (wheel > 0) context.translate(x, y);
  context.scale(zoom, zoom);
  if (wheel > 0) context.translate(-x, -y);

或者你可以根据鼠标位置有条件地在一个轴上而不是另一个轴上平移,但正确的解决方案由你决定,你必须测试并看看你喜欢什么。