【问题标题】:How can I get the actual height of a SVG text (not the bounding box height)如何获得 SVG 文本的实际高度(不是边界框高度)
【发布时间】:2017-02-20 07:42:49
【问题描述】:

我希望能够计算 SVG 中文本(或跨度)元素占用的实际高度。

目前,我通过计算对象边界框的高度来实现这一点,但它需要字体字形的高度,因此我放入元素中的任何文本都具有相同的高度,如下例所示:

var minA = document.getElementById('min-a'),
    capA = document.getElementById('cap-a'),
    minAHeight = document.getElementById('min-a-height'),
    capAHeight = document.getElementById('cap-a-height')
;

minAHeight.innerHTML = minA.getBBox().height;
capAHeight.innerHTML = capA.getBBox().height;
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 80">
  <text id="min-a" x="20" y ="20">a</text>
  <text id="cap-a" x="20" y ="50">Â</text>
  <text id="min-a-height" x="70" y ="20"></text>
  <text id="cap-a-height" x="70" y ="50"></text>
<svg>

如何计算每个元素的实际高度?

【问题讨论】:

  • 没有API,即你不能。
  • @RobertLongson 你绝对可以
  • @RobertLongson 发布 :)

标签: javascript html svg


【解决方案1】:

@Fuzzyma 走在正确的轨道上。您想使用 OpenType.js 并在浏览器中加载字体。

// These two match whatever you are doing in your code
const text = 'Hello'
const fontSize = 20

// Load font - I find ttf work better than woff (has extra data for other calculations if needed)
opentype.load(`/path/to/font.ttf`, (err, font) => {

   // Actual dimensions of the text
   const bb = font.getPath(text, 0, 0, fontSize)

})

这将为您提供真正的边界框,可能足以满足您的需求。如果您确实需要使用它来了解文本上的屏幕位置,这是可能的,但它更具挑战性。

它的要点是你需要匹配基线。字体包含升序/降序(font.tables.hhea.asscenderfont.tables.hhea.descender),一旦转换为 em(font.tables.head.unitsPerEm * fontSize),它们的总和就会达到字体大小。

有了这个,您需要遍历字体的每个字形并获得yMaxyMinxMinxMax。使用上升/下降和 Y 坐标来确定新 bb 与“假”边界框(DOM 返回的边界框)的距离。左边和右边更容易,除了一些奇怪的字体,它们的字母可以延伸到它们的邻居之外(边缘大小写)。

在浏览器之上添加每个浏览器的垂直偏移量...这可以通过获取 SVG 文本元素的 y 属性(即 -5)来提取 - 然后您将字体大小除以一半,然后取这个y,你就有了浏览器使用的垂直偏移量(在我们的例子中是5)。每个浏览器都不同,但 y 坐标反映了这一点。

【讨论】:

    【解决方案2】:

    不确定这是否能解决您的问题,但我能够使用画布 measureText 方法计算单个字母的尺寸:

    function getLetterSize(letter) {
        const ctx = document.createElement("canvas").getContext("2d");
        ctx.font = "25px sans-serif";
        const dim = ctx.measureText(letter);
        return {
            width: dim.actualBoundingBoxRight + dim.actualBoundingBoxLeft,
            height: dim.actualBoundingBoxAscent + dim.actualBoundingBoxDescent
        };
    }
    

    【讨论】:

      【解决方案3】:

      为此,您需要加载和解析字体文件,并使用其中存储的字形来计算边界框。 在服务器上,您将使用opentype.jsfontkit 加载字体并获取某些文本的边界框。

      但是在客户端你需要自己解析字体文件。对于 svg 字体来说这很容易,但在处理二进制格式(例如 truetype)时会变得更加困难。
      但是当你设法做到这一点时,你可以绘制 glypgs 的路径并使用浏览器 getBBox() 来计算你想要的边界框。

      这就是理论 - 但我的猜测是,解决这个问题比编写自己的字体文件解析器更容易。

      如果有人知道,请随时编辑!

      【讨论】:

        【解决方案4】:

        对于 svg 中的文本,您可以根据需要手动设置字体大小

        <svg:text #t
          [attr.x]="xoffset"
          [attr.y]="yoffset"
          font-family="Courier"
          [attr.font-size]="fontsize">
          {{bottom_text.toUpperCase()}}
        </svg:text> 
        

        这将在您的 svg 元素中为您提供静态大小的字体。您还可以选择使用浏览器开发工具在实际元素上“检查元素”。选择时会显示所选元素的宽度和高度。 (例如,参见图片)这个“悬停”高度将包括与元素关联的任何填充,但检查元素上列出的属性它还应该包含仅字体高度“font-size”

        【讨论】:

        • SVG text 元素的 font-size 属性是从基线到基线测量的,不幸的是,它与实际文本的边界框完全不同。
        猜你喜欢
        • 1970-01-01
        • 2017-05-21
        • 2015-12-31
        • 1970-01-01
        • 1970-01-01
        • 2013-02-16
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        相关资源
        最近更新 更多