• Empleos
  • Sobre nosotros
  • profesionales
    • Inicio
    • Empleos
    • Cursos y retos
    • Preguntas
    • Profesores
  • empresas
    • Inicio
    • Publicar vacante
    • Nuestro proceso
    • Precios
    • Pruebas Online
    • Nómina
    • Blog
    • Comercial
    • Calculadora de salario

0

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

I'm trying to implement a zoom function on my canvas keeping the mouse position relative to where it was before.

This function accomplishes it almost. And here is a full example: 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)



  }

I have an image set as the background of the canvas that gets drawn like this:

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

The problem is that if I do something like the following:

  1. Place the mouse on center of screen.
  2. Zoom In (Works well)
  3. Move the mouse to another place.
  4. Keep Zooming In
  5. Zoom Out All the way to scale being 1

The zoom out eventually ends up translating the canvas in the wrong way and my canvas image appears "sliced" or incomplete due to incorrect translations or scales. This happens just before the scale becomes 1, then it fixes itself because I have a resetTransform() call when scale = 1.

I'm expecting that no matter how I move the mouse I eventually zoom out and end up with the original transform matrix (identity matrix).

Can anyone help me spot what I'm doing wrong with my transforms. I don't quite get why it works perfect if I don't move the mouse, but stops working if I move the mouse in a zoomed in state and then zoom out.

almost 3 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

You are looking to "understand why this mouse out algorithm is not working", I would not say it is not working as there are no errors, I tested the zoom on your codepen, and it feels fine to me...
Your zoom is relative to the position of the mouse, interacting with it feels intuitive and smooth.

I did some clean up to your code:
https://codepen.io/heldersepu/pen/LYjYEyL?editors=0010

The only issue I see is translating without considering that image could be out of the bounds,
see this code:

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

That code will be fine in a world map where the image is really large and wraps, I believe that google maps uses a similar logic, and it's a perfect use case there, but you are not considering the limitation of your image.

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.

almost 3 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Nuestro proceso Comercial
Legal
Términos y condiciones Política de privacidad
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recomiéndame algunas ofertas
Necesito ayuda