Skip to content

Adding zoom and pan effects to SVG

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 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; = 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 =;
  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

"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.


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 in any direction follows a similar process using the translate function. The current transform values are parsed from the 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;
    case "right":
      dx = 3;
    case "up":
      dy = -3;
    case "down":
      dy = 3;
  } = 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.

Published inProgramming
Notify of
Newest Most Voted
Inline Feedbacks
View all comments
6 months ago

Freaking awesome…thanks!

3 months ago

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.