如何在 HTML 画布上找到文本的高度?

该规范有一个 context.memureText (text)函数,它会告诉您打印该文本需要多大的宽度,但我找不到一种方法来确定它有多高。我知道它是基于字体的,但我不知道如何将字体字符串转换为文本高度。

143619 次浏览

画布规范没有给出测量字符串高度的方法。但是,您可以设置文本的像素大小,并且通常可以相对容易地确定垂直边界。

如果你需要更精确的东西,那么你可以把文本扔到画布上,然后得到像素数据,并计算出有多少像素是垂直使用的。这相对简单,但效率不高。您可以这样做(它可以工作,但是在画布上绘制一些您希望删除的文本) :

function measureTextHeight(ctx, left, top, width, height) {


// Draw the text in the specified area
ctx.save();
ctx.translate(left, top + Math.round(height * 0.8));
ctx.mozDrawText('gM'); // This seems like tall text...  Doesn't it?
ctx.restore();


// Get the pixel data from the canvas
var data = ctx.getImageData(left, top, width, height).data,
first = false,
last = false,
r = height,
c = 0;


// Find the last line with a non-white pixel
while(!last && r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
last = r;
break;
}
}
}


// Find the first line with a non-white pixel
while(r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
first = r;
break;
}
}


// If we've got it then return the height
if(first != r) return last - first;
}


// We screwed something up...  What do you expect from free code?
return 0;
}


// Set the font
context.mozTextStyle = '32px Arial';


// Specify a context and a rect that is safe to draw in when calling measureTextHeight
var height = measureTextHeight(context, 0, 0, 50, 50);
console.log(height);

对于 Bespin,他们通过测量小写‘ m’的宽度来伪造高度... ... 我不知道这是如何使用的,我也不会推荐这种方法。以下是相关的 Bespin 方法:

var fixCanvas = function(ctx) {
// upgrade Firefox 3.0.x text rendering to HTML 5 standard
if (!ctx.fillText && ctx.mozDrawText) {
ctx.fillText = function(textToDraw, x, y, maxWidth) {
ctx.translate(x, y);
ctx.mozTextStyle = ctx.font;
ctx.mozDrawText(textToDraw);
ctx.translate(-x, -y);
}
}


if (!ctx.measureText && ctx.mozMeasureText) {
ctx.measureText = function(text) {
ctx.mozTextStyle = ctx.font;
var width = ctx.mozMeasureText(text);
return { width: width };
}
}


if (ctx.measureText && !ctx.html5MeasureText) {
ctx.html5MeasureText = ctx.measureText;
ctx.measureText = function(text) {
var textMetrics = ctx.html5MeasureText(text);


// fake it 'til you make it
textMetrics.ascent = ctx.html5MeasureText("m").width;


return textMetrics;
}
}


// for other browsers
if (!ctx.fillText) {
ctx.fillText = function() {}
}


if (!ctx.measureText) {
ctx.measureText = function() { return 10; }
}
};

但是,设置字体大小可能并不实际,因为设置

Font =”

将使用 CSS 定义的字体以及任何嵌入式字体标记。如果使用 CSS 字体,那么您不知道编程方式下的高度是多少,而使用的是措施文本方法,这是非常短视的。不过另一方面,IE8确实返回了宽度和高度。

编辑: abc 0如果是这样,你必须跟踪变换矩阵。下面的方法应该使用初始转换度量文本的高度。

编辑 # 2: 奇怪的是,当我在这个 StackOverflow 页面上运行下面的代码时,它不会产生正确的答案; 一些样式规则的存在完全有可能破坏这个函数。

画布使用 CSS 定义的字体,所以理论上我们只需要向文档添加一个适当样式的文本块并测量它的高度。我认为这比渲染文本然后检查像素数据要容易得多,而且它还应该尊重上升和下降。你可在此查阅以下资料:

