Svg zoom on mouse - mathematical model

Before you think: “Why is this guy asking for help on this problem, of course, it was implemented 1000x” - although you are mostly right, I tried to solve this problem with several open source libraries, but I am here.

I am trying to implement SVG based "mouse wheel scaling focusing on the mouse" from scratch.

I know that there are many libraries that do this, d3 and svg-pan-zoom, to name a couple. Unfortunately, my implementations using these libraries do not live up to my expectations. I was hoping that I could get help from the community with a basic math model for this type of user interface.

In principle, the desired behavior is similar to Google Maps, the user moves the mouse cursor over the location, they scroll the mouse wheel (inward), and the image scale of the map increases, and the location hovering over becomes the horizontal and vertical center of the viewport.

Naturally, I have access to the width / height of the viewport and x / y mouse.

In this example, I will focus only on the x axis, the window width is 900 units, the square is 100 units, the x offset is 400 units, and the scale is 1: 1

<g transform="translate(0 0) scale(1)"> 

enter image description here

Assuming the mouse position x is at 450 units, or about 450 units, if the user scrolls until the scale reaches 2: 1, I would expect the x offset to reach -450 units, thus centering the focus point.

 <g transform="translate(-450 0) scale(2)"> 

enter image description here

The x and y offset must be recalculated each time the wheel scrolls, depending on the current scale / mouse offsets.

All my attempts are completely devoid of the desired behavior, any advice is welcome.

While I appreciate any help, please refrain from providing suggestions to third-party libraries, jQuery plugins, and things of this nature. My goal here is to understand the mathematical model of this problem in a general sense, my use of SVG is primarily an illustration.

+5
source share
1 answer

What I usually do, I support three offsets x offsets y offsets and scale. They will be used as conversion to a group of containers, for example, your element <g transform="translate(0 0) scale(1)"> .

If the mouse were above the source, the new translation would be trivial to calculate. You just multiply the offset x and y by the difference in scale:

 offsetX = offsetX * newScale/scale offsetY = offsetY * newScale/scale 

What you can do is translate the offset so that the mouse is at the origin. Then you scale and then translate everything. Take a look at this typescript class that has a scaleRelativeTo method to do what you want:

 export class Point implements Interfaces.IPoint { x: number; y: number; public constructor(x: number, y: number) { this.x = x; this.y = y; } add(p: Interfaces.IPoint): Point { return new Point(this.x + px, this.y + py); } snapTo(gridX: number, gridY: number): Point { var x = Math.round(this.x / gridX) * gridX; var y = Math.round(this.y / gridY) * gridY; return new Point(x, y); } scale(factor: number): Point { return new Point(this.x * factor, this.y * factor); } scaleRelativeTo(point: Interfaces.IPoint, factor: number): Point { return this.subtract(point).scale(factor).add(point); } subtract(p: Interfaces.IPoint): Point { return new Point(this.x - px, this.y - py); } } 

So, if you gave the transformation given by translate(offsetX,offsetY) scale(scale) , and the scroll event occurred at (mouseX, mouseY) , which led to a newScale , you would have to calculate the new transformation:

 offsetX = (offsetX - mouseX) * newScale/scale + mouseX offsetY = (offsetY - mouseY) * newScale/scale + mouseY 
+5
source

Source: https://habr.com/ru/post/1246315/


All Articles