HTML5 canvas ctx.fillText won't do line breaks?

前端 未结 17 1036
甜味超标
甜味超标 2020-11-28 01:37

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         


        
相关标签:
17条回答
  • 2020-11-28 02:04

    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.

    0 讨论(0)
  • 2020-11-28 02:04

    Here's my solution, modifying the popular wrapText() function that is already presented here. I'm using the prototyping feature of JavaScript so that you can call the function from the canvas context.

    CanvasRenderingContext2D.prototype.wrapText = function (text, x, y, maxWidth, lineHeight) {
    
        var lines = text.split("\n");
    
        for (var i = 0; i < lines.length; i++) {
    
            var words = lines[i].split(' ');
            var line = '';
    
            for (var n = 0; n < words.length; n++) {
                var testLine = line + words[n] + ' ';
                var metrics = this.measureText(testLine);
                var testWidth = metrics.width;
                if (testWidth > maxWidth && n > 0) {
                    this.fillText(line, x, y);
                    line = words[n] + ' ';
                    y += lineHeight;
                }
                else {
                    line = testLine;
                }
            }
    
            this.fillText(line, x, y);
            y += lineHeight;
        }
    }
    

    Basic usage:

    var myCanvas = document.getElementById("myCanvas");
    var ctx = myCanvas.getContext("2d");
    ctx.fillStyle = "black";
    ctx.font = "12px sans-serif";
    ctx.textBaseline = "top";
    ctx.wrapText("Hello\nWorld!",20,20,160,16);
    

    Here's a demonstration I put together: http://jsfiddle.net/7RdbL/

    0 讨论(0)
  • 2020-11-28 02:04

    Canvas element doesn't support such characters as newline '\n', tab '\t' or < br /> tag.

    Try it:

    var newrow = mheight + 30;
    ctx.fillStyle = "rgb(0, 0, 0)";
    ctx.font = "bold 24px 'Verdana'";
    ctx.textAlign = "center";
    ctx.fillText("Game Over", mwidth, mheight); //first line
    ctx.fillText("play again", mwidth, newrow); //second line 
    

    or perhaps multiple lines:

    var textArray = new Array('line2', 'line3', 'line4', 'line5');
    var rows = 98;
    ctx.fillStyle = "rgb(0, 0, 0)";
    ctx.font = "bold 24px 'Verdana'";
    ctx.textAlign = "center";
    ctx.fillText("Game Over", mwidth, mheight); //first line
    
    for(var i=0; i < textArray.length; ++i) {
    rows += 30;
    ctx.fillText(textArray[i], mwidth, rows); 
    }  
    
    0 讨论(0)
  • 2020-11-28 02:05

    This question isn't thinking in terms of how canvas works. If you want a line break just simply adjust the coordinates of your next ctx.fillText.

    ctx.fillText("line1", w,x,y,z)
    ctx.fillText("line2", w,x,y,z+20)
    
    0 讨论(0)
  • 2020-11-28 02:06

    I don't think this is possible neither, but a workaround for this is to create a <p>element and position it with Javascript.

    0 讨论(0)
  • 2020-11-28 02:13

    I think you can still rely on CSS

    ctx.measureText().height doesn’t exist.
    

    Luckily, through CSS hack-ardry ( seeTypographic Metrics for more ways to fix older implementations of using CSS measurements), we can find the height of the text through measuring the offsetHeight of a with the same font-properties:

    var d = document.createElement(”span”);
    d.font = “20px arial”
    d.textContent = “Hello world!”
    var emHeight = d.offsetHeight;
    

    from: http://www.html5rocks.com/en/tutorials/canvas/texteffects/

    0 讨论(0)
提交回复
热议问题