Kanvas HTML5 ctx.fillText tidak akan melakukan jeda baris?

108

Sepertinya saya tidak bisa menambahkan teks ke kanvas jika teks tersebut menyertakan "\ n". Maksud saya, jeda baris tidak muncul / berfungsi.

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

Kode di atas akan menggambar "s ome \n <br/> thing", dalam satu baris.

Apakah ini batasan fillText atau apakah saya salah melakukannya? "\ n" ada di sana, dan tidak dicetak, tetapi juga tidak berfungsi.

Spectraljump
sumber
1
apakah Anda ingin membungkus secara otomatis saat mencapai akhir? atau hanya untuk mempertimbangkan karakter baris baru yang ada dalam teks?
Gabriele Petrioli
Bungkus teks menjadi beberapa baris.
Menara
Halo twodordan, apakah batasan ini ada di chrome dan mozilla? Orang sering menggunakan teks html sederhana yang mereka letakkan di atas kanvas dengan posisi: absolut misalnya. Anda juga dapat melakukan dua fillText dan memindahkan asal Y teks Anda untuk baris kedua Anda.
Tim
TL; DR: Panggil fillText()beberapa kali dan gunakan tinggi font Anda untuk memisahkan, atau gunakan developer.mozilla.org/en-US/docs/Web/API/TextMetrics developer.mozilla.org/en-US/docs/Web/API /… - atau, gunakan salah satu "solusi" yang sangat rumit di bawah ini yang tidak menggunakan TextMetrics ...
Andrew

Jawaban:

62

Saya khawatir itu adalah batasan Canvas ' fillText. Tidak ada dukungan multi-jalur. Lebih buruk lagi, tidak ada cara built-in untuk mengukur tinggi garis, hanya lebarnya, membuat melakukannya sendiri lebih sulit!

Banyak orang telah menulis dukungan multi-line mereka sendiri, mungkin proyek yang paling terkenal adalah Mozilla Skywriter .

Inti dari apa yang perlu Anda lakukan adalah beberapa fillTextpanggilan sambil menambahkan tinggi teks ke nilai y setiap kali. (Saya yakin mengukur lebar M adalah apa yang dilakukan penulis langit untuk memperkirakan teks.)

