Search code examples
javascriptsvgzooming

Zoom in and out, but keep svg centered


I have a world map in svg format, and am using a viewbox to focus on Africa. I have two buttons for zooming in and zooming out:

<rect class="button" x="75" y="170" onclick="zoom(0.8)" style="width:25px; height:20px; fill:khaki"/>
<rect class="button" x="100" y="170" onclick="zoom(1.25)" style="width:25px; height:20px; fill:khaki"/>

In an external .js file, I have code that pans and zooms, which I found in Peter Collingridge's online tutorial:

var transformMatrix = [1, 0, 0, 1, 0, 0];
var svg = document.getElementById('map-svg');
var viewbox = svg.getAttributeNS(null, "viewBox").split(" ");
var centerX = parseFloat(viewbox[2]) / 2;
var centerY = parseFloat(viewbox[3]) / 2;
var matrixGroup = svg.getElementById("matrix-group");

function pan(dx, dy) {
    transformMatrix[4] += dx;
    transformMatrix[5] += dy;
    var newMatrix = "matrix(" +  transformMatrix.join(' ') + ")";
    matrixGroup.setAttributeNS(null, "transform", newMatrix);
}

function zoom(scale) {
    for (var i = 0; i < transformMatrix.length; i++) {
transformMatrix[i] *= scale;
}

    transformMatrix[4] += (1 - scale) * centerX;
    transformMatrix[5] += (1 - scale) * centerY;

    var newMatrix = "matrix(" +  transformMatrix.join(' ') + ")";
    matrixGroup.setAttributeNS(null, "transform", newMatrix);
}

Everything works just as I want it to, except for one thing. When I zoom in, Africa "jumps" to the right, and when I zoom out, it "jumps" to the left. How can I zoom in and out, with Africa staying in the center of the viewbox?


Solution

  • I think I answered my own question. In lines 4 and 5, centerX and centerY are defined:

    var centerX = parseFloat(viewbox[2]) / 2;
    var centerY = parseFloat(viewbox[3]) / 2;
    

    Then in lines 20 and 21, centerX and centerY are used:

    transformMatrix[4] += (1 - scale) * centerX;
    transformMatrix[5] += (1 - scale) * centerY;
    

    I thought, "What if I multiply centerX and centerY by 2, to offset the division by 2 in lines 4 and 5?" That centered it on the Y axis, but not the X axis. So, I kept changing numbers until I got:

    transformMatrix[4] += (1 - scale) * (centerX * 4);
    transformMatrix[5] += (1 - scale) * (centerY * 2);
    

    Now it zooms just as I'd hoped, keeping the continent of Africa centered in the viewbox.