Ich mag deine "einzige Idee", nur eine statische Zeichenbreiten-Map zu erstellen! Es funktioniert tatsächlich gut für meine Zwecke. Manchmal möchten Sie aus Leistungsgründen oder weil Sie keinen einfachen Zugriff auf ein DOM haben, nur einen schnellen, eigenständigen Taschenrechner, der auf eine einzelne Schriftart kalibriert ist. Also hier ist eine, die auf Helvetica kalibriert ist; Übergeben Sie eine Zeichenfolge und (optional) eine Schriftgröße:
function measureText(str, fontSize = 10) {
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
return str
.split('')
.map(c => c.charCodeAt(0) < widths.length ? widths[c.charCodeAt(0)] : avg)
.reduce((cur, acc) => acc + cur) * fontSize
}
Dieses riesige hässliche Array besteht aus ASCII-Zeichenbreiten, die durch Zeichencode indiziert werden. Dies unterstützt also nur ASCII (andernfalls wird eine durchschnittliche Zeichenbreite angenommen). Glücklicherweise skaliert die Breite im Wesentlichen linear mit der Schriftgröße, sodass sie bei jeder Schriftgröße ziemlich gut funktioniert. Es fehlt merklich jegliches Bewusstsein für Kerning oder Ligaturen oder was auch immer.
Um "zu kalibrieren", habe ich einfach jedes Zeichen bis zu charCode 126 (der mächtigen Tilde) auf einem SVG gerendert und den Begrenzungsrahmen erhalten und in diesem Array gespeichert. Mehr Code und Erklärung und Demo hier .