在浏览器

时间:2017-03-31 11:56:48

标签: javascript svg fonts bounding-box

在浏览器中使用SVG时,浏览器具有getBBox功能,可以为您提供各种元素的边界框。但是当谈到文本元素时,我真的很困惑我如何计算这个装箱。 我知道fontsize是基于字体文件中指定的em-Box。 但是我的测试表明,这些结果都不会产生与FF或Chrome相同的结果(在fontsize 1000上只有几个px):

fontSize != bbox-height
(ascender-descender)/unitsPerEm * fontSize != bbox-height
(unitsPerEm-descender)/unitsPerEm * fontSize != bbox-height
...maybe adding a fixed amount to ascender for accents? Like Ć

那么浏览器中文本的bbox高度背后的秘密是什么?

我甚至试图查看FF和Chrome的源代码,但找到计算所依据的正确位置本身就是一个挑战

//编辑:回应评论: 我想在浏览器中计算svg文本的bbox(复制行为)。我需要知道正确计算bbox所需的字体度量以及用于计算(宽度和高度足够)的公式

1 个答案:

答案 0 :(得分:2)

经过大量的reasearch和tril以及错误后,我找到了一个可能的解决方案,至少解释了文本bbox维度的chromes行为。

BBox身高

首先,我使用npm包fontkit来加载和解析字体文件。 fontkit为您提供了整个字体的几个指标,其中包括:

  • font.ascent
  • font.descent
  • font.lineGap
  • font.unitsPerEm

所以为了计算bbox的高度,我想到了以下几点:

bboxHeight = (font.ascent - font.descent + font.lineGap) / unitsPerEm * fontSize

但是,如果字体比em框(font.ascent - font.descent > unitsPerEm)大,则会导致错误。在这种特殊情况下,bboxHeightfont.ascent - font.descent

这导致以下代码为高度:

var fontHeight = font.ascent - font.descent
var lineHeight = fontHeight > font.unitsPerEm ? fontHeight : fontHeight + font.lineGap
var height = lineHeight/font.unitsPerEm * fontSize

BBox宽度

计算我使用layout fontkit功能的文字宽度。 layout使您可以访问从中提取文本的字形,还可以访问字形的度量标准。我们需要的指标是advanceWidth,其中包括当前glpyh旁边的其他字形的边距。通过汇总所有advanceWidth并相应地缩放它们,我最终获得了bboxWidth

var width = font.layout(text).glyphs.reduce((last, curr) => last + curr.advanceWidth, 0)
width = width / font.unitsPerEm * fontSize

BBox y位置

麻烦不止于此,我们仍然需要计算bbox的y位置。这是一个相当简单的公式:

var bboxY = y-font.ascent/font.unitsPerEm * fontSize

其中y是你从dom(ydy属性)拉出的理论位置

BBox x位置

这就是你从dom(xdx)拉出的数字

整箱:

var box = {
    x:x,
    y: y-font.ascent/font.unitsPerEm * fontSize,
    width: width
    height: height
}

希望它可以帮助别人!