Reputation: 32066
I've been stuck on this problem for while. I have an SVG canvas that I can pan (with transform:translate
) and zoom (with transform:scale
).
I want to arbitrarily center the SVG canvas on any element. I thought this would be easy since I know the scale factor, the absolute point coordinates to center on, and the full width of unscaled SVG canvas. For example, to center on (0, 0) you just have to move the transform:translate
to ( svgWidth / 2, svgHeight / 2 )
However, at scale this seems to fall apart, and I can't figure out the formula to make it work. On this JSFiddle you can see my setup. For simplicity, this only centers on X, not Y.
I have 3 SVG canvases, each getting a programmatic offset and scale, as in a wrapping element <g class="transform" transform="translate(1, 0) scale(0.5)">
. This is how I do panning and zooming in my app. I have a point on the canvas that I want to center on. There's a function defined at the top getSvgOffsetToCenterPoint
which is the formula I'm trying to figure out.
The blue line runs through the center of each svg element using CSS. The red dots should be aligned on the blue line at all three scales. But as you can see, my formula (and any variation I try) does not appear to satisfy that.
Upvotes: 2
Views: 2668
Reputation: 4443
It took a while to figure out what was happening, but I got it working. Here's the updated fiddle: http://jsfiddle.net/eukxumtn/8/.
First I changed the scales to something easier to think about, removed the addition of the radius from the pointX
calculation to work with the center of the circle instead of the edge, and set the translation
to zero to see where we are starting from.
It looks like the visual size and position are affected by the scale, but the translation needs to occur in the original coordinate system.
Take the large dot for example (I changed its scale to 1.5). It's initial position is 50, but after scaling it looks like its initial position is 75 (1.5 * 50 = 75). You want it to look like it is at 100, so you need to move it the visual distance between the two (100 - 75 = 25). So the translation calculation becomes:
function getSvgOffsetToCenterPoint( pointX, svgWidth, svgScale ) {
var initialPositionScaled = svgScale * pointX;
var desiredPosition = svgWidth / 2;
return desiredPosition - initialPositionScaled;
}
If you put the + 10
back into the pointX
calculation, you are now computing the translation for the right edge of the circle instead of the center, and it works as desired.
If I have some time later, I'll circle back and see if I can find the explanation for this behavior in the documentation.
Upvotes: 3