var determineFontHeight = function(fontStyle) {
var body = document.getElementsByTagName("body")[0];
var dummy = document.createElement("div");
var dummyText = document.createTextNode("M");
dummy.appendChild(dummyText);
dummy.setAttribute("style", fontStyle);
body.appendChild(dummy);
var result = dummy.offsetHeight;
body.removeChild(dummy);
return result;
};


//A little test...
var exampleFamilies = ["Helvetica", "Verdana", "Times New Roman", "Courier New"];
var exampleSizes = [8, 10, 12, 16, 24, 36, 48, 96];
for(var i = 0; i < exampleFamilies.length; i++) {
var family = exampleFamilies[i];
for(var j = 0; j < exampleSizes.length; j++) {
var size = exampleSizes[j] + "pt";
var style = "font-family: " + family + "; font-size: " + size + ";";
var pixelHeight = determineFontHeight(style);
console.log(family + " " + size + " ==> " + pixelHeight + " pixels high.");
}
}

您必须确保在测量高度的 DOM 元素上获得正确的字体样式,但这非常简单; 实际上您应该使用

var canvas = /* ... */
var context = canvas.getContext("2d");
var canvasFont = " ... ";
var fontHeight = determineFontHeight("font: " + canvasFont + ";");
context.font = canvasFont;
/*
do your stuff with your font and its height here.
*/

我正在写一个虚拟终端,所以我需要在字符周围画矩形。

var size = 10
var lineHeight = 1.2 // CSS "line-height: normal" is between 1 and 1.2
context.font = size+'px/'+lineHeight+'em monospace'
width = context.measureText('m').width
height = size * lineHeight

很明显,如果你想要角色占用的确切空间,这是没有帮助的。但对于某些用途,它会给你一个很好的近似值。

UPDATE -作为这种工作的一个示例,我在 Carota 编辑中使用了这种技术。

接下来是 ellisbben 的回答,这里是一个增强版本,可以从基线获得上升和下降,也就是说,与 Win32的 GetTextMetric API 返回的 tmAscenttmDescent相同。如果您希望使用不同字体/大小的 span 进行文本的单词包装运行,则需要这样做。

Big Text on canvas with metric lines

上面的图像是在 Safari 中的一个画布上生成的,红色是画布被告知绘制文本的顶线,绿色是基线,蓝色是底部(所以红色到蓝色是整个高度)。

使用 jQuery 简洁:

var getTextHeight = function(font) {


var text = $('<span>Hg</span>').css({ fontFamily: font });
var block = $('<div style="display: inline-block; width: 1px; height: 0px;"></div>');


var div = $('<div></div>');
div.append(text, block);


var body = $('body');
body.append(div);


try {


var result = {};


block.css({ verticalAlign: 'baseline' });
result.ascent = block.offset().top - text.offset().top;


block.css({ verticalAlign: 'bottom' });
result.height = block.offset().top - text.offset().top;


result.descent = result.height - result.ascent;


} finally {
div.remove();
}


return result;
};

除了文本元素之外,我还用 display: inline-block添加了一个 div,这样我就可以设置它的 vertical-align样式,然后找出浏览器把它放在了哪里。

所以你得到一个包含 ascentdescentheight的对象(为了方便,只有 ascent + descent)。为了测试它,值得使用一个绘制水平线的函数:

var testLine = function(ctx, x, y, len, style) {
ctx.strokeStyle = style;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x + len, y);
ctx.closePath();
ctx.stroke();
};

然后你就可以看到文字在画布上相对于顶部、基线和底部的位置:

var font = '36pt Times';
var message = 'Big Text';


ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top'; // important!
ctx.font = font;
ctx.fillText(message, x, y);


// Canvas can tell us the width
var w = ctx.measureText(message).width;


// New function gets the other info we need
var h = getTextHeight(font);


testLine(ctx, x, y, w, 'red');
testLine(ctx, x, y + h.ascent, w, 'green');
testLine(ctx, x, y + h.height, w, 'blue');

正如 JJ 斯蒂夫建议的那样,您可以将文本添加到 span 中,然后测量 span 的偏移量高度。

