Mat Morse
Mat Morse

Reputation: 75

Adjust the Viewbox to contain a svg element

So i'm working on developing a map with svg and I wanted to be able to on user input zoom into a predefined area within my svg( a state or country ). I found a tutorial that does exactly this as well as animates it, which is here: https://css-tricks.com/interactive-data-visualization-animating-viewbox/ Also their codepen is here: https://codepen.io/sdras/pen/512230ed732f9b963ad3e50c8d4dcbb8

Now I'm having problems replicating this with my own svg. When I tell it to zoom into a certain area it will zoom into another area. I've tried copying the exact structure of their code with no success. I'm starting to think that the error is within my SVG itself.

HTML:

<svg id="foo" xmlns="http://www.w3.org/2000/svg" 
xmlns:xlink="http://www.w3.org/1999/xlink"  viewBox="0 0 1440 776">

Then too much code to copy and paste here.

SASS:

html
  body
    svg
      width: 100vw
      height: 100vh

JQuery:

var test = document.getElementById("_x32_");
console.log(test);
var s = test.getBBox();

//check the console for the SVGRect object
console.log( s );

//we store the values from the object as our new viewBox string
var newView = "" + s.x + " " + s.y + " " + s.width + " " + s.height;
console.log(newView);
//we then set the new viewBox string as the viewBox attribute on the SVG
var foo = document.getElementById("foo");
console.log(foo);
//foo.setAttribute("viewBox", newView);

The CodePen is here: https://codepen.io/mat148/pen/xqWMXR

Upvotes: 2

Views: 1640

Answers (1)

Paul LeBeau
Paul LeBeau

Reputation: 101800

The problem you are having is because the bounding box returned by getBBox() represents the bounds of the coords of that element before it gets transformed by the transform attributes on it's ancestor elements.

If we examine the file, we see that the parentage of your element looks like this:

<svg>
  <g id="north-america" transform="translate(100.000000, 45.000000)">
    <polygon id="_x32_" ...>

So in the case of this particular element, it actually is position at a point 100 to the right and 45 down from the position getBBox() returns.

If we hack in those offsets, you can see it works.

Obviously, that's not going to be a general solution.

There isn't a very simple solution to this problem, but here are a few approaches you can try:

  1. Alter the SVG to remove all the transforms, by applying them to the paths and polygons. This Stack Overflow question describes some ways to do that with Inkscape.

  2. I believe the RaphaelJS library has a function that can return the transformed bounding box. See Element.getBBox().

  3. Do it yourself by cloning the element, and it's ancestors, to a separate <svg> then calling getBBox() on the <svg>. Ie. create a simplified SVG that looks like the one in the code block ealier in this answer (<svg><g..><polygon>).

Upvotes: 2

Related Questions