# 2d zooming function using transformation matrix

I'm trying to create a sort of "graphing calculator coordinate system" where you can zoom into a point by scrolling with the mouse wheel. I'm using javafx's transformation matrices (Affines) to keep track of scale and translation. I'm struggeling to come up with a function that allows me to zoom into a point when scrolling, it always comes out weird and moves the canvas in strange ways. This is what I have tried:

    double multiplier = event.getDeltaY() / 1000.0; //event.getDeltaY() = mousewheel scroll

//event.getX() = mouseX, event.getY() = mouseY
this.cam.move(new Point2D(-event.getX() * multiplier, -event.getY() * multiplier)); //calls Affine.appendTranslation
this.cam.zoom(1 + multiplier); //calls Affine.appendScale


There is also Affine.prependScale and Affine.prependTranslation which adds scale / translation before existing operations. I'm not very good at matrix maths so if anyone knows a working zoom function please let me know.

I don't know javafx, but I can tell you the math.

An affine transformation is a linear transformation combined with a translation. e.g.

A(p) = | l11 l12 | * | p_x | + | t_x |
| l21 l22 |   | p_y |   | t_y |


Usually, for simplicity, we use homogeneous coordinates, which allows to write the transformation as a single matrix product:

       | l11 l12 t_x |   | p_x |
A(p) = | l21 l22 t_y | * | p_y |
|  0   0   1  |   |  1  |


Now suppose that A(c) = q and you want to zoom in such that the new transform A' keeps A'(c) = q. The linear zoom matrix is trivial:

       | z 0 0 |   | p_x |
Z(p) = | 0 z 0 | * | p_y |
| 0 0 1 |   |  1  |


where z is the zoom factor. Notice that Z has one fixed point, (0, 0).

          | z 0 0 |   | 0 |   | z*0 + 0*0  + 0*1 |   | 0 |
Z(0, 0) = | 0 z 0 | * | 0 | = | 0*0 + z*0  + 0*1 | = | 0 |
| 0 0 1 |   | 1 |   | 0*0 + 0*0  + 1*1 |   | 1 |


So basically, you want to combine A with a modified version of Z such that the fixed point is at q (if you place that modified Z in front of A) or c (if you place A in front of that modified Z).

To have a fixed point at q, simply translate so that q is sent to 0, zoom, then translate back.

Z' = T⁻¹ * Z * T


where T is the relevant translation. Expanding the matrices, we have:

        | 1 0 q_x |   | z 0 0 |   | 1 0 -q_x |   | p_x |
Z'(p) = | 0 1 q_y | * | 0 z 0 | * | 0 1 -q_y | = | p_y |
| 0 0  1  |   | 0 0 1 |   | 0 0   1  |   |  1  |


Notice that Z'(q) = q

Now you simply combine Z' with A:

A' = Z' * A


Now we can see that:

A'(c) = Z'(A(c)) = Z'(q) = q

• That worked wonderfully, thank you so much Oct 8, 2021 at 18:01