var d = document.createElement("span");
d.font = "20px arial";
d.textContent = "Hello world!";
document.body.appendChild(d);
var emHeight = d.offsetHeight;
document.body.removeChild(d);

HTML5Rocks HTML5Rocks所示

如果使用 context.font 定义字体,那么以像素为单位的文本高度是否等于字体大小(单位: pt) ?

通过检查大写 M 的长度,你可以得到一个非常接近垂直高度的近似值。

ctx.font = 'bold 10px Arial';


lineHeight = ctx.measureText('M').width;

我直接用像素操作解决了这个问题。

以下是图解答案:

这是密码:

    function textHeight (text, font) {


var fontDraw = document.createElement("canvas");


var height = 100;
var width = 100;


// here we expect that font size will be less canvas geometry
fontDraw.setAttribute("height", height);
fontDraw.setAttribute("width", width);


var ctx = fontDraw.getContext('2d');
// black is default
ctx.fillRect(0, 0, width, height);
ctx.textBaseline = 'top';
ctx.fillStyle = 'white';
ctx.font = font;
ctx.fillText(text/*'Eg'*/, 0, 0);


var pixels = ctx.getImageData(0, 0, width, height).data;


// row numbers where we first find letter end where it ends
var start = -1;
var end = -1;


for (var row = 0; row < height; row++) {
for (var column = 0; column < width; column++) {


var index = (row * width + column) * 4;


// if pixel is not white (background color)
if (pixels[index] == 0) {
// we havent met white (font color) pixel
// on the row and the letters was detected
if (column == width - 1 && start != -1) {
end = row;
row = height;
break;
}
continue;
}
else {
// we find top of letter
if (start == -1) {
start = row;
}
// ..letters body
break;
}


}


}
/*
document.body.appendChild(fontDraw);
fontDraw.style.pixelLeft = 400;
fontDraw.style.pixelTop = 400;
fontDraw.style.position = "absolute";
*/


return end - start;


}

这是疯狂的... 文本的高度是字体大小. . 你们没有人读过文档吗?

context.font = "22px arial";

这将设置高度为22px。

唯一的原因就是。

context.measureText(string).width

是因为字符串的宽度无法确定,除非它知道您想要的字符串的宽度,但是对于使用该字体绘制的所有字符串。.高度为22px。

如果你使用另一个比 px 的测量值,那么高度仍然是相同的,但是使用这个测量值,所以你最多只需要转换测量值。

为了补充 Daniel 的回答(太棒了! 而且绝对正确!) ,没有 JQuery 的版本:

function objOff(obj)
{
var currleft = currtop = 0;
if( obj.offsetParent )
{ do { currleft += obj.offsetLeft; currtop += obj.offsetTop; }
while( obj = obj.offsetParent ); }
else { currleft += obj.offsetLeft; currtop += obj.offsetTop; }
return [currleft,currtop];
}
function FontMetric(fontName,fontSize)
{
var text = document.createElement("span");
text.style.fontFamily = fontName;
text.style.fontSize = fontSize + "px";
text.innerHTML = "ABCjgq|";
// if you will use some weird fonts, like handwriting or symbols, then you need to edit this test string for chars that will have most extreme accend/descend values


var block = document.createElement("div");
block.style.display = "inline-block";
block.style.width = "1px";
block.style.height = "0px";


var div = document.createElement("div");
div.appendChild(text);
div.appendChild(block);


// this test div must be visible otherwise offsetLeft/offsetTop will return 0
// but still let's try to avoid any potential glitches in various browsers
// by making it's height 0px, and overflow hidden
div.style.height = "0px";
div.style.overflow = "hidden";


// I tried without adding it to body - won't work. So we gotta do this one.
document.body.appendChild(div);


block.style.verticalAlign = "baseline";
var bp = objOff(block);
var tp = objOff(text);
var taccent = bp[1] - tp[1];
block.style.verticalAlign = "bottom";
bp = objOff(block);
tp = objOff(text);
var theight = bp[1] - tp[1];
var tdescent = theight - taccent;


// now take it off :-)
document.body.removeChild(div);


// return text accent, descent and total height
return [taccent,theight,tdescent];
}

