计算 SVG 文本高度和宽度的正确方法

Posted

技术标签:

【中文标题】计算 SVG 文本高度和宽度的正确方法【英文标题】:Proper way to calculate the height and width of a SVG text 【发布时间】:2014-06-02 06:26:33 【问题描述】:

我需要计算 svg 文本元素的高度和宽度。有没有办法在不实际将其添加到我页面的 DOM 的情况下这样做?我只需要度量而不是实际元素。

我既没有使用 d3 也没有使用 Raphael,而只使用了纯 javascript。 (也许我应该使用前者之一进行计算?)

我所追求的只是 php 中的 imagettfbbox 之类的函数,但在纯 JavaScript 中。有这样的事吗?还是写起来容易?

因为我实际上并没有使用文本元素,所以添加和隐藏它们对我来说似乎很奇怪(我还在某处读到 Firefox 在计算隐藏元素的 bbox 时遇到问题,Calculating vertical height of a SVG text)。但也许这是唯一的出路?在这种情况下,我必须使用不透明度吗?之后我会以某种方式销毁元素吗?

【问题讨论】:

为什么将它添加到页面的 DOM 会成为问题? 你是如何创建文本元素的?您是在使用像 d3.js 或 Raphael 这样的库,还是在使用 document.createElement(),或者完全不同的东西?给我们一些背景 感谢您的 cmets。我试图提供更多背景信息。 可以使用canvas元素的measureText方法。 不幸的是,使用 measureText 我似乎失去了测量 H<tspan style="baseline-shift:sub;font-size:5px">2</tspan>O 的能力,它可以在 SVG 文本元素中使用。所以这个解决方案似乎不起作用。 【参考方案1】:

也许没有什么好的方法可以实现我所追求的。但是,放弃“没有实际将其添加到我的页面的DOM”部分,以下功能似乎达到了我的目标。

function bboxText( svgDocument, string ) 
    var data = svgDocument.createTextNode( string );

    var svgElement = svgDocument.createElementNS( svgns, "text" );
    svgElement.appendChild(data);

    svgDocument.documentElement.appendChild( svgElement );

    var bbox = svgElement.getBBox();

    svgElement.parentNode.removeChild(svgElement);

    return bbox;

编辑:

关于高度计算的说明:返回的 bbox 的高度,即bbox.height,始终是字形的完整高度,即a 将具有与A 相同的高度。而且我找不到更准确地计算它们的方法。

但是,可以计算大写重音字符的高度,例如Ä。这将只是 bbox y 坐标的负值,即-bbox.y

使用这个可以计算,例如,一些用于垂直对齐的坐标。例如,模拟dominantBaseline 属性设置为text-before-edgetext-after-edgecentral

text-before-edge:dy = -bbox.y

text-after-edge:dy = -bbox.height -bbox.y

central:dy = -bbox.y -bbox.height/2

其中dy 是垂直平移。这可用于绕过某些应用程序的限制,这些应用程序不支持由属性设置的这些对齐方式。

【讨论】:

您是否将其用作“生产”解决方案,最终找到了一种更好的方法来做到这一点而无需实际添加元素(我认为这很慢)? 不幸的是我还没有找到更好的方法。【参考方案2】:

我在VB.Net中也遇到过类似的问题!

我编写了一个生成 SVG 文件的 VB.Net 程序,它需要计算文本的宽度来计算下一个垂直条的位置,如下图所示

B 行竖线定位于计算 A 行元素的最大文本宽度。

要在控制台 VB.Net 应用程序中执行此操作,我执行以下代码行

Private Sub WriteTextInfo(sInfo As String)

    If sInfo <> "" Then
        'display Text in SVG file
        sw.WriteLine("<text x ='" & (xPos + 10) & "' y='" & yPos & "' fill='black' font-family='Arial' font-size='20'>" & sInfo & "</text>")

        'Create Font object as defined in <text> SVG tag 
        Dim font As New Font("Arial", 20.0F)
        'Compute width of text in pixels
        Dim xSize = TextRenderer.MeasureText(sInfo, font)
        'Divide pixels witdh by a factor 1.4 to obtain SVG width !
        Dim iWidth As Decimal = Math.Truncate(CDec(xSize.Width) / 1.4)

        'If new vertical position is greater than old vertical position
        If xPos + iWidth > xPosMax Then
            xPosMax = xPos + iWidth
        End If
    End If
End Sub

在简历中,我使用 TextRenderer.MeasureText() 函数计算文本的宽度(以像素为单位),然后将此数字除以 1.4 以获得 SVG 宽度。

1.4值是相对于我的情况通过实验得到的!

为了使用 TextRendered 和 Font 对象,我添加了对

的引用
System.Drawing
System.Windows.Forms

如您所见,我没有使用任何 DOM 方法来计算文本的宽度,因为我是在 VB.Net 程序中计算的。

【讨论】:

以上是关于计算 SVG 文本高度和宽度的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

带有 viewBox 和宽度的 SVG 在 IE 中无法正确缩放高度

如何在具有特定宽度和高度的矩形中获取 svg 文本元素?

更改 svg 文件的宽度和高度

SVG、文本、固定宽度/高度的字体

如何计算jspdf中文本的宽度和高度?

在 D3 v4 中使 SVG 容器具有父容器的 100% 宽度和高度(而不是像素)