Simon Sarris
sumber
Terima kasih! Saya merasa itu akan merepotkan ... Senang mengetahui tentang SKYWRITER, tetapi saya hanya akan "menunggu" sampai fillText () ditingkatkan. Itu bukanlah kesepakatan yang terlalu penting dalam kasus saya. Hah, tidak ada garis tinggi, sepertinya seseorang melakukan itu dengan sengaja. : D
Spectraljump
18
Sejujurnya, saya tidak akan menahan napas saat fillText () "ditingkatkan" untuk mendukung ini, karena saya merasa ini adalah cara penggunaannya (beberapa panggilan & menghitung yOffset sendiri). Saya rasa banyak kekuatan dengan API kanvas adalah bahwa ia memisahkan fungsionalitas gambar tingkat rendah dari apa yang sudah dapat Anda lakukan (melakukan pengukuran yang diperlukan). Selain itu, Anda dapat mengetahui tinggi teks hanya dengan memberikan ukuran teks dalam piksel; dengan kata lain: context.font = "16px Arial"; - Anda memiliki ketinggian di sana; lebarnya adalah satu-satunya yang dinamis.
Im
1
Beberapa sifat tambahan untuk measureText()telah ditambahkan yang saya pikir bisa memecahkan masalah. Chrome memiliki bendera untuk mengaktifkannya, tetapi browser lain belum ...!
SWdV
@SWdV hanya untuk memperjelas, itu telah ada di spesifikasi selama bertahun-tahun sekarang, mungkin masih bertahun-tahun sampai kami memiliki adopsi yang cukup luas untuk digunakan :(
Simon Sarris
67

Jika Anda hanya ingin menangani karakter baris baru dalam teks, Anda dapat mensimulasikannya dengan memisahkan teks pada baris baru dan memanggil beberapa kali fillText()

Sesuatu seperti 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>


Saya baru saja membuat bukti pembungkus konsep ( bungkus absolut pada lebar yang ditentukan. Belum ada penanganan kata yang melanggar )
contoh di 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>


Dan bukti konsep yang membungkus kata ( melanggar ruang ).
contoh di 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>


Dalam contoh kedua dan ketiga saya menggunakan measureText()metode yang menunjukkan berapa panjang ( dalam piksel ) string akan saat dicetak.

Gabriele Petrioli
sumber
bagaimana membenarkan seluruh teks panjang?
Amirhossein Tarmast
Jika Anda membutuhkan teks yang panjang dan rata, mengapa Anda menggunakan kanvas?
Mike 'Pomax' Kamermans
39

Mungkin datang ke pesta ini agak terlambat, tetapi saya menemukan tutorial berikut untuk membungkus teks di kanvas dengan sempurna.

http://www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/

Dari situ saya bisa berpikir untuk membuat multi baris berfungsi (maaf Ramirez, milik Anda tidak berhasil untuk saya!). Kode lengkap saya untuk membungkus teks di kanvas adalah sebagai berikut:

<script type="text/javascript">

     // http: //www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/
     function wrapText(context, text, x, y, maxWidth, lineHeight) {
        var cars = text.split("\n");

        for (var ii = 0; ii < cars.length; ii++) {

            var line = "";
            var words = cars[ii].split(" ");

            for (var n = 0; n < words.length; n++) {
                var testLine = line + words[n] + " ";
                var metrics = context.measureText(testLine);
                var testWidth = metrics.width;

                if (testWidth > maxWidth) {
                    context.fillText(line, x, y);
                    line = words[n] + " ";
                    y += lineHeight;
                }
                else {
                    line = testLine;
                }
            }

            context.fillText(line, x, y);
            y += lineHeight;
        }
     }

     function DrawText() {

         var canvas = document.getElementById("c");
         var context = canvas.getContext("2d");

         context.clearRect(0, 0, 500, 600);

         var maxWidth = 400;
         var lineHeight = 60;
         var x = 20; // (canvas.width - maxWidth) / 2;
         var y = 58;


         var text = document.getElementById("text").value.toUpperCase();                

         context.fillStyle = "rgba(255, 0, 0, 1)";
         context.fillRect(0, 0, 600, 500);

         context.font = "51px 'LeagueGothicRegular'";
         context.fillStyle = "#333";

         wrapText(context, text, x, y, maxWidth, lineHeight);
     }

     $(document).ready(function () {

         $("#text").keyup(function () {
             DrawText();
         });

     });

    </script>

Di mana cID kanvas saya dan textID kotak teks saya.

Seperti yang mungkin Anda lihat, saya menggunakan font non-standar. Anda dapat menggunakan @ font-face selama Anda telah menggunakan font pada beberapa teks SEBELUMNYA untuk memanipulasi kanvas - jika tidak, kanvas tidak akan mengambil font tersebut.

Semoga ini bisa membantu seseorang.

Colin Wiseman
sumber
26

Pisahkan teks menjadi beberapa baris, dan gambar masing-masing secara terpisah:

function fillTextMultiLine(ctx, text, x, y) {
  var lineHeight = ctx.measureText("M").width * 1.2;
  var lines = text.split("\n");
  for (var i = 0; i < lines.length; ++i) {
    ctx.fillText(lines[i], x, y);
    y += lineHeight;
  }
}
Rok Strniša
sumber
17

Inilah solusi saya, memodifikasi fungsi wrapText () populer yang sudah disajikan di sini. Saya menggunakan fitur pembuatan prototipe JavaScript sehingga Anda dapat memanggil fungsi dari konteks kanvas.

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

Penggunaan dasar:

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

Inilah demonstrasi yang saya buat : http://jsfiddle.net/7RdbL/

Jake
sumber
Bekerja seperti pesona. Terima kasih.
couzzi
13

Saya baru saja memperluas CanvasRenderingContext2D dengan menambahkan dua fungsi: mlFillText dan mlStrokeText.

Anda dapat menemukan versi terakhir di GitHub :

Dengan fungsi ini Anda dapat mengisi / stroke teks miltiline dalam sebuah kotak. Anda dapat meratakan teks secara vertikal dan horizontal. (Ini memperhitungkan \ n dan juga dapat membenarkan teks).

Prototipe tersebut adalah:

function mlFillText (teks, x, y, w, h, vAlign, hAlign, lineheight); function mlStrokeText (teks, x, y, w, h, vAlign, hAlign, lineheight);

Dimana vAlign bisa menjadi: "top", "center" atau "button" Dan hAlign bisa menjadi: "left", "center", "right" atau "justify"

Anda dapat menguji lib di sini: http://jsfiddle.net/4WRZj/1/

masukkan deskripsi gambar di sini

Berikut adalah kode pustaka:

// Library: mltext.js
// Desciption: Extends the CanvasRenderingContext2D that adds two functions: mlFillText and mlStrokeText.
//
// The prototypes are: 
//
// function mlFillText(text,x,y,w,h,vAlign,hAlign,lineheight);
// function mlStrokeText(text,x,y,w,h,vAlign,hAlign,lineheight);
// 
// Where vAlign can be: "top", "center" or "button"
// And hAlign can be: "left", "center", "right" or "justify"
// Author: Jordi Baylina. (baylina at uniclau.com)
// License: GPL
// Date: 2013-02-21

function mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, fn) {
    text = text.replace(/[\n]/g, " \n ");
    text = text.replace(/\r/g, "");
    var words = text.split(/[ ]+/);
    var sp = this.measureText(' ').width;
    var lines = [];
    var actualline = 0;
    var actualsize = 0;
    var wo;
    lines[actualline] = {};
    lines[actualline].Words = [];
    i = 0;
    while (i < words.length) {
        var word = words[i];
        if (word == "\n") {
            lines[actualline].EndParagraph = true;
            actualline++;
            actualsize = 0;
            lines[actualline] = {};
            lines[actualline].Words = [];
            i++;
        } else {
            wo = {};
            wo.l = this.measureText(word).width;
            if (actualsize === 0) {
                while (wo.l > w) {
                    word = word.slice(0, word.length - 1);
                    wo.l = this.measureText(word).width;
                }
                if (word === "") return; // I can't fill a single character
                wo.word = word;
                lines[actualline].Words.push(wo);
                actualsize = wo.l;
                if (word != words[i]) {
                    words[i] = words[i].slice(word.length, words[i].length);
                } else {
                    i++;
                }
            } else {
                if (actualsize + sp + wo.l > w) {
                    lines[actualline].EndParagraph = false;
                    actualline++;
                    actualsize = 0;
                    lines[actualline] = {};
                    lines[actualline].Words = [];
                } else {
                    wo.word = word;
                    lines[actualline].Words.push(wo);
                    actualsize += sp + wo.l;
                    i++;
                }
            }
        }
    }
    if (actualsize === 0) lines[actualline].pop();
    lines[actualline].EndParagraph = true;

    var totalH = lineheight * lines.length;
    while (totalH > h) {
        lines.pop();
        totalH = lineheight * lines.length;
    }

    var yy;
    if (vAlign == "bottom") {
        yy = y + h - totalH + lineheight;
    } else if (vAlign == "center") {
        yy = y + h / 2 - totalH / 2 + lineheight;
    } else {
        yy = y + lineheight;
    }

    var oldTextAlign = this.textAlign;
    this.textAlign = "left";

    for (var li in lines) {
        var totallen = 0;
        var xx, usp;
        for (wo in lines[li].Words) totallen += lines[li].Words[wo].l;
        if (hAlign == "center") {
            usp = sp;
            xx = x + w / 2 - (totallen + sp * (lines[li].Words.length - 1)) / 2;
        } else if ((hAlign == "justify") && (!lines[li].EndParagraph)) {
            xx = x;
            usp = (w - totallen) / (lines[li].Words.length - 1);
        } else if (hAlign == "right") {
            xx = x + w - (totallen + sp * (lines[li].Words.length - 1));
            usp = sp;
        } else { // left
            xx = x;
            usp = sp;
        }
        for (wo in lines[li].Words) {
            if (fn == "fillText") {
                this.fillText(lines[li].Words[wo].word, xx, yy);
            } else if (fn == "strokeText") {
                this.strokeText(lines[li].Words[wo].word, xx, yy);
            }
            xx += lines[li].Words[wo].l + usp;
        }
        yy += lineheight;
    }
    this.textAlign = oldTextAlign;
}