我刚刚测试了上面的代码,在 Mac 上最新的 Chrome,FF 和 Safari 上运行得很好。

编辑: 我也添加了字体大小,并用 webfont 代替 system font 进行了测试——非常棒。

在正常情况下,以下措施应该奏效:

var can = CanvasElement.getContext('2d');          //get context
var lineHeight = /[0-9]+(?=pt|px)/.exec(can.font); //get height from font variable

我已经实现了一个很好的库,可以使用 HTML 画布精确测量文本的高度和宽度。这应该是你想要的。

Https://github.com/chrisbellew/text-measurer.js

这里有一个简单的函数,不需要库。

我编写这个函数是为了得到相对于基线的顶部和底部界限。如果 textBaseline设置为 alphabetic。它所做的是创建另一个画布,然后在那里绘制,然后找到顶部和底部最不空白的像素。这是上下界。它将它作为相对值返回,因此如果高度为20px,并且没有低于基线的值,那么上限就是 -20

您必须为它提供字符。否则,它显然会给您0高度和0宽度。

用法:

alert(measureHeight('40px serif', 40, 'rg').height)

函数如下:

function measureHeight(aFont, aSize, aChars, aOptions={}) {
// if you do pass aOptions.ctx, keep in mind that the ctx properties will be changed and not set back. so you should have a devoted canvas for this
// if you dont pass in a width to aOptions, it will return it to you in the return object
// the returned width is Math.ceil'ed
console.error('aChars: "' + aChars + '"');
var defaultOptions = {
width: undefined, // if you specify a width then i wont have to use measureText to get the width
canAndCtx: undefined, // set it to object {can:,ctx:} // if not provided, i will make one
range: 3
};


aOptions.range = aOptions.range || 3; // multiples the aSize by this much


if (aChars === '') {
// no characters, so obviously everything is 0
return {
relativeBot: 0,
relativeTop: 0,
height: 0,
width: 0
};
// otherwise i will get IndexSizeError: Index or size is negative or greater than the allowed amount error somewhere below
}


// validateOptionsObj(aOptions, defaultOptions); // not needed because all defaults are undefined


var can;
var ctx;
if (!aOptions.canAndCtx) {
can = document.createElement('canvas');;
can.mozOpaque = 'true'; // improved performanceo on firefox i guess
ctx = can.getContext('2d');


// can.style.position = 'absolute';
// can.style.zIndex = 10000;
// can.style.left = 0;
// can.style.top = 0;
// document.body.appendChild(can);
} else {
can = aOptions.canAndCtx.can;
ctx = aOptions.canAndCtx.ctx;
}


var w = aOptions.width;
if (!w) {
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';
ctx.font = aFont;
w = ctx.measureText(aChars).width;
}


w = Math.ceil(w); // needed as i use w in the calc for the loop, it needs to be a whole number


// must set width/height, as it wont paint outside of the bounds
can.width = w;
can.height = aSize * aOptions.range;


ctx.font = aFont; // need to set the .font again, because after changing width/height it makes it forget for some reason
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';


ctx.fillStyle = 'white';


console.log('w:', w);


var avgOfRange = (aOptions.range + 1) / 2;
var yBaseline = Math.ceil(aSize * avgOfRange);
console.log('yBaseline:', yBaseline);


ctx.fillText(aChars, 0, yBaseline);


var yEnd = aSize * aOptions.range;


var data = ctx.getImageData(0, 0, w, yEnd).data;
// console.log('data:', data)


var botBound = -1;
var topBound = -1;


// measureHeightY:
for (y=0; y<=yEnd; y++) {
for (var x = 0; x < w; x += 1) {
var n = 4 * (w * y + x);
var r = data[n];
var g = data[n + 1];
var b = data[n + 2];
// var a = data[n + 3];


if (r+g+b > 0) { // non black px found
if (topBound == -1) {
topBound = y;
}
botBound = y; // break measureHeightY; // dont break measureHeightY ever, keep going, we till yEnd. so we get proper height for strings like "`." or ":" or "!"
break;
}
}
}


return {
relativeBot: botBound - yBaseline, // relative to baseline of 0 // bottom most row having non-black
relativeTop: topBound - yBaseline, // relative to baseline of 0 // top most row having non-black
height: (botBound - topBound) + 1,
width: w// EDIT: comma has been added to fix old broken code.
};
}

