大小适合画布上的字体

Ari*_*osh 5 html javascript css jquery html5-canvas

我目前有这个http://jsfiddle.net/dgAEY/,它工作得很好,我只需要找出一种方法来确定字体长度太长时的大小.我已经研究了自动大小的动态文本来填充固定大小的容器,我试图应用他们发布的Jquery函数,但我无法让它工作.

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>
Run Code Online (Sandbox Code Playgroud)

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

    }
});
Run Code Online (Sandbox Code Playgroud)

mar*_*rkE 15

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

然后,如果宽度太大,请缩小字体大小,直到它适合.

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
Run Code Online (Sandbox Code Playgroud)

[补充:代码示例]

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

这是一个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");

}
Run Code Online (Sandbox Code Playgroud)

  • 它应该是:context.font = fontsize +"px"+ fontface; (你忘记了"px").没有它,它就不起作用.否则,它的工作原理.谢谢你的代码. (5认同)
  • 我建议使用二进制搜索循环而不是线性搜索,因此对于最大字体大小 = 1024px,只需最多 10 次迭代即可获得 1px 精度的适合大小(而不是小测试区域的 ~1000)。 (2认同)

Vee*_*aha 13

针对 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;
}
Run Code Online (Sandbox Code Playgroud)

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


dak*_*ker 5

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

    }
});
Run Code Online (Sandbox Code Playgroud)

  • 这样做只会在达到最大宽度后将文本挤压在一起,这实际上并不会缩小文本大小:http://jsfiddle.net/dgAEY/2/ (2认同)

小智 5

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

试试这两个版本:

原始方法(markE):

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

更快的方法:

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

主要代码在这里:

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;
}
Run Code Online (Sandbox Code Playgroud)