I’ve been battling this one for a little while now. SVG is great for fast graphics rendering and scaling to any dimension, but what do you do when you need to keep your text size the same, regardless of the size of your scaling?
For example. Let’s say you have a map of the United States, drawn in SVG. You also have a set of hidden labels for major states, that you want to display when the user clicks on a state already prepped. I have something like this:
Now when a state is clicked on, we load a file that has the counties for the state, and calculate the transform needed to get the county shapes to fill our viewport. In addition, we apply the transform to the labels, so that they will show up in the proper location:
Now this doesn’t look too bad, but some states are smaller than others, which makes the transform REALLY big.
So what are we to do? There is a “font-size” attribute we can apply, we can even use CSS, but once the transform is applied, it’s values trump whatever is in CSS/HTML since we’re resizing dynamically. If we were somehow able to calculate where the transform would be, or what the resulting coordinates are of our label, then we could simply “redraw” the label after the transform has occurred. I tried using this with the getBBox() method, but it was still referencing the original properties of our label/elements.
Finally, I came across the solution using the getBoundingClientRect() function, which provides the details of our label/element AFTER the transform has completed! With this information, we can create a new label at the new location. I’m using the d3 library with GeoJson to provide my initial data, so your code may be a little different, but here’s what my code looks like after the transform occurs:
I’ve done a little extra formatting on our new labels, so that they have a “pill box” background. We also have a CSS class in place that sets our font to the properties we need (12 point font, black text).
Here’s what our results look like:
Our super zoom states don’t look that bad either…
So there you have it. Take advantage of the getBoundingClientRect() function after you transform your SVG objects in order to redraw your text at the proper location.
Hope this helps! Enjoy!