relativeBotrelativeTopheight是返回对象中的有用内容。

下面是一些例子:

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
function measureHeight(aFont, aSize, aChars, aOptions={}) {
// if you do pass aOptions.ctx, keep in mind that the ctx properties will be changed and not set back. so you should have a devoted canvas for this
// if you dont pass in a width to aOptions, it will return it to you in the return object
// the returned width is Math.ceil'ed
console.error('aChars: "' + aChars + '"');
var defaultOptions = {
width: undefined, // if you specify a width then i wont have to use measureText to get the width
canAndCtx: undefined, // set it to object {can:,ctx:} // if not provided, i will make one
range: 3
};
	

aOptions.range = aOptions.range || 3; // multiples the aSize by this much
	

if (aChars === '') {
// no characters, so obviously everything is 0
return {
relativeBot: 0,
relativeTop: 0,
height: 0,
width: 0
};
// otherwise i will get IndexSizeError: Index or size is negative or greater than the allowed amount error somewhere below
}
	

// validateOptionsObj(aOptions, defaultOptions); // not needed because all defaults are undefined
	

var can;
var ctx;
if (!aOptions.canAndCtx) {
can = document.createElement('canvas');;
can.mozOpaque = 'true'; // improved performanceo on firefox i guess
ctx = can.getContext('2d');
		

// can.style.position = 'absolute';
// can.style.zIndex = 10000;
// can.style.left = 0;
// can.style.top = 0;
// document.body.appendChild(can);
} else {
can = aOptions.canAndCtx.can;
ctx = aOptions.canAndCtx.ctx;
}
	

var w = aOptions.width;
if (!w) {
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';
ctx.font = aFont;
w = ctx.measureText(aChars).width;
}
	

w = Math.ceil(w); // needed as i use w in the calc for the loop, it needs to be a whole number
	

// must set width/height, as it wont paint outside of the bounds
can.width = w;
can.height = aSize * aOptions.range;
	

ctx.font = aFont; // need to set the .font again, because after changing width/height it makes it forget for some reason
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';
	

ctx.fillStyle = 'white';
	

console.log('w:', w);
	

var avgOfRange = (aOptions.range + 1) / 2;
var yBaseline = Math.ceil(aSize * avgOfRange);
console.log('yBaseline:', yBaseline);
	

ctx.fillText(aChars, 0, yBaseline);
	

var yEnd = aSize * aOptions.range;
	

var data = ctx.getImageData(0, 0, w, yEnd).data;
// console.log('data:', data)
	

var botBound = -1;
var topBound = -1;
	

// measureHeightY:
for (y=0; y<=yEnd; y++) {
for (var x = 0; x < w; x += 1) {
var n = 4 * (w * y + x);
var r = data[n];
var g = data[n + 1];
var b = data[n + 2];
// var a = data[n + 3];
			

if (r+g+b > 0) { // non black px found
if (topBound == -1) {
topBound = y;
}
botBound = y; // break measureHeightY; // dont break measureHeightY ever, keep going, we till yEnd. so we get proper height for strings like "`." or ":" or "!"
break;
}
}
}
	

return {
relativeBot: botBound - yBaseline, // relative to baseline of 0 // bottom most row having non-black
relativeTop: topBound - yBaseline, // relative to baseline of 0 // top most row having non-black
height: (botBound - topBound) + 1,
width: w
};
}