(function mlInit() {
    CanvasRenderingContext2D.prototype.mlFunction = mlFunction;

    CanvasRenderingContext2D.prototype.mlFillText = function (text, x, y, w, h, vAlign, hAlign, lineheight) {
        this.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, "fillText");
    };

    CanvasRenderingContext2D.prototype.mlStrokeText = function (text, x, y, w, h, vAlign, hAlign, lineheight) {
        this.mlFunction(text, x, y, w, h, hAlign, vAlign, lineheight, "strokeText");
    };
})();

Dan inilah contoh penggunaannya:

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

var T = "This is a very long line line with a CR at the end.\n This is the second line.\nAnd this is the last line.";
var lh = 12;

ctx.lineWidth = 1;

ctx.mlFillText(T, 10, 10, 100, 100, 'top', 'left', lh);
ctx.strokeRect(10, 10, 100, 100);

ctx.mlFillText(T, 110, 10, 100, 100, 'top', 'center', lh);
ctx.strokeRect(110, 10, 100, 100);

ctx.mlFillText(T, 210, 10, 100, 100, 'top', 'right', lh);
ctx.strokeRect(210, 10, 100, 100);

ctx.mlFillText(T, 310, 10, 100, 100, 'top', 'justify', lh);
ctx.strokeRect(310, 10, 100, 100);

