Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the bounds of a rotated SVG element in screen pixels?

I'm trying to find the best way to get the bounding box of an arbitrary SVG element in screen pixels, in order to overlay an HTML element correctly. My approach so far has been to use .getBBox() and .getCTM() to retrieve the object's bounding box and transform matrix, then apply the transform to the bounding box points as described in the accepted answer to this question.

// get the element
var el = $(selector)[0],
    pt = $(selector).closest('svg')[0].createSVGPoint();

// get the bounding box and matrix
var bbox = el.getBBox(),
    matrix = el.getScreenCTM();

pt.x = bbox.x;
pt.y = bbox.y;
var nw = pt.matrixTransform(matrix);
pt.x += bbox.width;
pt.y += bbox.height;
var se = pt.matrixTransform(matrix);

// make a div in the screen space around the object
var $div = $('<div class="bbox"/>').css({
        left: nw.x,
        top: nw.y,
        width: se.x - nw.x,
        height: se.y - nw.y
    })
    .appendTo('body');

You can see my test here: http://jsfiddle.net/nrabinowitz/zr2jX/

However, as the test shows, this approach seems to fail when there's a rotation included in the transform - it looks like the bounding box is calculated pre-rotation, so getting the corners of the rotated bounding box isn't working.

How can I properly calculate the non-rotated bounding box of the transformed elements?

like image 773
nrabinowitz Avatar asked Aug 30 '12 18:08

nrabinowitz


1 Answers

After some research, here are the best options I've found:

  • getBoundingClientRect() seems to work well for SVG elements in modern browsers, and is quite fast, but results may vary somewhat from platform to platform (especially if you have a substantial stroke width). However, to @Sergiu's point, this does not account for changes in shape, and gives you the bounds of the rotated bounding box, not the actual path or object, so it can be quite imprecise - see criticism here. Example fiddle: http://jsfiddle.net/stevenbenner/6M5zf/

  • My main goal was to get positional corners and midpoints of the bounding rectangle, and in the end I decided that using the rotated bounding box might even be preferable to the "real" bounding box of a rotated shape. I was able to do this using the approach above, and then cycling the points to get as close as possible to N,S,E,W positions. You can see my example fiddle here: http://jsfiddle.net/nrabinowitz/sPtzV/

like image 184
nrabinowitz Avatar answered Oct 26 '22 20:10

nrabinowitz