</script>
</head>
<body style="background-color:steelblue;">
<input type="button" value="reuse can" onClick="alert(measureHeight('40px serif', 40, 'rg', {canAndCtx:{can:document.getElementById('can'), ctx:document.getElementById('can').getContext('2d')}}).height)">
<input type="button" value="dont reuse can" onClick="alert(measureHeight('40px serif', 40, 'rg').height)">
<canvas id="can"></canvas>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>

relativeBotrelativeTop就是你在这张图中看到的:

Https://developer.mozilla.org/en-us/docs/web/api/canvas_api/tutorial/drawing_text

浏览器开始支持 高级文本度量,当它得到广泛支持时,这个任务就变得微不足道了:

let metrics = ctx.measureText(text);
let fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

无论呈现的字符串是什么,fontHeight都会为您提供常量的边框高度。actualHeight特定于正在呈现的字符串。

规格: https://www.w3.org/TR/2012/CR-2dcontext-20121217/#dom-textmetrics-fontboundingboxascent及其下面的部分。

支援情况(2017年8月20日) :

一行答案

var height = parseInt(ctx.font) * 1.2;

CSS“ line-height: Normal”介于1和1.2之间

阅读 给你了解更多信息

我发现,只是为了 ARIAL最简单,最快,最准确的方法,找到高度的边界框是使用某些字母的宽度。如果您计划使用某种字体而不让用户选择其中一种不同的字体,您可以做一点研究,找到正确的字母,做该字体的工作。

<!DOCTYPE html>
<html>
<body>


<canvas id="myCanvas" width="700" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>


<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "100px Arial";
var txt = "Hello guys!"
var Hsup=ctx.measureText("H").width;
var Hbox=ctx.measureText("W").width;
var W=ctx.measureText(txt).width;
var W2=ctx.measureText(txt.substr(0, 9)).width;


ctx.fillText(txt, 10, 100);
ctx.rect(10,100, W, -Hsup);
ctx.rect(10,100+Hbox-Hsup, W2, -Hbox);
ctx.stroke();
</script>


<p><strong>Note:</strong> The canvas tag is not supported in Internet
Explorer 8 and earlier versions.</p>


</body>
</html>

近似解:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "100px Arial";
var txt = "Hello guys!"
var wt = ctx.measureText(txt).width;
var height = wt / txt.length;

这将是准确的结果在等宽字体。

这是我根据其他一些答案所做的:

function measureText(text, font) {
const span = document.createElement('span');
span.appendChild(document.createTextNode(text));
Object.assign(span.style, {
font: font,
margin: '0',
padding: '0',
border: '0',
whiteSpace: 'nowrap'
});
document.body.appendChild(span);
const {width, height} = span.getBoundingClientRect();
span.remove();
return {width, height};
}


var font = "italic 100px Georgia";
var text = "abc this is a test";
console.log(measureText(text, font));

这对1)多行文本和2) ,甚至在 IE9!

<div class="measureText" id="measureText">
</div>




.measureText {
margin: 0;
padding: 0;
border: 0;
font-family: Arial;
position: fixed;
visibility: hidden;
height: auto;
width: auto;
white-space: pre-wrap;
line-height: 100%;
}


function getTextFieldMeasure(fontSize, value) {
const div = document.getElementById("measureText");


// returns wrong result for multiline text with last line empty
let arr = value.split('\n');
if (arr[arr.length-1].length == 0) {
value += '.';
}


div.innerText = value;
div.style['font-size']= fontSize + "px";
let rect = div.getBoundingClientRect();


return {width: rect.width, height: rect.height};
};

我知道这是一个老的回答问题,但为了将来的参考,我想添加一个简短的,最小的,JS-only (没有 jquery)解决方案,我相信人们可以从中受益:

var measureTextHeight = function(fontFamily, fontSize)
{
var text = document.createElement('span');
text.style.fontFamily = fontFamily;
text.style.fontSize = fontSize + "px";
text.textContent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
document.body.appendChild(text);
var result = text.getBoundingClientRect().height;
document.body.removeChild(text);
return result;
};

