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);
3 comments:
I'm trying to implement your example with a geo AlbersUsa projection using D3.
My states are still not being centered properly. The issues is that I scale the entire map not just one state. and then I try to center the selected state in the middle. Any ideas on how I can achieve this?
Hi, Ayesha. I'm assuming you've already seen Mike Bostock's example which is doing what you're looking for. The only difference here is that it doesn't fully scale the state so it occupies as much space as possible on the screen.
http://bl.ocks.org/mbostock/2206590
I tried to apply my method and it was (unfortunately) flawed. I tweaked it a bit and applied it to Mike's above example. I just uploaded my version of it.
https://github.com/nswarr/zoom-center-example/blob/master/state-zoom.js
It seems to work fine but there are one or two states where the scale is just off by a bit (for example, Kentucky). I don't have a ton of time at the moment so I decided I'd just share what I came up with. I hope that helps!
Oh yeah, I was drawing dots on the screen as reference points. Feel free to remove them!
Post a Comment