In this post, we’ll see how to add zoom and pan effects to animate SVG components. The final result can be seen below.
We will use a simple script to modify the CSS transform
property to produce the desired effects. The advantage of modifying only this CSS property is that the resulting animation will be very fluid and won’t force layout / reflow.
Zooming
Zooming will be achieved by using the scale
function of the transform
property. In order to zoom-in, we increase the scale value by a little bit. To zoom-out, we decrease it.
const svg = document.getElementById("svg"); const zoom = (direction) => { const { scale, x, y } = getTransformParameters(svg); let dScale = 0.1; if (direction == "out") dScale *= -1; if (scale == 0.1 && direction == "out") dScale = 0; svg.style.transform = getTransformString(scale + dScale, x, y); };
In the code snippet above, we used the zoom
function to achieve this effect. The applied transform
can be accessed as a string. ThegetTransformParameters
function will parse it and return the corresponding scale, translate X and translate Y values.
const getTransformParameters = (element) => { const transform = element.style.transform; let scale = 1, x = 0, y = 0; if (transform.includes("scale")) scale = parseFloat(transform.slice(transform.indexOf("scale") + 6)); if (transform.includes("translateX")) x = parseInt(transform.slice(transform.indexOf("translateX") + 11)); if (transform.includes("translateY")) y = parseInt(transform.slice(transform.indexOf("translateY") + 11)); return { scale, x, y }; };
For example, an element
that is translated diagonally to the top-right corner by 5% of its size and scaled by a factor of two would have the following element.style.transform
:
"scale(2) translateX(5%) translateY(-5%)"
The transformation functions are applied from right to left. In this case, the object is translated first and then scaled.
The transform functions are multiplied in order from left to right, meaning that composite transforms are effectively applied in order from right to left.
MDN
The getTransformString
helper function simply returns a string to set the desired transform
property value.
const getTransformString = (scale, x, y) => "scale(" + scale + ") " + "translateX(" + x + "%) translateY(" + y + "%)";
Panning
Panning in any direction follows a similar process using the translate
function. The current transform values are parsed from the element.style.transform
string. Then, based on the desired direction, either the x
or the y
translate value is modified.
const pan = (direction) => { const { scale, x, y } = getTransformParameters(svg); let dx = 0, dy = 0; switch (direction) { case "left": dx = -3; break; case "right": dx = 3; break; case "up": dy = -3; break; case "down": dy = 3; break; } svg.style.transform = getTransformString(scale, x + dx, y + dy); };
See that the x
and y
values are expressed as a percentage of the element’s size in this demonstration. We could have used pixels instead (px
) or some other length unit.
Even listeners
Each operation is associated with a button. The final step is to add event listeners to them.
document.getElementById("left-button").onclick = () => pan("left"); document.getElementById("right-button").onclick = () => pan("right"); document.getElementById("up-button").onclick = () => pan("up"); document.getElementById("down-button").onclick = () => pan("down"); document.getElementById("zoom-in-button").onclick = () => zoom("in"); document.getElementById("zoom-out-button").onclick = () => zoom("out");
Access the source code here.
Freaking awesome…thanks!
You are welcome!
There is a reason why this example shows a moving Black circle on White background.
Because it is actually moving SVG within HTML markup.
If you want to move SVG objects similar to MIRO, you need to keep the SVG thing where it is, encapsulate all your shapes into an SVG group then Zoom and Move that group.