Given this SVG:
<svg xmlns="http://www.w3.org/2000/svg">
<rect width="50" height="50"
transform="translate(75,75) rotate(45) translate(-25,-25)" />
<script>
var bb = document.querySelector('rect').getBBox();
console.log([bb.x,bb,y,bb.width,bb.height]);
</script>
</svg>
The resulting output is [0, 0, 50, 50]
.
The desired result is [39.645,39.645,70.711,70.711]
.
Visual Version: http://jsfiddle.net/2wpju/7/
What's the simplest, most efficient way to calculate the bounding box of an element with respect to its parent element?
Below is the best answer I've come up with so far, but there are two problems:
- It seems like a lot of work for what might be handled better, and
- As seen in this demo it's not necessarily the minimum bounding box (notice the upper circle), since the axis-aligned bounding box of a rotated axis-aligned bounding box always increases the size.
// Calculate the bounding box of an element with respect to its parent element
function transformedBoundingBox(el){
var bb = el.getBBox(),
svg = el.ownerSVGElement,
m = el.getTransformToElement(el.parentNode);
// Create an array of all four points for the original bounding box
var pts = [
svg.createSVGPoint(), svg.createSVGPoint(),
svg.createSVGPoint(), svg.createSVGPoint()
];
pts[0].x=bb.x; pts[0].y=bb.y;
pts[1].x=bb.x+bb.width; pts[1].y=bb.y;
pts[2].x=bb.x+bb.width; pts[2].y=bb.y+bb.height;
pts[3].x=bb.x; pts[3].y=bb.y+bb.height;
// Transform each into the space of the parent,
// and calculate the min/max points from that.
var xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity;
pts.forEach(function(pt){
pt = pt.matrixTransform(m);
xMin = Math.min(xMin,pt.x);
xMax = Math.max(xMax,pt.x);
yMin = Math.min(yMin,pt.y);
yMax = Math.max(yMax,pt.y);
});
// Update the bounding box with the new values
bb.x = xMin; bb.width = xMax-xMin;
bb.y = yMin; bb.height = yMax-yMin;
return bb;
}