This article explains how to scale an SVG into a smaller viewbox and then center it and use the mouse to control zoom, pan and centering.

*This graphic is best viewed on a PC or laptop.*

- Use the mouse wheel to zoom in/out
- Use mouse drag to pan canvas
- Click on circle to enlarge and center in box

With this example, I wanted to solve a three-fold problem:

- Scale SVG to fit into smaller window size.
- Use mouse drag and thumbwheel to pan and zoom the SVG.
- Use mouse-click to zoom into specific path and center it.

The first and second problems are easily solved using the viewBox attribute and d3.behavior.zoom(). The difficulty is calculating the transform.translate co-ordinates when solving problem 3. When you use the viewBox attribute to transform the SVG, the scale is automatically reset to 1. Therefore, subsequent transformations need to take that into consideration.

In this example, there are three circles as described in file circles.tsv. The SVG viewbox (outlined in red) has width 840 and height 480, so we need to fit the 3 circles into this container. The bounding box that surrounds the 3 circles has top-left co-ordinates (200,100), width 2000 and height 2000.

So we are trying to fit an SVG of width 2000 and height 2000 into a viewbox of width 840 and height 480. The SVG is ~2.4 times the width and ~4.2 times the height of the viewbox. Therefore, if we want to scale uniformly, we must scale the whole SVG to 1/4.2 (0.24). However, with the viewBox attribute, we don’t need to worry about this. Simply set the viewBox attribute to the top-left co-ordinates, width and height of the circles’ bounding box as follows:

```
bbox = container.node().getBBox();
vx = bbox.x;
vy = bbox.y;
vw = bbox.width;
vh = bbox.height;
defaultView = "" + vx + " " + vy + " " + vw + " " + vh;
svg
.attr("viewBox", defaultView)
.attr("preserveAspectRatio", "xMidYMid meet")
.call(zoom);
```

`container`

is the SVG group containing the 3 circles

`vx`

and `vy`

are the top-left co-ordinates of the `container`

(200,100)

`vw`

is the width from the left of the blue circle to the right of the red circle

`vh`

is the height from the top of the blue circle to the bottom of the yellow circle

`preserveAspectRatio`

scales the SVG uniformly

`xMidYMid meet`

centers the SVG horizontally and vertically in the viewBox

`.call(zoom)`

transforms the co-ordinates and scale upon using the mousewheel or upon dragging with the mouse.

So far so good, but I also wanted to zoom into a circle when the circle is clicked. To do this, we need to increase the scale and center the bounding box of the circle in the viewbox. Remember that the scale has been reset to 1 using the viewBox attribute, so if we want to double the circle’s width and height, we use `scale = 2`

. Now the tricky bit is working out the translate values for the x and y co-ordinates. We do this using the following function:

```
function getTransform(node, xScale) {
bbox = node.node().getBBox();
var bx = bbox.x;
var by = bbox.y;
var bw = bbox.width;
var bh = bbox.height;
var tx = -bx*xScale + vx + vw/2 - bw*xScale/2;
var ty = -by*xScale + vy + vh/2 - bh*xScale/2;
return {translate: [tx, ty], scale: xScale}
}
```

`bx`

and `by`

are the top-left co-ordinates of the `node`

(in this case, the circle that was clicked)

`bw`

(and `bh`

) is the diameter of the circle

`vx`

, `vy`

, `vw`

, `vh`

are as above

`tx`

is the translation of the x co-ordinate

`ty`

is the translation of the y co-ordinate

Note the formulas for `tx`

and `ty`

. You can try different scenarios by changing the `width`

, `height`

and `scale`

values or by changing the circle positions and sizes in circles.tsv.