La canvas HTML5 ctx.fillText non eseguirà interruzioni di riga?

Non riesco a essere in grado di aggiungere testo a una canvas se il testo include “\ n”. Voglio dire, le interruzioni di riga non mostrano / funzionano.

ctxPaint.fillText("s ome \n \\n 
thing", x, y);

Il codice sopra disegnerà "s ome \n
thing"
, su una riga.

È una limitazione di fillText o sto sbagliando? i “\ n” sono lì, e non sono stampati, ma non funzionano neanche.

Ho paura che si tratti di un limite di riempimento del testo. Non c’è un supporto multi-linea. Cosa c’è di peggio, non esiste un modo integrato per misurare l’altezza della linea, solo la larghezza, rendendolo ancora più difficile!

Un sacco di persone hanno scritto il proprio supporto multi-linea, forse il progetto più notevole che ha è Mozilla Skywriter .

L’essenza di ciò che devi fare è riempire più chiamate di testo mentre aggiungi l’altezza del testo al valore y ogni volta. (credo che misurare la larghezza di M sia ciò che fanno le persone dello skywriter per approssimare il testo).

Se vuoi solo occuparti dei caratteri di nuova riga nel testo, puoi simularlo suddividendo il testo nelle nuove righe e chiamando più volte fillText()

Qualcosa come 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 
 canvas{background-color:#ccc;} 
  

Magari arrivando a questa festa un po ‘tardi, ma ho trovato il seguente tutorial per avvolgere il testo su una canvas perfetta.

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

Da quel momento sono stato in grado di pensare a far funzionare le multi linee (mi dispiace Ramirez, il tuo non ha funzionato per me!). Il mio codice completo per avvolgere il testo in una canvas è il seguente:

  

Dove c è l’ID della mia canvas e il text è l’ID della mia casella di testo.

Come probabilmente puoi vedere sto usando un font non standard. Puoi usare @ font-face finché hai usato il carattere su un testo PRIMA per manipolare la canvas, altrimenti la canvas non prenderà il font.

Spero che questo aiuti qualcuno.

Dividi il testo in linee e disegna ciascuna separatamente:

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

Ecco la mia soluzione, modificando la popolare funzione wrapText () che è già presentata qui. Sto usando la funzione di prototipazione di JavaScript in modo che tu possa chiamare la funzione dal contesto della canvas.

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

Utilizzo di base:

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

Ecco una dimostrazione che ho messo insieme: http://jsfiddle.net/7RdbL/

Il codice per il word-wrapping (rottura degli spazi) fornito da @Gaby Petrioli è molto utile. Ho esteso il suo codice per fornire supporto per caratteri newline \n . Inoltre, spesso è utile avere le dimensioni del riquadro di delimitazione, quindi multiMeasureText() restituisce sia la larghezza che l’altezza.

Puoi vedere il codice qui: http://jsfiddle.net/jeffchan/WHgaY/76/

Usando javascript ho sviluppato una soluzione. Non è bello ma ha funzionato per me:


 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 
tag splits the values. function toMultiLine(text){ var textArr = new Array(); text = text.replace(/\n\r?/g, '
'); textArr = text.split("
"); return textArr; }

Spero possa aiutare!

Ho appena esteso CanvasRenderingContext2D aggiungendo due funzioni: mlFillText e mlStrokeText.

Puoi trovare l’ultima versione in GitHub :

Con questa funzione puoi riempire / accorciare il testo di miltiline in una scatola. È ansible allineare il testo verticalmente e orizzontalmente. (Prende in considerazione \ n’s e può anche giustificare il testo).

I prototipi sono:

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

Dove vAlign può essere: “top”, “center” o “button” E hAlign può essere: “left”, “center”, “right” o “justify”

Puoi testare la lib qui: http://jsfiddle.net/4WRZj/1/

inserisci la descrizione dell'immagine qui

Ecco il codice della libreria:

 // 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"); }; })(); 

Ed ecco l’esempio di utilizzo:

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

Ecco una versione di Colin’s wrapText() che supporta anche il testo centrato verticalmente con 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; } }; 

Penso che tu possa ancora fare affidamento sui CSS

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

Fortunatamente, tramite CSS hack-ardry (vedere Metriche tipografiche per altri modi per correggere le vecchie implementazioni dell’uso delle misure CSS), possiamo trovare l’altezza del testo misurando l’offsetHeight di a con le stesse proprietà dei font:

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

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

Non penso che sia nemmeno ansible, ma una soluzione per questo è creare un elemento

e posizionarlo con Javascript.

Mi sono imbattuto in questo a causa dello stesso problema. Sto lavorando con la dimensione del carattere variabile, quindi questo prende in considerazione:

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

dove .noteContent è il div contenteditable che l’utente ha modificato (questo è annidato in una jQuery ogni funzione), e ctx.font è “14px Arial” (si noti che la dimensione dei pixel viene prima)

Se hai solo bisogno di due righe di testo, puoi dividerle in due diverse chiamate di testo di riempimento e dare a ciascuna una linea di base diversa.

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

L’elemento Canvas non supporta caratteri come newline ‘\ n’, tab ‘\ t’ o tag
.

Provalo:

 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 

o forse più righe:

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

La mia soluzione ES5 per il problema:

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

Maggiori informazioni sul problema sono sul mio blog .