WEB/JavaScript

[JavaScript] HTML5 캔버스 ctx.fillText는 줄 바꿈 관련

AlrepondTech 2018. 5. 14. 10:36
반응형

 

 

 

 

 

 

=======================

=======================

=======================

 

 

 

 

 

 

 

출처: https://code.i-harness.com/ko/q/4cb491

 

 

어쩌면이 파티에 조금 늦을 지 모르지만 캔버스에 텍스트를 배치하는 데 필요한 다음 자습서를 찾았습니다.

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

그로부터 여러 줄이 작동한다고 생각할 수있었습니다. (미안 해요. 라미레즈, 네가 나를 위해 일하지 않았다!). 캔버스에 텍스트를 줄 바꿈하는 내 전체 코드는 다음과 같습니다.

<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 는 내 캔버스의 ID이고 text 는 내 텍스트 상자의 ID입니다.

아마도 비표준 글꼴을 사용하고있는 것을 볼 수 있습니다. 일부 텍스트 앞에있는 글꼴을 캔버스 조작에 사용하는 한 @ font-face를 사용할 수 있습니다. 그렇지 않으면 캔버스가 글꼴을 선택하지 않습니다.

희망이 사람을 도움이됩니다.

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

여기에 이미 나와있는 wrapText () 함수를 수정하여 내 솔루션입니다. 캔버스 컨텍스트에서 함수를 호출 할 수 있도록 JavaScript의 프로토 타이핑 기능을 사용하고 있습니다.

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/

 

//--------------------------------------

@Gaby Petrioli 가 제공하는 단어 줄 바꿈 (공백으로 분리)에 대한 코드는 매우 유용합니다. 줄 바꿈 문자를 지원하도록 코드를 확장했습니다. \n . 또한 경계 상자의 크기를 갖는 것이 종종 유용하므로 multiMeasureText() 는 너비와 높이를 모두 반환합니다.

http://jsfiddle.net/jeffchan/WHgaY/76/ 에서 코드를 볼 수 있습니다.

//--------------------------------------

 

 

 

 

반응형

 

 

728x90

 

 

 

CanvasRenderingContext2D를 확장하여 mlFillText와 mlStrokeText의 두 함수를 추가했습니다.

GitHub 에서 마지막 버전을 찾을 수 있습니다.

이 기능을 사용하면 상자에 밀틴 텍스트를 채우거나 칠할 수 있습니다. 텍스트를 세로 및 가로로 정렬 할 수 있습니다. (계정에 \ n을 넣고 텍스트를 정당화 할 수도 있습니다.)

프로토 타입은 다음과 같습니다.

함수 mlFillText (텍스트, x, y, w, h, vAlign, hAlign, lineheight); 함수 mlStrokeText (텍스트, x, y, w, h, vAlign, hAlign, lineheight);

여기서 vAlign은 "top", "center"또는 "button"일 수 있습니다. hAlign은 "left", "center", "right"또는 "justify"일 수 있습니다.

여기서 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);

//--------------------------------------

 

 

다음은 context.textBaseline = 'middle' 하여 세로로 가운데에 정렬 된 텍스트 도 지원하는 Colin의 wrapText() 버전입니다.

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

//--------------------------------------

나는이 문제가 똑같은 문제로 인해서 일어났다. 가변 글꼴 크기로 작업하고 있으므로이 점을 고려해야합니다.


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"입니다 (픽셀 크기가 먼저 나타남)

//--------------------------------------

 

문제에 대한 내 ES5 솔루션 :


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

이 문제에 대한 자세한 내용은 내 블로그에 있습니다.

 

 

 

=======================

=======================

=======================

 

 

반응형