5

I'd like my container SVG element to scale in order to fit its child group elements or for it to present scrollbars on overflow. I was wondering if there was a css property in order to do so.

E.g. If the markup looks like the following:

<div class="wrapper" style="width:500px; overflow-x:scroll;">
   <svg class="main">
      <g width="1000"></g>
   </svg>
</div>

How might I get the svg's width to fill to '1000' or present scrollbars if child elements exceed its width?

The following css has no effect on the above:

.main {
    width: 500px; // Setting to 100% also does nothing
    overflow-x: scroll;
}

I currently achieve the desired effect with javascript by updating the svg container's width as necessary; but this is cumbersome and error-prone, as I'd need to check to make sure that when any new element is added inside svg, that the svg container resizes to fit.

Any help would be much appreciated.

funseiki
  • 9,167
  • 9
  • 36
  • 59

3 Answers3

2

remove width and height from the <svg> and add an viewBox attribute instead. Addionally you need a preserveAspectRatio attribute with a value of your desired behavior.

For more detailed information have a look here. This method uses the SVG viewport which is a bit complicated at the first glance, but in effect, this separates the visible dimensions from the graphical setup of the graphic. This way the <svg> receives its width and height from the context it lives in, from the css in your case.

It took me a while to understand that concept, but once you got it you will notice that gives you a lot flexibility, what is actually much more than with pixel images.

philipp
  • 15,947
  • 15
  • 61
  • 106
  • I'm not sure how setting the viewBox attribute attribute helps. Here is a [fiddle](http://jsfiddle.net/T6CWy/) with your above suggestions. Preserve aspect ratio only has 'meet' and 'slice', neither of which seem to update the width (or add scrollbars) as necessary. – funseiki May 05 '14 at 16:22
  • to be honest, still I do not clearly understand what you would like to achieve, but with the above approach you can fit an svg into the bounds of its context. If it is not possible to create an html element which updates in the way you desire, by some css settings, than it is also not possible for an svg element and you have to do the trick with javascript. – philipp May 05 '14 at 16:34
0

Not sure if this solves your problem or not, but you could put the constraints on svg's parent tag (the div tag).

Something like this:

<div class="wrapper">
  <svg class="main" xmlns="http://www.w3.org/2000/svg">
    <g>
      <rect x="20" y="20" height="250" width="400" style="fill:#006600"/>       
    </g>
  </svg>
</div>

.wrapper {
    width: 200px;
    height: 100px;
    overflow: scroll;
}
.main {
    width: 400px; 
    height: 250px;
}

Here's a jsfiddle.

sfletche
  • 47,248
  • 30
  • 103
  • 119
  • With the above, the rect still gets clipped (the scrollbar doesn't reach its end). I would still need to dynamically set the svg's width and height in order for the outer div's scrollbar to reach the end of the rect. – funseiki May 04 '14 at 07:13
  • @funseiki - you can fix that by adding a margin to the `svg` element. See the updated fiddle in my answer. – sfletche May 04 '14 at 14:14
  • This does not fix the issue, try changing the x position of the rect to 300 for an exaggerated view. The margin just creates an extra whitespace, but it does not actually extend the viewing range past the rect. – funseiki May 04 '14 at 14:41
  • Ah. I see your problem. You want an outer container that can handle dynamic changes (or any values) in the size of the svg. If that's the case, your initial javascript strategy is likely correct. – sfletche May 04 '14 at 16:01
0

There is no way to have the SVG automatically update its width and height when you add elements to it. All you can do is manually update the width and height yourself.

However, rather than having to remember to update the SVG width and height every time you add something, you could add an interval timer function to do the check for you.

setInterval(mySVGCheckFn, 500);

function  mySVGCheckFn() 
{
    var  svg = document.getElementById("mysvg");
    var  bbox = svg.getBBox();

    // Add 10 padding for some breathing space    
    svg.setAttribute("width", bbox.x + bbox.width + 10);
    svg.setAttribute("height", bbox.y + bbox.height + 10);
}

Demo here

Click 'Add more' to add random circles to the SVG.

DOM2 added some event types that are supposed to be fired when you add nodes to the DOM. They would be the ideal solution, however I believe they aren't supported reliably across all browsers.

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • 1
    Seems a bit wasteful to run this all the time. If one is modifying the DOM it's not hard to call a function like this after having inserted some child elements. – Erik Dahlström May 05 '14 at 10:38
  • 1
    I agree that it is not the nicest solution, but the OP wanted a way to do it without having to "check to make sure that when any new element is added". :) – Paul LeBeau May 05 '14 at 10:42
  • This works (aside from negative values) as needed, though I think I'll probably just stick to updating as new elements are added. – funseiki May 05 '14 at 16:28
  • Yes I deliberately chose not to handle negative coords to keep things simple. If you wanted those objects to be visible, you would need to update the viewBox as well as width and height. – Paul LeBeau May 06 '14 at 03:09