Question

How can I reliably ask for the size (in pixels) an SVG element is taking up on the host page?

  • Both svg.offsetWidth and svg.getBoundingClientRect().width work in Chrome v34.
  • Neither of those work correctly in Firefox v29. (The former is empty, the latter returns incorrect values.)

Test Page: http://jsfiddle.net/dL5pZ/3/

The motivation for this question is to get a reliable implementation for this answer, which requires knowing the aspect ratio of the outside of the element. Further, for this question I need to know the actual size of the SVG, or at least something that returns proportionate values across different calls and a resizing element.

Was it helpful?

Solution

I've been down that road before. Unfortunately, most of the functions for getting the size of the <svg> element are buggy in Firefox. The only working solution I found was using window.getComputedStyle(svgElement).width (or height), which needs to be parsed (and also only works when svgElement.display == 'block', which it is in your example). I have adopted your fiddle to work in Firefox: http://jsfiddle.net/dL5pZ/5/

Update: The issue with display 'inline' was fixed some time ago around Firefox 29.

Update 2: As mentioned in another answer, getBoundingClientRect should also work nowadays.

OTHER TIPS

Some more info from my research because I've spent the last 2 days working on this issue..

So, it always works in Chrome and Opera, it works in IE if you add preserveAspectRatio="xMinYMin slice" but Firefox seems buggy.

To make it work cross platform try: a) accessing width and height of SVG directly - Ch,O,IE b) getComputedStyle:

var style = window.getComputedStyle(svg, null);
var svgWidth = style.getPropertyValue("width").slice(0, -2);  // "1240px" -> "1240"

keep in mind that for single queries it is fine, but when you try to do it about 60 times per second then the browser becomes very slow c) as we know this issue happens when we have

<div><svg style="width:100%; height:100%"></svg></div>

and the width and height of SVG element are 1 in Firefox.. but these dimensions are as same as the dimensions of the div parent element which you can access! But to make life harder it doesn't work in IE.

So reassuming, this is my final cross browser code:

if(!svg.width.baseVal.value || svg.width.baseVal.value < 2){
  //this is the FF case
  if(!this.parentElement) return;
  this.width = this.parentElement.clientWidth;
  this.height = this.parentNode.clientHeight;
}
else{
  //this works for Ch,O,IE
  this.width = svg.width.baseVal.value;
  this.height = svg.height.baseVal.value
}

getBoundingClientRect has been fixed in Firefox from version 33 onwards and will do what you want it to now. See bug 530985 for details.

This was the way I fixed it:

var heightComponents = ['height', 'paddingTop', 'paddingBottom', 'borderTopWidth', 'borderBottomWidth'],
    widthComponents = ['width', 'paddingLeft', 'paddingRight', 'borderLeftWidth', 'borderRightWidth'];

var svgCalculateSize = function (el) {

    var gCS = window.getComputedStyle(el), // using gCS because IE8- has no support for svg anyway
        bounds = {
            width: 0,
            height: 0
        };

    heightComponents.forEach(function (css) { 
        bounds.height += parseFloat(gCS[css]);
    });
    widthComponents.forEach(function (css) {
        bounds.width += parseFloat(gCS[css]);
    });
    return bounds;
};

Using your jsFiddle: http://jsfiddle.net/dL5pZ/7/

This is what I ended up using:

var svgWidth = svg.clientWidth || window.getComputedStyle(svg).width.slice(0, -2),
    svgHeight = svg.clientHeight || window.getComputedStyle(svg).height.slice(0, -2);

as clientWidth and clientHeight always return 0 in Firefox.

For d3 users:

var svg = d3.select('#yoursvg')[0][0],
    svgWidth = svg.clientWidth || window.getComputedStyle(svg).width.slice(0, -2),
    svgHeight = svg.clientHeight || window.getComputedStyle(svg).height.slice(0, -2);

Hope it helps.

<button onclick="demosvg()">click on</button>

<svg>       
  //<image xlink:href="demo.jpg" id="img1" height="200" width="200"/>    
  <img id="myImg" src="demo.jpg" style="width:500px;height:98px;">
</svg>

<div id="demo"></div>


<script>
function demosvg() {
    var var1 = document.getElementById("img1").naturalWidth;
    document.getElementById("demo").innerHTML = "width is: " + var1+ " pixels";


}
</script>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top