我在我的一个项目中修补了 CanvasRenderingContext2D.mesureText () ,以包含文本的实际高度。它是用普通的 JS 编写的,没有任何依赖关系。

/*
* Monkeypatch CanvasRenderingContext2D.measureText() to include actual height of the text
*/
; (function (global) {
"use strict";


var _measureText = global.CanvasRenderingContext2D.prototype.measureText;


global.CanvasRenderingContext2D.prototype.measureText = function () {
var textMetrics = _measureText.apply(this, arguments);


var _getHeight = function (text) {
var $span = global.document.createElement("span");
var spanTextNode = global.document.createTextNode(text);
$span.appendChild(spanTextNode);
$span.setAttribute("style", `font: ${this.font}`);


var $div = global.document.createElement("div");
$div.setAttribute("style", "display: inline-block; width: 1px; height: 0; vertical-align: super;");


var $parentDiv = global.document.createElement("div");
$parentDiv.appendChild($span);
$parentDiv.appendChild($div);


var $body = global.document.getElementsByTagName("body")[0];
$body.appendChild($parentDiv);


var divRect = $div.getBoundingClientRect();
var spanRect = $span.getBoundingClientRect();
var result = {};


$div.style.verticalAlign = "baseline";
result.ascent = divRect.top - spanRect.top;


$div.style.verticalAlign = "bottom";
result.height = divRect.top - spanRect.top;


result.descent = result.height - result.ascent;


$body.removeChild($parentDiv);


return result.height - result.descent;
}.bind(this);


var height = _getHeight(arguments[0]);


global.Object.defineProperty(textMetrics, "height", { value: height });


return textMetrics;
};


})(window);

你可以像这样使用它

ctx.font = "bold 64px Verdana, sans-serif"; // Automatically considers it as part of height calculation
var textMetrics = ctx.measureText("Foobar");
var textHeight = textMetrics.height;

parseInt(ctx.font, 10)

例如:。

let text_height = parseInt(ctx.font, 10)

例如: 申报表35

没有正确答案让我有点吃惊。没有必要做估计或猜测。此外,字体大小不是字体边框的实际大小。字体高度取决于是否有升序和降序。

要计算它,使用 ctx.measureText()并将 actualBoundingBoxAscentactualBoundingBoxDescent相加。这样你就知道实际尺寸了。您还可以将 font*版本加在一起,以获得用于计算元素高度等内容的大小,但严格来说,这并不是字体实际使用空间的高度。

const text = 'Hello World';
const canvas = document.querySelector('canvas');
canvas.width = 500;
canvas.height = 200;


const ctx = canvas.getContext('2d');
const fontSize = 100;


ctx.font = `${fontSize}px Arial, Helvetica, sans-serif`;
// top is critical to the fillText() calculation
// you can use other positions, but you need to adjust the calculation
ctx.textBaseline = 'top';
ctx.textAlign = 'center';


const metrics = ctx.measureText(text);
const width = metrics.width;
const actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
// fallback to using fontSize if fontBoundingBoxAscent isn't available, like in Firefox. Should be close enough that you aren't more than a pixel off in most cases.
const fontHeight = (metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent) ?? fontSize;


ctx.fillStyle = '#00F'; // blue
ctx.fillRect((canvas.width / 2) - (width / 2), (canvas.height / 2) - (fontHeight / 2), width, fontHeight);


ctx.fillStyle = '#0F0'; // green
ctx.fillRect((canvas.width / 2) - (width / 2), (canvas.height / 2) - (actualHeight / 2), width, actualHeight);


// canvas.height / 2 - actualHeight / 2 gets you to the top of
// the green box. You have to add actualBoundingBoxAscent to shift
//  it just right
ctx.fillStyle = '#F00'; // red
ctx.fillText(text, canvas.width / 2, canvas.height / 2 - actualHeight / 2 + metrics.actualBoundingBoxAscent);
<canvas></canvas>