One of the first things I needed to do was select a circle and have it "fit to screen" which was essentially zooming and centering the circle. There were a couple gotchas that I had to hammer through before I figured it out.

- Scale the view THEN translate. It fits my mental model better to make the view the size I need via scale and then to move around it with a translation. I'm sure you could translate first and then scale if you want.
- Translations performed on a scaled shape do not need to be scaled themselves. So, if I scale a circle with a diameter of 40 by 2 then now the coordinate system has doubled and its diameter is 80. If I wanted to translate the shape by (10,20) I wouldn't have to scale it first and make it (20, 40).
- The top left of your viewport is your origin (0,0) and its positive expansion is down and right.

Here's a quick example I worked up here: https://github.com/nswarr/zoom-center-example.

First, we need to know how much we need to scale the view.

We divide the height of the viewport by the diameter of the circle so we know how many times we need to magnify the circle to make it fit the screen. In the case of my example, we're scaling based on the height of the viewport since it's shorter than the width. We can only zoom as far as the shortest dimension so as not to cut off the shape.var scale = height / (radius * 2)

When you scale, the viewport is being expanded beyond the visible boundaries downwards and to the right. What you see in the viewport if you only scaled would be the top left of the newly scaled view. You need to find out what the X and Y coordinates are for the center of your smaller "window" since that's where you want to put your zoomed in shape.scaledCenterX = (width / scale) / 2 scaledCenterY = (height / scale) / 2

The rest is simple. Just subtract the shape's position from the center of your window to get your translation. Please note again, the scaling comes before the translation.x = -(node.x - scaledCenterX) y = -(node.y - scaledCenterY) var transform = "scale(" + scale + ")"; transform += " translate(" + x + "," + y + ")"; vis.transition().duration(500).attr("transform", transform);