如何获得 SVG 文本元素的紧密边界框
How get tight bounding box of an SVG Text Element
通常为了获取 SVG 中任何元素的边界框,我们使用 getBoundingClientRect() 或 getBBox() 分别为我们提供顶部、底部、左侧、右侧、宽度、高度或 x、y、宽度、高度。但是当文本旋转时,这些值不足以获得元素的紧密边界框,因为由这些值形成的框将具有水平和垂直边缘,不平行于文本。如何为旋转文本选择紧密边界框,如下图所示。 (文本已通过 Chrome 检查元素选择器突出显示。)
没有直接的方法可以实现这一点。但是您可以尝试以下解决方案。
如果您使用 getBBox()
获取 <text>
元素的边界框,那么它通常是未旋转的边界框。那是因为getBBox()
在计算return的值时没有包含元素transform
。
例如,请看下面的示例。比较文本BBox与其父组元素的BBox。
var text = document.getElementById("text");
var b = text.getBBox();
console.log("text bbox="+[b.x,b.y,b.width,b.height].join(' '));
var group = document.getElementById("group");
var b = group.getBBox();
console.log("group bbox="+[b.x,b.y,b.width,b.height].join(' '));
<svg width="300" height="300">
<g id ="group">
<text id="text" x="150" y="150" text-anchor="middle" font-size="30"
transform="rotate(45,150,150)">ROTATED</text>
</g>
</svg>
我想如果你想要这 4 个点,你可能必须使用与元素相同的变换在边界框上变换它们。如果只是为了显示,只需对已经显示的边界框应用相同的变换即可。我想如果你想要4点,它有点复杂,但可能有更简单的方法。
无论如何,这可能会有用。
我们抓取文本的边界框。
我们抓取元素上的矩阵(在本例中为旋转)。
然后我们将其应用于我们从边界框收集的所有点。
我添加了更多代码,只是为了在点处创建圆圈,以突出显示它。
var text = document.querySelector('text');
var svg = document.querySelector('svg')
function getTransformedPts( el ) {
var m = el.getCTM();
var bb = el.getBBox();
var tpts = [
matrixXY(m,bb.x,bb.y),
matrixXY(m,bb.x+bb.width,bb.y),
matrixXY(m,bb.x+bb.width,bb.y+bb.height),
matrixXY(m,bb.x,bb.y+bb.height) ]
return tpts;
}
function matrixXY(m,x,y) {
return { x: x * m.a + y * m.c + m.e, y: x * m.b + y * m.d + m.f };
}
var pts = getTransformedPts( text );
for( pt in pts ) {
var c = document.createElementNS("http://www.w3.org/2000/svg","circle");
c.setAttribute('cx', pts[pt].x);
c.setAttribute('cy', pts[pt].y);
c.setAttribute('r',3)
svg.append(c)
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="800" height="800">
<text x="50" y="50" transform="rotate(10)" font-size="30">testing rotated text box points</text>
</svg>
通常为了获取 SVG 中任何元素的边界框,我们使用 getBoundingClientRect() 或 getBBox() 分别为我们提供顶部、底部、左侧、右侧、宽度、高度或 x、y、宽度、高度。但是当文本旋转时,这些值不足以获得元素的紧密边界框,因为由这些值形成的框将具有水平和垂直边缘,不平行于文本。如何为旋转文本选择紧密边界框,如下图所示。 (文本已通过 Chrome 检查元素选择器突出显示。)
没有直接的方法可以实现这一点。但是您可以尝试以下解决方案。
如果您使用 getBBox()
获取 <text>
元素的边界框,那么它通常是未旋转的边界框。那是因为getBBox()
在计算return的值时没有包含元素transform
。
例如,请看下面的示例。比较文本BBox与其父组元素的BBox。
var text = document.getElementById("text");
var b = text.getBBox();
console.log("text bbox="+[b.x,b.y,b.width,b.height].join(' '));
var group = document.getElementById("group");
var b = group.getBBox();
console.log("group bbox="+[b.x,b.y,b.width,b.height].join(' '));
<svg width="300" height="300">
<g id ="group">
<text id="text" x="150" y="150" text-anchor="middle" font-size="30"
transform="rotate(45,150,150)">ROTATED</text>
</g>
</svg>
我想如果你想要这 4 个点,你可能必须使用与元素相同的变换在边界框上变换它们。如果只是为了显示,只需对已经显示的边界框应用相同的变换即可。我想如果你想要4点,它有点复杂,但可能有更简单的方法。
无论如何,这可能会有用。
我们抓取文本的边界框。 我们抓取元素上的矩阵(在本例中为旋转)。 然后我们将其应用于我们从边界框收集的所有点。 我添加了更多代码,只是为了在点处创建圆圈,以突出显示它。
var text = document.querySelector('text');
var svg = document.querySelector('svg')
function getTransformedPts( el ) {
var m = el.getCTM();
var bb = el.getBBox();
var tpts = [
matrixXY(m,bb.x,bb.y),
matrixXY(m,bb.x+bb.width,bb.y),
matrixXY(m,bb.x+bb.width,bb.y+bb.height),
matrixXY(m,bb.x,bb.y+bb.height) ]
return tpts;
}
function matrixXY(m,x,y) {
return { x: x * m.a + y * m.c + m.e, y: x * m.b + y * m.d + m.f };
}
var pts = getTransformedPts( text );
for( pt in pts ) {
var c = document.createElementNS("http://www.w3.org/2000/svg","circle");
c.setAttribute('cx', pts[pt].x);
c.setAttribute('cy', pts[pt].y);
c.setAttribute('r',3)
svg.append(c)
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="800" height="800">
<text x="50" y="50" transform="rotate(10)" font-size="30">testing rotated text box points</text>
</svg>