我喜欢你做一个静态字符宽度映射的“唯一想法”!它实际上很适合我的目的。有时,出于性能原因或因为您无法轻松访问 DOM,您可能只需要一个快速的 hacky 独立计算器,校准为单一字体。所以这里有一个校准到 Helvetica 的;传递一个字符串和一个字体大小:
const widths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.2796875,0.2765625,0.3546875,0.5546875,0.5546875,0.8890625,0.665625,0.190625,0.3328125,0.3328125,0.3890625,0.5828125,0.2765625,0.3328125,0.2765625,0.3015625,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.2765625,0.2765625,0.584375,0.5828125,0.584375,0.5546875,1.0140625,0.665625,0.665625,0.721875,0.721875,0.665625,0.609375,0.7765625,0.721875,0.2765625,0.5,0.665625,0.5546875,0.8328125,0.721875,0.7765625,0.665625,0.7765625,0.721875,0.665625,0.609375,0.721875,0.665625,0.94375,0.665625,0.665625,0.609375,0.2765625,0.3546875,0.2765625,0.4765625,0.5546875,0.3328125,0.5546875,0.5546875,0.5,0.5546875,0.5546875,0.2765625,0.5546875,0.5546875,0.221875,0.240625,0.5,0.221875,0.8328125,0.5546875,0.5546875,0.5546875,0.5546875,0.3328125,0.5,0.2765625,0.5546875,0.5,0.721875,0.5,0.5,0.5,0.3546875,0.259375,0.353125,0.5890625]
const avg = 0.5279276315789471
function measureText(str, fontSize) {
return Array.from(str).reduce(
(acc, cur) => acc + (widths[cur.charCodeAt(0)] ?? avg), 0
) * fontSize
}
那个巨大的丑陋数组是由字符代码索引的 ASCII 字符宽度。所以这只支持ASCII(否则它假设一个平均字符宽度)。幸运的是,宽度基本上与字体大小成线性关系,因此它在任何字体大小下都能很好地工作。它明显缺乏对字距调整或连字等的任何认识。
为了“校准”,我只是在 svg 上将每个字符渲染到 charCode 126(强大的波浪号),然后得到边界框并将其保存到这个数组中; more code and explanation and demo here.