javascript 大小以适合画布上的字体

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20551534/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 18:46:17  来源:igfitidea点击:

Size to fit font on a canvas

javascriptjqueryhtmlcsshtml5-canvas

提问by Arian Faurtosh

I currently have this http://jsfiddle.net/dgAEY/which works perfectly, I just need to figure out a way to size the font when it gets too long. I've looked into Auto-size dynamic text to fill fixed size containerand I've tried to apply the Jquery function they posted but I couldn't get it to work.

我目前有这个http://jsfiddle.net/dgAEY/,它工作得很好,我只需要想办法在字体太长时调整字体大小。我已经研究了自动调整大小的动态文本以填充固定大小的容器,并且我尝试应用他们发布的 Jquery 函数,但我无法让它工作。

HTML

HTML

<form action="" method="POST" id="nametag" class="nametag">
    Line1: 
    <input type="text" id="line1" name="line1" style="width:250px;" /><br>
    Line2:
    <input type="text" id="line2" name="line2" style="width:250px;" /><br>
    Line3:
    <input type="text" id="line3" name="line3" style="width:250px;" /><br>
    Line4:
    <input type="text" id="line4" name="line4" style="width:250px;" /><br>

    <br><br><b>Name Tag</b><br>
    <canvas width="282px" height="177px" id="myCanvas" style="border: black thin solid;"></canvas>
</form>

JavaScript

JavaScript

$(document).ready(function () {
    var canvas = $('#myCanvas')[0];
    var context = canvas.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
        context.drawImage(imageObj, 0, 0);
    };
    imageObj.src = "http://dummyimage.com/282x177/FFF/FFF"; 

    $('#nametag').bind('change keyup input', updateCanvas);
    $('#line2').bind('click', updateCanvas);
    $('#line3').bind('click', updateCanvas);
    $('#line4').bind('click', updateCanvas);

    function updateCanvas() {

        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(imageObj, 0, 0);
        context.textAlign = "center";

        context.font = "bold 18pt Arial";
        context.fillText($('#line1').val(), canvas.width * 0.5, 70);

        context.font = "12pt Arial";
        context.fillText($('#line2').val(), canvas.width * 0.5, 90);
        context.fillText($('#line3').val(), canvas.width * 0.5, 120);
        context.fillText($('#line4').val(), canvas.width * 0.5, 140);

    }
});

回答by markE

You can use context.measureText to get the pixel width of any given text in the current font.

您可以使用 context.measureText 获取当前字体中任何给定文本的像素宽度。

Then if that width is too big, reduce the font size until it fits.

然后,如果该宽度太大,请减小字体大小,直到适合为止。

context.font="14px verdana";

var width = context.measureText("Hello...Do I fit on the canvas?").width

if(width>myDesiredWidth)  // then reduce the font size and re-measure

[ Addition: a code example ]

[附加:代码示例]

Demo: http://jsfiddle.net/m1erickson/yL5jL/

演示:http: //jsfiddle.net/m1erickson/yL5jL/

Here's an example of a do-while loop that finds the font size that fits your text to canvas width:

下面是一个 do-while 循环的例子,它找到适合你的文本到画布宽度的字体大小:

var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");

fitTextOnCanvas("Hello, World!","verdana",125);


function fitTextOnCanvas(text,fontface,yPosition){    

    // start with a large font size
    var fontsize=300;

    // lower the font size until the text fits the canvas
    do{
        fontsize--;
        context.font=fontsize+"px "+fontface;
    }while(context.measureText(text).width>canvas.width)

    // draw the text
    context.fillText(text,0,yPosition);

    alert("A fontsize of "+fontsize+"px fits this text on the canvas");

}

回答by daker

Add the maxWidthParameter to your context.textfill

maxWidth参数添加到您的 context.textfill