ctx.mlFillText(T, 10, 110, 100, 100, 'center', 'left', lh);
ctx.strokeRect(10, 110, 100, 100);

ctx.mlFillText(T, 110, 110, 100, 100, 'center', 'center', lh);
ctx.strokeRect(110, 110, 100, 100);

ctx.mlFillText(T, 210, 110, 100, 100, 'center', 'right', lh);
ctx.strokeRect(210, 110, 100, 100);

ctx.mlFillText(T, 310, 110, 100, 100, 'center', 'justify', lh);
ctx.strokeRect(310, 110, 100, 100);

ctx.mlFillText(T, 10, 210, 100, 100, 'bottom', 'left', lh);
ctx.strokeRect(10, 210, 100, 100);

ctx.mlFillText(T, 110, 210, 100, 100, 'bottom', 'center', lh);
ctx.strokeRect(110, 210, 100, 100);

ctx.mlFillText(T, 210, 210, 100, 100, 'bottom', 'right', lh);
ctx.strokeRect(210, 210, 100, 100);

ctx.mlFillText(T, 310, 210, 100, 100, 'bottom', 'justify', lh);
ctx.strokeRect(310, 210, 100, 100);

ctx.mlStrokeText("Yo can also use mlStrokeText!", 0 , 310 , 420, 30, 'center', 'center', lh);
jbaylina
sumber
Uncaught ReferenceError: Words is not definedJika saya mencoba mengubah font. Misalnya: ctx.font = '40px Arial';- coba masukkan itu ke biola Anda
psiko brm
Btw, dari mana sih Wordsvariabel (case-sensitive) berasal ?? Itu tidak ditentukan di mana pun. Bagian kode itu hanya dijalankan saat Anda mengubah font ..
psiko brm
1
@psychobr Anda benar sepenuhnya. Ini adalah bug (saya sudah memperbaikinya). Bagian kode ini hanya dijalankan jika Anda harus membagi kata menjadi dua baris. Terima kasih!
jbaylina
Saya telah membuat beberapa peningkatan yang saya butuhkan: membuat spasi, membuat garis depan / garis baru, membuat goresan dan mengisi dengan satu panggilan (jangan mengukur teks dua kali), saya juga harus mengubah iterasi, karena for intidak berfungsi dengan baik dengan ekstensi Array.prototype. Bisakah Anda meletakkannya di github sehingga kami dapat mengulanginya?
psiko brm
@psychobr Saya menggabungkan perubahan Anda. Terima kasih!
jbaylina
8

