首页 > 解决方案 > 放大画布,然后在不同的鼠标位置缩小会破坏背景显示

问题描述

我正在尝试在画布上实现缩放功能,以保持鼠标位置相对于以前的位置。

这个功能几乎完成了它。这是一个完整的例子: 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)



  }

我将图像设置为画布的背景,如下所示:

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

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

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

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

我期待无论我如何移动鼠标,我最终都会缩小并最终得到原始变换矩阵(恒等矩阵)。

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

标签: javascriptcanvasgraphicshtml5-canvas2d

解决方案


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

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

我看到的唯一问题是在不考虑图像可能超出范围的情况下进行翻译,
请参阅以下代码:

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

该代码在图像非常大且包裹的世界地图中会很好,我相信谷歌地图使用类似的逻辑,并且这是一个完美的用例,但您没有考虑图像的限制。

Zooming in your image we are not going to see the problem because the image is always padded, but going out you can be moving out of the bounds of the image if we are on the edge.
Here is an example:

  • move the mouse to the bottom left
  • zoom in a few times
  • move the mouse to the bottom right
  • zoom out

the resulting canvas looks something like:

What to do on that case?
An option could be not to translate when we zoom out:

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

Or you could conditionally translate on one axis and not the other depending on the mouse position, but the correct solution is for you to decide, you have to test and see what you like.


推荐阅读