$(document).ready(function () {
    var canvas = $('#myCanvas')[0];
    var context = canvas.getContext('2d');

    var imageObj = new Image();
    imageObj.onload = function() {
        context.drawImage(imageObj, 0, 0);
    };
    imageObj.src = "http://dummyimage.com/282x177/FFF/FFF"; 

    $('#nametag').bind('change keyup input', updateCanvas);
    $('#line2').bind('click', updateCanvas);
    $('#line3').bind('click', updateCanvas);
    $('#line4').bind('click', updateCanvas);

    function updateCanvas() {
        var maxWith = canvas.width;

        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(imageObj, 0, 0);
        context.textAlign = "center";

        context.font = "bold 18pt Arial";
        context.fillText($('#line1').val(), canvas.width * 0.5, 70, maxWith);

        context.font = "12pt Arial";
        context.fillText($('#line2').val(), canvas.width * 0.5, 90, maxWith);
        context.fillText($('#line3').val(), canvas.width * 0.5, 120, maxWith);
        context.fillText($('#line4').val(), canvas.width * 0.5, 140, maxWith);

    }
});

回答by Vibber

I have created an improved version of markE's code. It becomes apparent that his code is slower if you have multiple texts. The browsers are good at caching but on the first run you can definitely get a noticeable lag even with just a handful of lines that need scaling.

我创建了 markE 代码的改进版本。如果您有多个文本,很明显他的代码会变慢。浏览器擅长缓存,但在第一次运行时,即使只有少数几行需要缩放,你也肯定会出现明显的延迟。

Try these two versions:

试试这两个版本:

Original method (markE):

原始方法(markE):

http://jsfiddle.net/be6ppdre/29/

http://jsfiddle.net/be6ppdre/29/

Faster method:

更快的方法:

http://jsfiddle.net/ho9thkvo/2/

http://jsfiddle.net/ho9thkvo/2/

The main code is here:

主要代码在这里:

function fitTextOnCanvas(text, fontface){    
    var size = measureTextBinaryMethod(text, fontface, 0, 600, canvas.width);
    return size;
}

function measureTextBinaryMethod(text, fontface, min, max, desiredWidth) {
    if (max-min < 1) {
        return min;     
    }
    var test = min+((max-min)/2); //Find half interval
    context.font=test+"px "+fontface;
    measureTest = context.measureText(text).width;
    if ( measureTest > desiredWidth) {
        var found = measureTextBinaryMethod(text, fontface, min, test, desiredWidth)
    } else {
        var found = measureTextBinaryMethod(text, fontface, test, max, desiredWidth)
    }
    return found;
}

回答by rob

this will only apply to a small set of circumstances but if provided a perfect answer to the problem for me. The last [optional] parameter to fillTextis maxWidth, so

这仅适用于一小部分情况,但如果为我提供了问题的完美答案。fillText的最后一个 [可选] 参数是maxWidth,所以

ctx.fillText('long text', x, y, maxWidth);

Will render 'long text' at x,ysquashing the result to maxWidth.

将在x处呈现“长文本” ,y将结果压缩maxWidth

For really long text this produces absolutely awful results but for the odd string that was just exceeding your maxWidthit can be a very simple god-send.

对于非常长的文本,这会产生非常糟糕的结果,但对于刚刚超过maxWidth的奇怪字符串,这可能是一个非常简单的天赐之物。

回答by Veetaha

Simple and efficient solution for DOM environment, no loops, just do one sample measurement and scale the result appropriately.

DOM环境简单高效的解决方案,无循环,只需做一个样本测量并适当缩放结果。

function getFontSizeToFit(text: string, fontFace: string, maxWidth: number) {
    const ctx = document.createElement('canvas').getContext('2d');
    ctx.font = `1px ${fontFace}`;
    return maxWidth / ctx.measureText(text).width;
}

Beware that if you use npm 'canvas'module for NodeJs environment, the result won't be that accurate as they use some custom C++ implementation that returns only integer sample width.

请注意,如果您在 NodeJs 环境中使用 npm 'canvas'模块,结果将不会那么准确,因为它们使用一些仅返回整数样本宽度的自定义 C++ 实现。