Menggunakan javascript saya mengembangkan solusi. Itu tidak indah tetapi berhasil untuk saya:


function drawMultilineText(){

    // set context and formatting   
    var context = document.getElementById("canvas").getContext('2d');
    context.font = fontStyleStr;
    context.textAlign = "center";
    context.textBaseline = "top";
    context.fillStyle = "#000000";

    // prepare textarea value to be drawn as multiline text.
    var textval = document.getElementByID("textarea").value;
    var textvalArr = toMultiLine(textval);
    var linespacing = 25;
    var startX = 0;
    var startY = 0;

    // draw each line on canvas. 
    for(var i = 0; i < textvalArr.length; i++){
        context.fillText(textvalArr[i], x, y);
        y += linespacing;
    }
}

// Creates an array where the <br/> tag splits the values.
function toMultiLine(text){
   var textArr = new Array();
   text = text.replace(/\n\r?/g, '<br/>');
   textArr = text.split("<br/>");
   return textArr;
}

Semoga membantu!

Ramirez
sumber
1
halo, misalkan teks saya seperti ini var text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa lalu apa yang terjadi di kanvas ???
Amol Navsupe
Ini akan keluar dari kanvas, karena @Ramirez tidak meletakkan parameter maxWidth ke fillText :)
KaHa6uc
6

Kode untuk membungkus kata (melanggar spasi) yang disediakan oleh @Gaby Petrioli sangat membantu. Saya telah memperpanjang kodenya untuk memberikan dukungan untuk karakter baris baru \n. Selain itu, sering kali berguna untuk memiliki dimensi kotak pembatas, jadi multiMeasureText()kembalikan lebar dan tingginya.

Anda dapat melihat kodenya di sini: http://jsfiddle.net/jeffchan/WHgaY/76/

jeffchan
sumber
tautan kedaluwarsa, harap masukkan kode dalam jawaban ini meskipun Anda memiliki tautan yang berfungsi. Jika jsfiddle dimatikan, jawaban ini menjadi tidak berguna sama sekali.
Mike 'Pomax' Kamermans
5

Berikut adalah versi Colin wrapText()yang juga mendukung teks yang berada di tengah vertikal dengan context.textBaseline = 'middle':

var wrapText = function (context, text, x, y, maxWidth, lineHeight) {
    var paragraphs = text.split("\n");
    var textLines = [];

    // Loop through paragraphs
    for (var p = 0; p < paragraphs.length; p++) {
        var line = "";
        var words = paragraphs[p].split(" ");
        // Loop through words
        for (var w = 0; w < words.length; w++) {
            var testLine = line + words[w] + " ";
            var metrics = context.measureText(testLine);
            var testWidth = metrics.width;
            // Make a line break if line is too long
            if (testWidth > maxWidth) {
                textLines.push(line.trim());
                line = words[w] + " ";
            }
            else {
                line = testLine;
            }
        }
        textLines.push(line.trim());
    }

    // Move text up if centered vertically
    if (context.textBaseline === 'middle')
        y = y - ((textLines.length-1) * lineHeight) / 2;

    // Render text on canvas
    for (var tl = 0; tl < textLines.length; tl++) {
        context.fillText(textLines[tl], x, y);
        y += lineHeight;
    }
};
Tom Söderlund
sumber
5

