javascript 确定 HTML5 画布中字符串的宽度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10099226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determine width of string in HTML5 canvas
提问by edc1591
I'm drawing text in an HTML5 canvas on top of an image (a meme generator). I want to calculate a font size so that the string will span the entire width of the canvas.
我在图像(模因生成器)顶部的 HTML5 画布中绘制文本。我想计算字体大小,以便字符串跨越画布的整个宽度。
So basically, is there a way in JavaScript to determine what font size I should use for some string of a certain font for a given width?
所以基本上,JavaScript 中有没有一种方法可以确定对于给定宽度的某种字体的某些字符串应该使用什么字体大小?
回答by alex
The fillText()
method has an optional fourth argument, which is the max widthto render the string.
该fillText()
方法有一个可选的第四个参数,它是呈现字符串的最大宽度。
MDN's documentation says...
MDN 的文档说...
maxWidth
Optional; the maximum width to draw. If specified, and the string is computed to be wider than this width, the font is adjusted to use a more horizontally condensed font (if one is available or if a reasonably readable one can be synthesized by scaling the current font horizontally) or a smaller font.
最大宽度
选修的; 要绘制的最大宽度。如果指定,并且计算出的字符串比此宽度更宽,则字体将调整为使用更水平压缩的字体(如果可用,或者如果可以通过水平缩放当前字体合成合理可读的字体)或更小字体。
However, at the time of writing, this argument isn't supported well cross browser, which leads to the second solution using measureText()
to determine the dimensions of a string without rendering it.
但是,在撰写本文时,该参数在跨浏览器中并没有得到很好的支持,这导致了第二种解决方案measureText()
,用于在不呈现字符串的情况下确定字符串的尺寸。
var width = ctx.measureText(text).width;
Here is how I may do it...
这是我可以做到的...
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Font sizes must be in descending order. You may need to use `sort()`
// if you can't guarantee this, e.g. user input.
var fontSizes = [72, 36, 28, 14, 12, 10, 5, 2],
text = 'Measure me!';
// Default styles.
ctx.textBaseline = 'top';
ctx.fillStyle = 'blue';
var textDimensions,
i = 0;
do {
ctx.font = fontSizes[i++] + 'px Arial';
textDimensions = ctx.measureText(text);
} while (textDimensions.width >= canvas.width);
ctx.fillText(text, (canvas.width - textDimensions.width) / 2, 10);?
I have a list of font sizes in descending order and I iterate through the list, determining if the rendered text will fit within the canvas dimensions.
我有一个按降序排列的字体大小列表,我遍历列表,确定渲染的文本是否适合画布尺寸。
If it will, I render the text center aligned. If you must have padding on the left and right of the text (which will look nicer), add the padding value to the textDimensions.width
when calculating if the text will fit.
如果可以,我将文本居中对齐。如果您必须在文本的左侧和右侧进行填充(这样看起来会更好),请textDimensions.width
在计算文本是否适合时将填充值添加到。
If you have a long list of font sizes to try, you'd be better off using a binary search algorithm. This will increase the complexity of your code, however.
如果您要尝试的字体大小列表很长,最好使用二分搜索算法。但是,这会增加代码的复杂性。
For example, if you have 200 font sizes, the linear O(n) iteration through the array elements could be quite slow.
例如,如果您有 200 种字体大小,则数组元素的线性 O(n) 迭代可能会非常慢。
The binary chop should be O(log n).
二进制斩波应该是 O(log n)。
Here is the gutsof the function.
这里是胆的功能。
var textWidth = (function me(fontSizes, min, max) {
var index = Math.floor((min + max) / 2);
ctx.font = fontSizes[index] + 'px Arial';
var textWidth = ctx.measureText(text).width;
if (min > max) {
return textWidth;
}
if (textWidth > canvas.width) {
return me(fontSizes, min, index - 1);
} else {
return me(fontSizes, index + 1, max);
}
})(fontSizes, 0, fontSizes.length - 1);
回答by ccsakuweb
I have the next code and it works perfectly for me. Maybe there is a little error but I don't need to have a list of font sizes. I just get the width with a font size and if it is too big I calculate a proportional size depending of the canvas width and padding (50)
我有下一个代码,它非常适合我。也许有一点错误,但我不需要有字体大小列表。我只是用字体大小来获取宽度,如果它太大,我会根据画布宽度和填充来计算比例大小(50)
ctx.font = FONT_SIZE+"pt Verdana";
var textWidth = ctx.measureText(markText).width;
if(textWidth > canvas.width - 50) {
ctx.font = parseInt(FONT_SIZE*(canvas.width-50)/textWidth)+"pt Verdana";
textWidth = ctx.measureText(markText).width;
}
ctx.textBaseline = "middle";
ctx.fillStyle = "rgba(255,255,255,0.5)";
ctx.strokeStyle = "rgba(0,0,0,0.5)";
var xT = image.width / 2 - textWidth / 2;
var yT = image.height / 2;
ctx.fillText(markText, xT, yT);
ctx.strokeText(markText, xT, yT);