大小适合画布上的字体

时间:2013-12-12 18:38:20

标签: javascript jquery html css canvas

我目前有 http://jsfiddle.net/dgAEY/ 这完美无缺,我只需要找出一种方法来在字体太长时调整字体大小。我查看了Auto-size dynamic text to fill fixed size container,我试图应用他们发布的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>

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

    }
});

5 个答案:

答案 0 :(得分: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

[添加:代码示例]

演示: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");

}

答案 1 :(得分:5)

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

试试这两个版本:

原始方法(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;
}

答案 2 :(得分:4)

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

    }
});

答案 3 :(得分:2)

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

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

将在 x y 处渲染“长文本”,将结果压缩为 maxWidth

对于非常长的文本,这会产生非常糟糕的结果,但对于超出 maxWidth 的奇数字符串,它可以是一个非常简单的上帝发送。

答案 4 :(得分:1)

针对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;
}

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