26

Is there any accurate way to get the real size of a svg element that includes stroke, filters or other elements contributing to the element's real size from within Javascript?

I have tried pretty much everything coming to my mind and now I feel I'm coming to a dead end :-(

Updated question to add more context (Javascript)

Emil
  • 714
  • 1
  • 5
  • 10
  • 1
    Should this be translated into screen space, or kept within the coordinates of your SVG document? – Phrogz Mar 24 '12 at 13:15
  • Here's a (bad?) idea: draw a copy of the SVG modified to have only the element itself to an HTML Canvas, and then test opacity of pixels of the canvas to find the bounding box. – Phrogz Mar 24 '12 at 13:22
  • @Phrogz - I also thought about that, but beside the performance implications, there are security constraints preventing me to draw arbitrary SVG in canvas, at least for Gecko/Firefox. I don't really care about the coordinates as I can convert them back and forth fairly easy. – Emil Mar 24 '12 at 17:22
  • 1
    Note that even with a brute-force bounding-box calculation on all pixels of the canvas the performance [is not bad](http://phrogz.net/tmp/canvas_bounding_box.html). – Phrogz Mar 24 '12 at 19:59
  • Indeed, pretty good... But I cannot draw a complex group on a canvas though. – Emil Mar 24 '12 at 21:06

4 Answers4

38

You can't get the values directly. However, you can get the dimensions of the bounding rectangle:

var el   = document.getElementById("yourElement"); // or other selector like querySelector()
var rect = el.getBoundingClientRect(); // get the bounding rectangle

console.log( rect.width );
console.log( rect.height);

It is supported at least in the actual versions of all major browser.

Check fiddle

Community
  • 1
  • 1
Christoph
  • 50,121
  • 21
  • 99
  • 128
  • 7
    Note that a) this is in screen space instead of SVG unit space, but more importantly b) this [does not account for stroke width](http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox). – Phrogz Mar 24 '12 at 13:19
  • It does include the stroke width on browsers that implement it which as far as I know is just Firefox and IE9+ – Robert Longson Mar 24 '12 at 17:16
  • @Phrogz this is wrong. It accounts stroke width. And yes, it's screen size, but thats a good thing, otherwise you would have to calculate the width manually. The OP actually wanted the real size, which I assume is screen size. – Christoph Mar 24 '12 at 19:53
  • @RobertLongson I just checked it, it's supported in all major browsers. – Christoph Mar 24 '12 at 19:53
  • @RobertLongson Oh, interesting. Safari implements this method, but it does not include the borders. – Phrogz Mar 24 '12 at 19:57
  • @Christoph Right you are; I was looking at the wrong spec and an (apparently) buggy implementation. +1 – Phrogz Mar 24 '12 at 19:58
  • @RobertLongson well, i just checked IE, FF, Chrome and Opera... don't have Safari ... I still regularly forget to count this as major browser though it has more marketshare than Opera ... my bad;) – Christoph Mar 24 '12 at 20:11
  • After trying many things, I settled to computing the real bounding rect manually for Webkit, by iterating every child and determining the leftmost, rightmost and so on, including the stroke-width attribute. While this is not a bulletproof solution as it can fail on elements with specific transformations, it covers most scenarios I need in my application. For Gecko, I am going to use getBoundingClientRect. – Emil Mar 26 '12 at 08:53
  • @Christoph I've tried getBoundingClientRect in many browsers and not one of them allows for stroke width. I'd be interested to see a "proof" of this approach? – DeadPassive Jul 24 '13 at 11:47
  • What do you mean by "allow for stroke width"? If you look at http://jsfiddle.net/zLZSw/30/ you will see that except for webkit/blink engine stroke width is considered when the bounding rectangle is calculated. – Christoph Jul 24 '13 at 12:47
  • @Christoph in Firefox, I get c1: 45.916... c2: 68.866... In Chrome, I get c1 & c2 the same, but it is 36.600... different than either number in Firefox. Can you explain this? – Victoria Jan 23 '17 at 23:56
  • @Victoria can you provide a fiddle/codepen so I can have a look at it? – Christoph Jan 24 '17 at 16:32
  • @Christoph I just used yours from the preceding comment. After writing my comment, I wondered if it is just a different in default size of an SVG element in the different browsers... but I haven't followed up on that idea, I'm really looking around trying to figure out how to get the size of an element in SVG coordinates, not window coordinates. – Victoria Jan 24 '17 at 20:23
  • @Christoph looks like it is dependent on the browser window size, and the space jsfiddle assigns to the output area. Would be a better fiddle, if the width and height were specified. And getBBox() seems like the way to get SVG coordinates, which don't change based on the outer size. – Victoria Jan 24 '17 at 23:29
  • @Christoph getBBox doesn't account for stroke width which gives it limited usefulness. It seems like getBoundingClientRect does include stroke width in Firefox and Edge, but not Chrome and Opera, which makes it completely useless. Need an API that returns the bounding box of every pixel drawn as a result of an SVG Element tree, in SVG coordinates... there already is a transformation back to client coordinates... getScreenCTM. – Victoria Jan 24 '17 at 23:35
2

Both raphael js http://dmitrybaranovskiy.github.io/raphael/ and d3 js http://d3js.org/ have various methods to find the size of an svg object or sets of svg object. It depends on if it's a circle, square, path, etc... as to which method to use.
I suspect you are using complex shapes, so in that case bounding box would be your best bet http://raphaeljs.com/reference.html#Element.getBBox (Edit: updated reference site.) http://dmitrybaranovskiy.github.io/raphael/reference.html#Element.getBBox

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Thaddeus Albers
  • 4,094
  • 5
  • 32
  • 42
0

Here is an example using D3.js:

Starting with a div:

<div style="border:1px solid lightgray;"></div>

The javascript code looks like this:

var myDiv = d3.select('div');
var mySvg = myDiv.append('svg');
var myPath = mySvg.append('path');
myPath.attr({
    'fill': '#F7931E',
    'd': 'M37,17v15H14V17H37z M50,0H0v50h50V0z'
});

// Get height and width.
console.log(myPath.node().getBBox());
ValarDohaeris
  • 6,064
  • 5
  • 31
  • 43
kiewic
  • 15,852
  • 13
  • 78
  • 101
-1

You didn't specify any programming language. So I can suggest to use Inkscape.

In the file menu you find document's properties and in the first page there's "resize page to content" command. In this way you remove all the white space around your draw and you see the real size. After width and height values apprear inside the header of svg.

I know that Inkscape supports scripting and command line operations but I don't know if it's possible to do the trimming operatation in this way. But if it's possible you can do that from every programming language.

pluka
  • 133
  • 1
  • 5