Jika Anda hanya membutuhkan dua baris teks, Anda dapat membaginya menjadi dua panggilan fillText berbeda dan memberikan garis dasar yang berbeda pada masing-masing baris.

ctx.textBaseline="bottom";
ctx.fillText("First line", x-position, y-position);
ctx.textBaseline="top";
ctx.fillText("Second line", x-position, y-position);
thingEvery
sumber
4

Pertanyaan ini tidak memikirkan bagaimana kanvas bekerja. Jika Anda ingin jeda baris cukup sesuaikan koordinat Anda berikutnya ctx.fillText.

ctx.fillText("line1", w,x,y,z)
ctx.fillText("line2", w,x,y,z+20)
jayjey
sumber
3

Saya pikir Anda masih bisa mengandalkan CSS

ctx.measureText().height doesnt exist.

Untungnya, melalui hack-ardry CSS (lihat Metrik Tipografi untuk lebih banyak cara untuk memperbaiki implementasi lama menggunakan pengukuran CSS), kita dapat menemukan tinggi teks melalui pengukuran offsetHeight dari a dengan properti font yang sama:

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

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

MarioF
sumber
Itu adalah solusi yang bagus jika Anda memiliki memori untuk membangun elemen seperti itu setiap kali Anda perlu mengukur. Anda juga bisa ctx.save(), ctx.font = '12pt Arial' lalu parseInt( ctx.font, 10 ),. Perhatikan bahwa saya menggunakan 'pt' saat mengaturnya. Ini kemudian akan diterjemahkan ke dalam PX dan dapat diubah menjadi digit untuk dikonsumsi sebagai tinggi font.
Eric Hodonsky
3

Saya membuat perpustakaan kecil untuk skenario ini di sini: Canvas-Txt

Ini membuat teks dalam multi-baris dan menawarkan mode penyelarasan yang layak.

Untuk menggunakan ini, Anda perlu menginstalnya atau menggunakan CDN.

Instalasi

npm install canvas-txt --save

JavaScript

import canvasTxt from 'canvas-txt'

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

var txt = 'Lorem ipsum dolor sit amet'

canvasTxt.fontSize = 24

canvasTxt.drawText(ctx, txt, 100, 200, 200, 200)

Ini akan membuat teks dalam kotak tak terlihat dengan posisi / dimensi:

{ x: 100, y: 200, height: 200, width: 200 }

Contoh Fiddle

/* https://github.com/geongeorge/Canvas-Txt  */

const canvasTxt = window.canvasTxt.default;
const ctx = document.getElementById('myCanvas').getContext('2d');

const txt = "Lorem ipsum dolor sit amet";
const bounds = { width: 240, height: 80 };

let origin = { x: ctx.canvas.width / 2, y: ctx.canvas.height / 2, };
let offset = { x: origin.x - (bounds.width / 2), y: origin.y - (bounds.height / 2) };

canvasTxt.fontSize = 20;

ctx.fillStyle = '#C1A700';
ctx.fillRect(offset.x, offset.y, bounds.width, bounds.height);

ctx.fillStyle = '#FFFFFF';
canvasTxt.drawText(ctx, txt, offset.x, offset.y, bounds.width, bounds.height);
body {
  background: #111;
}

canvas {
  border: 1px solid #333;
  background: #222; /* Could alternatively be painted on the canvas */
}
<script src="https://unpkg.com/[email protected]/build/index.js"></script>

<canvas id="myCanvas" width="300" height="160"></canvas>

