确定HTML5画布中的字符串宽度

时间:2012-04-11 02:59:12

标签: javascript html5 text canvas fonts

我在图像顶部的HTML5画布上绘制文本(模因生成器)。我想计算字体大小,以便字符串将跨越画布的整个宽度。

基本上,在JavaScript中是否有一种方法可以确定给定宽度的某些字符串应使用的字体大小?

3 个答案:

答案 0 :(得分:27)

fillText()方法有一个可选的第四个参数,即用于呈现字符串的 max width

MDN的文档说......

  

<强> maxWidth

     

可选;绘制的最大宽度。如果指定,则字符串为   如果计算得比这个宽度宽,则调整字体以使用a   更加水平压缩的字体(如果有一个可用或如果一个   合理可读的可以通过缩放当前字体来合成   水平的)或较小的字体。

然而,在撰写本文时,跨浏览器不支持此参数,这导致第二个解决方案使用measureText()来确定字符串的尺寸而不渲染它。

var width = ctx.measureText(text).width;

我可以这样做......

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);​

jsFiddle

我有一个按降序排列的字体大小列表,我遍历列表,确定渲染的文本是否适合画布尺寸。

如果可以,我将文本中心对齐。如果你必须在文本的左侧和右侧有填充(看起来更好),在计算文本是否合适时,将填充值添加到textDimensions.width

如果您要使用很长的字体大小列表,最好使用binary search algorithm。但是,这会增加代码的复杂性。

例如,如果您有200个字体大小,则通过数组元素的线性迭代将为O(n)。

二进制印章应为O(log n)。

这是函数的 guts

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);

jsFiddle

答案 1 :(得分:1)

  1. 为文本写下您想要的所有内容。 (例如ctx.font

  2. 在编写实际文本之前使用ctx.measureText("myText").width来获取文本的宽度,因为我们在ctx上进行了更改后调用了它,因此每次更改ctx属性(例如字体)时都会有所不同< /p>

  3. 现在我们将从中间扩展。

     ctx.translate(midPoint_X_Of_Text, midPoint_Y_Of_Text);
     ctx.scale(desiredWidth/measuredWidth, desiredWidth/measuredWidth);
     ctx.translate(-midPoint_X_Of_Text, -midPoint_Y_Of_Text);
    
  4. 写入文本 ctx.fillText()ctx.strokeText()

  5. 通过 ctx.save()ctx.restore() 或手动像 setTransform() 一样撤销所有更改

var can = document.getElementById('myCan');
var ctx = can.getContext("2d");

var desiredWidth = can.width;
var myText = "Hello How Are You?"

function draw(){
  ctx.font = can.height/2 + "px verdana";
  ctx.fillStyle = "red";
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  let measuredWidth = ctx.measureText(myText).width;
  let ratio = desiredWidth/measuredWidth;
  ctx.translate(can.width/2,can.height/2);
  ctx.scale(ratio,ratio);
  ctx.translate(-can.width/2,-can.height/2);
  ctx.fillText(myText,can.width/2,can.height/2);
  ctx.setTransform();
}

draw();

let myInput = document.getElementById('myInput');
myInput.addEventListener('input',(e)=>{
    ctx.clearRect(0,0,can.width,can.height);
        myText = myInput.value;
        draw();
})
<html>
<body>
  <center>
    <input id="myInput" value="Hello How Are You?"/><br>
    <canvas id="myCan" height="300" width=300 style="border:black solid 2px;">
    </canvas>
  </center>
</body>
</html>

答案 2 :(得分:0)

我有下一个代码,它对我来说很完美。也许有一点错误,但我不需要有一个字体大小列表。我只是得到字体大小的宽度,如果它太大我根据画布宽度和填充计算比例大小(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);