Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 Canvas - can I somehow use linefeeds in fillText()? [duplicate]

I can't seem to be able to add text to a canvas if the text includes "\n". I mean, the line breaks do not show/work.

ctxPaint.fillText("s  ome \n \\n <br/> thing", x, y);

The above code will draw "s ome \n <br/> thing", on one line.

Is this a limitation of fillText or am I doing it wrong? the "\n"s are there, and aren't printed, but they don't work either.

like image 513
Spectraljump Avatar asked Feb 17 '11 09:02

Spectraljump


People also ask

How do you break text in canvas?

The fillText() method draws filled text on the canvas. If you want to break lines you can do this by splitting the text at the new lines and calling the filltext() multiple times. By doing so, you are splitting the text into lines and drawing each line separately.

How do I change text color in canvas?

To change the color of text created by fillText, use the fillStyle property. Similarly, to change the color of text created by strokeText, use the strokeStyle property: var canvas = document. querySelector( "#myCanvas" );

How do I display text on canvas in HTML?

Solution with Javascript To add a text to the HTML <canvas> element, you need to use the fillText() or strokeText() methods, or you can use the combination of the two. You can also give color to your text, define the font and size, and even add gradients.

How do I show text in canvas?

Drawing Text on the Canvas To draw text on a canvas, the most important property and methods are: font - defines the font properties for the text. fillText(text,x,y) - draws "filled" text on the canvas. strokeText(text,x,y) - draws text on the canvas (no fill)


2 Answers

If you just want to take care of the newline chars in the text you could simulate it by splitting the text at the newlines and calling multiple times the fillText()

Something like http://jsfiddle.net/BaG4J/1/

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';
    console.log(c);
var txt = 'line 1\nline 2\nthird line..';
var x = 30;
var y = 30;
var lineheight = 15;
var lines = txt.split('\n');

for (var i = 0; i<lines.length; i++)
    c.fillText(lines[i], x, y + (i*lineheight) );
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>

I just made a wrapping proof of concept (absolute wrap at specified width. No handling words breaking, yet)
example at http://jsfiddle.net/BaG4J/2/

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';

var txt = 'this is a very long text to print';

printAt(c, txt, 10, 20, 15, 90 );


function printAt( context , text, x, y, lineHeight, fitWidth)
{
    fitWidth = fitWidth || 0;
    
    if (fitWidth <= 0)
    {
         context.fillText( text, x, y );
        return;
    }
    
    for (var idx = 1; idx <= text.length; idx++)
    {
        var str = text.substr(0, idx);
        console.log(str, context.measureText(str).width, fitWidth);
        if (context.measureText(str).width > fitWidth)
        {
            context.fillText( text.substr(0, idx-1), x, y );
            printAt(context, text.substr(idx-1), x, y + lineHeight, lineHeight,  fitWidth);
            return;
        }
    }
    context.fillText( text, x, y );
}
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>

And a word-wrapping (breaking at spaces) proof of concept.
example at http://jsfiddle.net/BaG4J/5/

var c = document.getElementById('c').getContext('2d');
c.font = '11px Courier';

var txt = 'this is a very long text. Some more to print!';

printAtWordWrap(c, txt, 10, 20, 15, 90 );


function printAtWordWrap( context , text, x, y, lineHeight, fitWidth)
{
    fitWidth = fitWidth || 0;
    
    if (fitWidth <= 0)
    {
        context.fillText( text, x, y );
        return;
    }
    var words = text.split(' ');
    var currentLine = 0;
    var idx = 1;
    while (words.length > 0 && idx <= words.length)
    {
        var str = words.slice(0,idx).join(' ');
        var w = context.measureText(str).width;
        if ( w > fitWidth )
        {
            if (idx==1)
            {
                idx=2;
            }
            context.fillText( words.slice(0,idx-1).join(' '), x, y + (lineHeight*currentLine) );
            currentLine++;
            words = words.splice(idx-1);
            idx = 1;
        }
        else
        {idx++;}
    }
    if  (idx > 0)
        context.fillText( words.join(' '), x, y + (lineHeight*currentLine) );
}
canvas{background-color:#ccc;}
<canvas id="c" width="150" height="150"></canvas>

In the second and third examples i am using the measureText() method which shows how long (in pixels) a string will be when printed.

like image 187
Gabriele Petrioli Avatar answered Oct 02 '22 14:10

Gabriele Petrioli


I'm afraid it is a limitation of Canvas' fillText. There is no multi-line support. Whats worse, there's no built-in way to measure line height, only width, making doing it yourself even harder!

A lot of people have written their own multi-line support, perhaps the most notable project that has is Mozilla Skywriter.

The gist of what you'll need to do is multiple fillText calls while adding the height of the text to the y value each time. (measuring the width of M is what the skywriter people do to approximate text, I believe.)

like image 34
Simon Sarris Avatar answered Oct 02 '22 14:10

Simon Sarris