HTML5canvasctx.fillText不会做换行符?

如果文本包含“\ n”,我似乎无法将文本添加到canvas。 我的意思是,换行不显示/工作。

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

上面的代码将在一行中绘制"s ome \n <br/> thing"

这是fillText的限制还是我做错了? “\ n”在那里,而不是打印,但他们也不工作。

恐怕是Canvas'fillText的限制。 没有多线支持。 更糟的是,没有固定的方法来测量线条高度,只有宽度,使自己更难!

很多人写了自己的多线支持,也许是Mozilla Skywriter最显着的项目。

你需要做的事情是多次fillText调用,而每次将文本的高度添加到y值。 (我相信,测量​​M的宽度就是天文作家们为了近似文本而做的)。

也许来参加这个晚会有点晚,但是我发现下面这个教程在一个完美的canvas上包装文本。

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

从那以后,我可以想象得到多行工作(对不起,拉米雷斯,你没有为我工作!)。 我用完整的代码来包装文字在canvas上如下所示:

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

其中c是我的canvas的ID, text是我的文本框的ID。

正如你可能看到我正在使用一个非标准的字体。 只要您使用PRIOR文字上的字体操作canvas,就可以使用@ font-face,否则canvas将无法拾取字体。

希望这有助于某人。

如果你只是想照顾文本中的换行符,可以通过拆分新行处的文本并多次调用fillText()来模拟它。

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> 

这是我的解决scheme,修改已经在这里介绍的stream行的wrapText()函数。 我正在使用JavaScript的原型function,以便您可以从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; } } 

基本用法:

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

下面是我放在一起的一个演示: http : //jsfiddle.net/7RdbL/

将文本分成几行,分别绘制:

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

@Gaby Petrioli提供的用于单词包装(打破空格)的代码非常有用。 我已经扩展他的代码来提供对换行符的支持\n 。 此外,通常情况下有边界框的尺寸是有用的,所以multiMeasureText()返回宽度和高度。

你可以在这里看到代码: http : //jsfiddle.net/jeffchan/WHgaY/76/

使用JavaScript我开发了一个解决scheme。 这不是美丽的,但它为我工作:


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

希望有所帮助!

我只是扩展了CanvasRenderingContext2D,添加了两个函数:mlFillText和mlStrokeText。

你可以在GitHub中find最新的版本:

有了这个function,你可以在一个盒子里填充/冲击miltiline文本。 您可以将文字垂直和水平alignment。 (这需要考虑\ n的,也可以certificate文字)。

原型是:

函数mlFillText(text,x,y,w,h,vAlign,hAlign,lineheight); 函数mlStrokeText(text,x,y,w,h,vAlign,hAlign,lineheight);

vAlign可以是:“top”,“center”或“button”,hAlign可以是“left”,“center”,“right”或“justify”

你可以在这里testing这个lib: http : //jsfiddle.net/4WRZj/1/

在这里输入图像描述

这里是图书馆的代码:

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

这里是使用示例:

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

我认为你仍然可以依靠CSS

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

幸运的是,通过CSS hack-ardry(请参阅使用CSS度量的旧版实现方法的更多方法),我们可以通过使用相同的font-properties测量a的offsetHeight来find文本的高度:

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

来自: http : //www.html5rocks.com/en/tutorials/canvas/texteffects/

这里是Colin的wrapText()版本,它也支持 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; } }; 

我不认为这是可能的,但一个解决方法是创build一个<p>元素并使用Javascript来定位它。

由于遇到同样的问题,我碰巧遇到了这个问题。 我正在处理可变字体大小,所以这会考虑到这一点:

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

其中.noteContent是用户编辑的contenteditable div(这是嵌套在jQuery中的每个函数中),而ctx.font是“14px Arial”(注意像素大小在前)

Canvas元素不支持换行'\ n',标签'\ t'或标签等字符。

尝试一下:

 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 

或者可能有多行:

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

我的问题的ES5解决scheme:

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

关于这个问题的更多信息在我的博客上 。