Воспроизвести ограничивающую рамку текста в браузерах

При использовании SVG в браузере браузер имеет getBBox функция, чтобы дать вам ограничительную рамку различных элементов. Но когда дело дошло до текстовых элементов, меня очень смутило, как рассчитывается эта коробка. Я знаю, что размер шрифта основан на em-Box, который указан в файле шрифта. Однако мои тесты показывают, что ни один из них не дает таких же результатов, как в FF или Chrome (которые отличаются только на несколько пикселей на fontsize 1000):

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, но найти правильное место, где основаны расчеты, - это сложная задача.

// РЕДАКТИРОВАТЬ: В ответ на комментарий: я хочу рассчитать bbox текста SVG, как это сделано в браузере (повторить поведение). Мне нужно знать метрики шрифта, которые необходимы для правильного расчета bbox и формуляра, который используется для вычисления (ширина и высота достаточны)

1 ответ

Решение

После множества исследований и поисков и ошибок я нашел возможное решение, по крайней мере, для объяснения поведения цветов в текстовых измерениях bbox.

Высота 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). В этом особом случае bboxHeight является font.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 S и масштабируя их соответственно, я в конечном итоге с bboxWidth:

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

BBox y position

Проблема не останавливается здесь, мы все еще должны вычислить y-позицию bbox. Вот довольно простая формула:

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

Где у теоретическая позиция, которую вы бы вытянуть из дома (y а также dy атрибут)


BBox x position

Это просто фигура, которую вы вытаскиваете из дома (x а также dx)


Вся коробка:

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

Надеюсь, это поможет кому-то еще!

Другие вопросы по тегам