Geon George
sumber
Saya melanjutkan dan menetapkan beberapa variabel untuk membantu contoh "mendokumentasikan sendiri". Ini juga menangani pemusatan kotak pembatas di dalam kanvas. Saya juga menambahkan persegi panjang di belakang, sehingga Anda benar-benar dapat melihatnya di tengah dalam hubungan. Kerja bagus! +1 Satu hal kecil yang saya perhatikan adalah bahwa garis yang membungkus tidak akan memiliki ruang terdepan yang ditekan. Anda mungkin ingin memangkas setiap baris, misalnya ctx.fillText(txtline.trim(), textanchor, txtY)saya hanya melihat ini di demo interaktif Anda di situs web Anda.
Tn. Polywhirl
@ Mr.Polywhirl Terima kasih telah menjelaskan jawabannya. Saya telah memperbaiki masalah trim dan menerbitkan 2.0.9versinya. Situs demo diperbaiki dengan memperbarui versi paket. Ada masalah dengan banyak spasi. Saya tidak tahu apakah lebih baik menggunakan paket yang memiliki opini atau mengabaikan masalahnya. Telah mendapatkan permintaan untuk ini dari berbagai tempat. Saya tetap melanjutkan dan menambahkan trim. Lorem ipsum dolor, sit <many spaces> amet ini adalah alasan mengapa saya tidak melakukannya sejak awal. Menurut Anda, apa yang harus saya pertimbangkan untuk beberapa spasi dan hanya dihapus jika hanya ada satu?
Geon George
Sunting: tampaknya blok kode StackOverflow mengabaikan banyak spasi juga
Geon George
2

Saya tidak berpikir ini tidak mungkin juga, tetapi solusi untuk ini adalah membuat <p>elemen dan memposisikannya dengan Javascript.

Harmen
sumber
Ya, itulah yang sedang saya pikirkan. Hanya saja dengan fillText()dan strokeText(), Anda dapat melakukan hal-hal di luar kemampuan CSS.
Menara
Saya belum menguji ini, tetapi saya pikir ini mungkin solusi yang lebih baik - solusi lain di sini menggunakan fillText () membuatnya jadi teks tidak dapat dipilih (atau mungkin ditempelkan).
Jerry Asher
2

Saya mengalami ini karena mengalami masalah yang sama. Saya bekerja dengan ukuran font variabel, jadi ini memperhitungkannya:

var texts=($(this).find('.noteContent').html()).split("<br>");
for (var k in texts) {
    ctx.fillText(texts[k], left, (top+((parseInt(ctx.font)+2)*k)));
}

di mana .noteContent adalah div contenteditable yang diedit pengguna (ini bertumpuk di jQuery setiap fungsi), dan ctx.font adalah "14px Arial" (perhatikan bahwa ukuran piksel lebih dulu)

MaKR
sumber
0

Elemen kanvas tidak mendukung karakter seperti baris baru '\ n', tab '\ t' atau tag <br />.

Cobalah:

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 

atau mungkin beberapa baris:

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); 
}  
Dariusz J
sumber
0

Solusi ES5 saya untuk masalah ini:

var wrap_text = (ctx, text, x, y, lineHeight, maxWidth, textAlign) => {
  if(!textAlign) textAlign = 'center'
  ctx.textAlign = textAlign
  var words = text.split(' ')
  var lines = []
  var sliceFrom = 0
  for(var i = 0; i < words.length; i++) {
    var chunk = words.slice(sliceFrom, i).join(' ')
    var last = i === words.length - 1
    var bigger = ctx.measureText(chunk).width > maxWidth
    if(bigger) {
      lines.push(words.slice(sliceFrom, i).join(' '))
      sliceFrom = i
    }
    if(last) {
      lines.push(words.slice(sliceFrom, words.length).join(' '))
      sliceFrom = i
    }
  }
  var offsetY = 0
  var offsetX = 0
  if(textAlign === 'center') offsetX = maxWidth / 2
  for(var i = 0; i < lines.length; i++) {
    ctx.fillText(lines[i], x + offsetX, y + offsetY)
    offsetY = offsetY + lineHeight
  }
}

Informasi lebih lanjut tentang masalah ini ada di blog saya .

Oleg Berman
sumber