Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Size to fit font on a canvas

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 container and I've tried to apply the Jquery function they posted but I couldn't get it to work.

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

    }
});
like image 583
Arian Faurtosh Avatar asked Dec 12 '13 18:12

Arian Faurtosh


1 Answers

Base on @Veetaha answer, here is my function to fit multiple lines of center text

function getFontSizeToFit(ctx, text, fontFace, width, height) {
    ctx.font = `1px ${fontFace}`;
    
    let fitFontWidth = Number.MAX_VALUE
    const lines = text.match(/[^\r\n]+/g);
    lines.forEach(line => {
        fitFontWidth = Math.min(fitFontWidth, width / ctx.measureText(line).width)
    })
    let fitFontHeight = height / (lines.length * 1.2); // if you want more spacing between line, you can increase this value
    return Math.min(fitFontHeight, fitFontWidth)
}

Demo

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

let text = "Hello World \n Hello World 2222 \n AAAAA \n BBBB"

fitTextCenter()
function fitTextCenter() {
    let fontSize = getFontSizeToFit(ctx, text, "Arial", c.width, c.height)
    ctx.font = fontSize + "px Arial"

    fillTextCenter(ctx, text, 0, 0, c.width, c.height)
}

function fillTextCenter(ctx, text, x, y, width, height) {
    ctx.textBaseline = 'middle';
    ctx.textAlign = "center";

    const lines = text.match(/[^\r\n]+/g);
    for (let i = 0; i < lines.length; i++) {
        let xL = (width - x) / 2
        let yL = y + (height / (lines.length + 1)) * (i + 1)

        ctx.fillText(lines[i], xL, yL)
    }
}

function getFontSizeToFit(ctx, text, fontFace, width, height) {
    ctx.font = `1px ${fontFace}`;

    let fitFontWidth = Number.MAX_VALUE
    const lines = text.match(/[^\r\n]+/g);
    lines.forEach(line => {
        fitFontWidth = Math.min(fitFontWidth, width / ctx.measureText(line).width)
    })
    let fitFontHeight = height / (lines.length * 1.2); // if you want more spacing between line, you can increase this value
    return Math.min(fitFontHeight, fitFontWidth)
}

function testScaleUpX() {
    c.width += 1
    fitTextCenter()
}

function testScaleUpY() {
    c.height += 1
    fitTextCenter()
}

function testScaleDownX() {
    c.width -= 1
    fitTextCenter()
}

function testScaleDownY() {
    c.height -= 1
    fitTextCenter()
}
<canvas id="myCanvas" width="200" height="80" style="border:1px solid #000;"></canvas>
<button onclick="testScaleUpX()">+ X</button>
<button onclick="testScaleUpY()">+ Y</button>
<button onclick="testScaleDownX()">- X</button>
<button onclick="testScaleDownY()">- Y</button>
like image 103
Linh Avatar answered Oct 03 '22 14:10

Linh