Pan and zoom with text


30 Jun 2012 Code on Github

In response to the previous tutorial I was asked how to make a pan and zoom control that included text. The previous code will work with text, but it will scale the text as you zoom in and out, which is not necessarily the behaviour you want.

This is the same map of Australia, but now with toponyms. As you zoom in and out the text maintains its position relative the drawing while maintaining its size. This can cause odd effects at extreme scales.

Western Australia Queensland Victoria New South Wales ACT Northern Territories South Australia

The problem is quite tricky and my solution is not particularly elegant. You can get the full code here. Briefly, it works by having separate groups for the drawing and for the text. The drawing moves as before, but the text elements have to be moved individually when you zoom since their positions relative to one another changes.

This code loops through all the text in the names group, getting the current (x, y) coordinate, passing them to a function, transformNames(), and using the returned values to set the new coordinates.

for (var i = 0; i < nameElements.length; i++) {
    var x = parseFloat(nameElements[i].getAttributeNS(null, "x"));
    var y = parseFloat(nameElements[i].getAttributeNS(null, "y"));
    var newCoords = transformNames(x, y);
    nameElements[i].setAttributeNS(null, "x", newCoords[0]);
    nameElements[i].setAttributeNS(null, "y", newCoords[1]);
}

When translating the function add (dx, dy) as before:

function(x, y) {
  return [x + dx, y + dy];
};

The function is a bit more complex when scaling. We have calculate the current distance from the center and then scale that distance.

function(x, y) {
  return [
    centerX - (centerX - x) * scale,
    centerY - (centerY - y) * scale
  ];
};

Another small point is that the text elements must have the style text-anchor: middle to ensure the centre of the text maintains its position relative to the drawing rather than the beginning.

Comments (3)

Jelle on 7 Dec 2012, 9:55 p.m.

Nice script Peter. I'm currently thinking of making a script that can do text flow and scale up to a minimum px size. I don't want the text to be displayed in anything less than 9 px.

samara morgan on 5 Dec 2013, 1:04 p.m.

This is really superb. The pan and zoom the image along with the text is what I was looking for. I was adding some labeled diagrams of take machines to my blog. This will be really helpful. Really thank you for sharing this amazing data.

Anonymous on 6 Jul 2017, 10:37 p.m.

Hello, first thanks for your zoom/pan post. I am using your code with SnapSVG, but user's are allowed to populate the screen with as many svg shapes as they like... should the scroll/zoom/add around they are often lost from view. Is it easy to add a zoom extents (all svg items visible) ?