我正在解决一个问题,即如何将实用转换后的SVG元素适配到给定的矩形边界中。
- 目标矩形是固定的而且没有进行过变换。
- 输入矩形可能有任意类型的变换。
- 输入矩形可以是任意变换过的群组的子元素。
- 变换应该仅应用于输入矩形。
- 这个问题仅涉及JavaScript元素变换。
当元素本身只有变换时,这是一个很简单的任务:
在这种情况下,目标矩形与输入getBoundingClientRect(在屏幕坐标中的边框矩形)之间的比例等于正确的缩放因子。
但是当父元素也进行变换时,它就无法工作:
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);
document.getElementById('test2').innerHTML = 'expected: 100x100 . Results: ' + resultBBounds.width + 'x' + resultBBounds.height
<svg
version="1.2"
viewBox="0 0 480 150"
width="480"
height="150"
xmlns="http://www.w3.org/2000/svg"
>
<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"
/>
</svg>
<div id="test2"></div>
提前感谢您的想法!
Dipen Shah 给出的答案关注于将变换应用于父元素,这也是一种选择,但我的目标是将元素转换为目标矩形的边界。