I am struggling with an issue to fit pragmatically transformed SVG element into the given rect bounds.
- Destination rect is given and not transformed.
- Input rect has any type of transformations.
- Input rect can be a child of transformed groups.
It's an easy task when the element has only transformations by itself:
In this case proportion between the destination and input getBoundingClientRect (bounding rect in screen coordinates) is equals to a proper scaling factor.
But it's not working when parent elements are transformed by itself:
var inputElement = document.getElementById("input");
var destinationElement = document.getElementById("destination");
var inputBB = inputElement.getBoundingClientRect();
var outputBB = destinationElement.getBoundingClientRect();
var scaleX = outputBB.width / inputBB.width;
var scaleY = outputBB.height / inputBB.height;
// get offsets between figure center and destination rect center:
var offsetX = outputBB.x + outputBB.width / 2 - (inputBB.x + inputBB.width / 2);
var offsetY =
outputBB.y + outputBB.height / 2 - (inputBB.y + inputBB.height / 2);
// get current figure transformation
let currentMatrix = (
inputElement.transform.baseVal.consolidate() ||
inputElement.ownerSVGElement.createSVGTransform()
).matrix;
// Get center of figure in element coordinates:
const inputBBox = inputElement.getBBox();
const centerTransform = inputElement.ownerSVGElement.createSVGPoint();
centerTransform.x = inputBBox.x + inputBBox.width / 2;
centerTransform.y = inputBBox.y + inputBBox.height / 2;
// create scale matrix:
const svgTransform = inputElement.ownerSVGElement.createSVGTransform();
svgTransform.setScale(scaleX, scaleY);
let scalingMatrix = inputElement.ownerSVGElement
.createSVGMatrix()
// move the figure to the center of the destination rect.
.translate(offsetX, offsetY)
// Apply current matrix, so old transformations are not lost
.multiply(currentMatrix)
.translate(centerTransform.x, centerTransform.y)
// multiply is used instead of the scale method while for some reasons matrix scale is giving proportional scaling...
// From a transforms proper matrix is generated.
.multiply(svgTransform.matrix)
.translate(-centerTransform.x, -centerTransform.y);
// Apply new created matrix to element back:
const newTransform = inputElement.ownerSVGElement.createSVGTransform();
newTransform.setMatrix(scalingMatrix);
inputElement.transform.baseVal.initialize(newTransform);
var bboundsTest= document.getElementById("bboundsTest");
const resultBBounds = inputElement.getBoundingClientRect();
bboundsTest.setAttribute('x', resultBBounds .x);
bboundsTest.setAttribute('y', resultBBounds .y);
bboundsTest.setAttribute('width', resultBBounds .width);
bboundsTest.setAttribute('height', resultBBounds .height);
<svg
version="1.2"
viewBox="0 0 480 240"
width="480"
height="240"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<g transform="skewX(10) translate(95,1) rotate(30)">
<g transform="skewX(30) translate(-3,3) rotate(30)">
<g transform="skewX(10) translate(-3,4) rotate(10)">
<rect
id="input"
transform="translate(95,76.5) skewX(25) translate(50,50) scale(1.5) translate(-50,-50) translate(0,0) rotate(45)"
width="30"
height="30"
fill="red"
/>
</g>
</g>
</g>
<rect
id="destination"
x="20"
y="20"
width="100"
height="100"
fill="transparent"
stroke="blue"
/>
<rect
id="bboundsTest"
x="20"
y="20"
width="100"
height="100"
fill="transparent"
stroke="black"
/>
</g>
</svg>Any ideas how to take parent transformations into the count to find proper scaling factors?
Thanks in advance for the ideas!
from Fit SVG transformed element into the rect bounds with JavaScript

No comments:
Post a Comment