I'm trying to calculate the bounding box of transformed SVG elements and for that I'm using getBoundingClientRect() and mapping the x and y values to SVG coordinates. However, this function seems to produce wrong outputs in Chrome and Edge when the shape has curves and a rotation. In the other hand, Firefox is able to produce the expected result.
You would achieve the same with something like this (more or less useless code just for illustration):
<script type="text/javascript">
const svg = document.getElementById('svg');
let svgElem = document.getElementById('svgElem');
const bBox = svgElem.getBBox(); // MDN: The returned value is a SVGRect object, which defines the bounding box. This value is irrespective of any transformation attribute applied to it or the parent elements
console.dir(bBox);
const boundingClientRect = svgElem.getBoundingClientRect();
console.dir(boundingClientRect);
// create a rect without transforms
const rect1 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect1.setAttribute('x', bBox.x);
rect1.setAttribute('y', bBox.y);
rect1.setAttribute('width', bBox.width);
rect1.setAttribute('height', bBox.height);
rect1.setAttribute('fill', '#00ff0040');
svg.appendChild(rect1);
const ctm = svgElem.getCTM();
const topLeftX = ctm.a * bBox.x ctm.c * bBox.y ctm.e;
const topLeftY = ctm.b * bBox.x ctm.d * bBox.y ctm.f;
const topRightX = ctm.a * (bBox.x bBox.width) ctm.c * bBox.y ctm.e;
const topRightY = ctm.b * (bBox.x bBox.width) ctm.d * bBox.y ctm.f;
const bottomLeftX = ctm.a * bBox.x ctm.c * (bBox.y bBox.height) ctm.e;
const bottomLeftY = ctm.b * bBox.x ctm.d * (bBox.y bBox.height) ctm.f;
const bottomRightX = ctm.a * (bBox.x bBox.width) ctm.c * (bBox.y bBox.height) ctm.e;
const bottomRightY = ctm.b * (bBox.x bBox.width) ctm.d * (bBox.y bBox.height) ctm.f;
const x = Math.min(topLeftX, topRightX, bottomLeftX, bottomRightX);
const y = Math.min(topLeftY, topRightY, bottomLeftY, bottomRightY);
const width = Math.max(topLeftX, topRightX, bottomLeftX, bottomRightX) - x;
const height = Math.max(topLeftY, topRightY, bottomLeftY, bottomRightY) - y;
const rect2 = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect2.setAttribute('x', x);
rect2.setAttribute('y', y);
rect2.setAttribute('width', width);
rect2.setAttribute('height', height);
rect2.setAttribute('fill', '#ff000040');
svg.appendChild(rect2);
</script>
Or you could just check the Developer tools of Firefox/Chromium to see the dfifferences (just to say putting a group around doesn't work either).
Maybe SVG version 2 will make a difference in the future:
So this might be a workaround way to get the "real" bounding box.
As for getBoundingClientRect: MDN says: "The returned value is a DOMRect object which is the smallest rectangle which contains the entire element, including its padding and border-width."
IMHO there is a bug in Chromium's implementation.