HTML5 캔버스 ctx.fillText가 줄 바꿈을하지 않습니까?


108

텍스트에 "\ n"이 포함되어 있으면 캔버스에 텍스트를 추가 할 수없는 것 같습니다. 내 말은, 줄 바꿈이 표시되지 않거나 작동하지 않습니다.

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

위의 코드는 "s ome \n <br/> thing"한 줄에 를 그립니다 .

이것이 fillText의 제한입니까 아니면 내가 잘못하고 있습니까? "\ n"이 있고 인쇄되지 않지만 작동하지 않습니다.


1
끝에 도달하면 자동으로 포장 하시겠습니까? 또는 텍스트에있는 개행 문자를 고려하기 위해?
Gabriele Petrioli 2010

텍스트를 여러 줄로 묶습니다.
Tower

안녕하세요 twodordan,이 제한이 크롬과 모질라 모두에 존재합니까? 사람들은 종종 간단한 html 텍스트를 사용하여 캔버스 위에 예를 들어 position : absolute로 표시합니다. 또한 두 개의 fillText를 수행하고 두 번째 줄에 대한 텍스트의 Y 원점을 이동할 수 있습니다.
Tim


요약 :fillText() 여러 번 호출 하고 글꼴 높이를 사용하여 분리하거나 developer.mozilla.org/en-US/docs/Web/API/TextMetrics developer.mozilla.org/en-US/docs/Web/API를 사용합니다. /… -또는 TextMetrics를 사용하지 않는 아래의 매우 복잡한 "솔루션"중 하나를 사용하십시오 ...
Andrew

답변:


62

Canvas의 한계 인 것 같습니다 fillText. 여러 줄 지원이 없습니다. 설상가상으로 선 높이를 측정하는 내장 된 방법이없고 너비 만 측정 할 수 있으므로 직접 수행하기가 더 어려워집니다!

많은 사람들이 자신의 다중 라인 지원을 작성했으며 아마도 가장 주목할만한 프로젝트는 Mozilla Skywriter 입니다.

해야 할 일의 요점은 fillText매번 y 값에 텍스트 높이를 추가하면서 여러 번 호출하는 것입니다. (M의 너비를 측정하는 것은 스카이 라이터 사람들이 텍스트를 근사화하기 위해하는 일입니다.)


감사합니다! 귀찮은 느낌이 들었습니다 ... SKYWRITER에 대해 알아서 반가 웠지만 fillText ()가 개선 될 때까지 "기다릴 것"입니다. 제 경우에는별로 중요한 거래가 아니 었습니다. 하, 줄 높이가 없습니다. 누군가가 의도적으로 한 것 같습니다. : D
Spectraljump

18
솔직히, 나는 이것을 지원하기 위해 "개선 된"fillText ()에 대해 당신의 숨을 참지 않을 것입니다. 왜냐하면 이것이 사용되는 방식 (여러 호출과 yOffset을 직접 계산)이라는 느낌을 받기 때문입니다. 캔버스 API의 많은 장점은 하위 수준 그리기 기능과 이미 수행 할 수있는 작업 (필요한 측정 수행)을 분리한다는 것입니다. 또한 텍스트 크기를 픽셀 단위로 제공하여 텍스트 높이를 알 수 있습니다. 즉, context.font = "16px Arial"; -거기에 높이가 있습니다. 너비는 동적 인 유일한 것입니다.
Lev

1
일부 추가 속성 에 대한이 measureText()나는 문제를 해결할 수 있다고 생각하는 추가되었습니다. Chrome에는이를 활성화하는 플래그가 있지만 다른 브라우저에서는 지원하지 않습니다.
SWdV

@SWdV 단지 명확하게하기 위해, 사람들은 :( 우리가 사용하기에 충분히 넓은 채택 할 때까지 아직 년이 될 수있다, 지금은 년 동안 사양에 있었다
사이먼 Sarris

67

텍스트에서 개행 문자를 처리하고 싶다면 개행에서 텍스트를 분할하고 여러 번 호출하여 시뮬레이션 할 수 있습니다. 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>


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


그리고 단어 줄 바꿈 ( 공백에서 나누기 ) 개념 증명. 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>


두 번째 및 세 번째 예제 measureText()에서는 인쇄 할 때 문자열이 얼마나 길지 ( 픽셀 단위 ) 를 보여주는 방법을 사용하고 있습니다.


전체 긴 텍스트를 정당화하는 방법?
Amirhossein Tarmast

길고 정당한 텍스트가 필요한 경우 캔버스를 사용하는 이유는 무엇입니까?
Mike 'Pomax'Kamermans

39

이 파티에 조금 늦게 올지도 모르지만 캔버스에 텍스트를 완벽하게 감싸는 다음 자습서를 찾았습니다.

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

그로부터 나는 다중 라인이 작동한다고 생각할 수있었습니다 (죄송합니다 Ramirez, 당신은 나를 위해 작동하지 않았습니다!). 캔버스에서 텍스트를 래핑하는 전체 코드는 다음과 같습니다.

<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를 사용할 수 있습니다. 그렇지 않으면 캔버스가 글꼴을 선택하지 않습니다.

이것이 누군가를 돕기를 바랍니다.


26

텍스트를 선으로 분할하고 각각 개별적으로 그립니다.

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

17

여기에 이미 제시된 인기있는 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/


매력처럼 작동했습니다. 감사합니다.
couzzi

13

방금 CanvasRenderingContext2D를 확장하여 mlFillText와 mlStrokeText라는 두 가지 함수를 추가했습니다.

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

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

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

function mlFillText (text, x, y, w, h, vAlign, hAlign, lineheight); function 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);

Uncaught ReferenceError: Words is not defined글꼴을 변경하려고하면. 예를 들어 : ctx.font = '40px Arial';-바이올린에 넣어보십시오
psycho brm

Btw, 도대체 Words(대소 문자 구분) 변수는 어디에서 왔습니까 ?? 어디에도 정의되어 있지 않습니다. 코드의 해당 부분은 글꼴을 변경할 때만 실행됩니다.
psycho brm

1
@psychobrm 당신은 절대적으로 맞습니다. 버그입니다 (이미 수정했습니다). 이 코드 부분은 단어를 두 줄로 분할해야하는 경우에만 실행됩니다. 감사합니다!
jbaylina 2013 년

필요한 몇 가지 업그레이드를 수행했습니다. 공간 렌더링, 선행 / 후행 줄 바꿈 렌더링, 스트로크 렌더링 및 한 번의 호출로 채우기 (텍스트를 두 번 측정 for in하지 않음) , 확장에서 잘 작동하지 않기 때문에 반복도 변경해야했습니다 Array.prototype. 반복 할 수 있도록 github에 올려 주시겠습니까?
사이코 brm

@psychobrm 변경 사항을 병합했습니다. 감사합니다!
jbaylina

8

자바 스크립트를 사용하여 솔루션을 개발했습니다. 아름답지는 않지만 나를 위해 일했습니다.


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

도움이 되었기를 바랍니다.


1
안녕하세요, 내 텍스트가 다음과 같다고 가정합니다. var text = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 그러면 캔버스에서 무슨 일이 일어나나요 ???
Amol Navsupe 2015 년

@Ramirez이 :) fillText로의 maxWidth 매개 변수를 넣지 않은 것처럼이 캔버스 밖으로 이동합니다
KaHa6uc

6

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

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


링크가 만료,이 답변의 코드를 넣어주세요 경우에도 당신이 일 연결이 있습니다. jsfiddle이 종료되면이 대답은 그대로 완전히 쓸모 없게됩니다.
Mike 'Pomax'Kamermans

5

여기 콜린의 버전입니다 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;
    }
};

5

두 줄의 텍스트 만 필요한 경우 두 줄을 서로 다른 fillText 호출로 분할하고 각각에 다른 기준선을 제공 할 수 있습니다.

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

4

이 질문은 캔버스가 작동하는 방식에 대해 생각하지 않습니다. 줄 바꿈을 원하면 다음 좌표를 조정하기 만하면 ctx.fillText됩니다.

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

3

여전히 CSS에 의존 할 수 있다고 생각합니다.

ctx.measureText().height doesnt exist.

다행히도 CSS hack-ardry (CSS 측정을 사용하는 이전 구현을 수정하는 더 많은 방법은 Typographic Metrics 참조)를 통해 동일한 font-properties를 사용하여 a의 offsetHeight를 측정하여 텍스트의 높이를 찾을 수 있습니다.

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/


측정해야 할 때마다 이와 같은 요소를 만들 수있는 메모리가 있다면 좋은 솔루션입니다. 당신은 또한 수 ctx.save()다음, ctx.font = '12pt Arial' 다음 parseInt( ctx.font, 10 ). 설정할 때 'pt'를 사용합니다. 그런 다음 PX로 변환되고 글꼴 높이로 소비 할 숫자로 바뀔 수 있습니다.
Eric Hodonsky 2016 년

3

여기에이 시나리오를위한 작은 라이브러리를 만들었습니다. Canvas-Txt

여러 줄로 텍스트를 렌더링하고 적절한 정렬 모드를 제공합니다.

이를 사용하려면 설치하거나 CDN을 사용해야합니다.

설치

npm install canvas-txt --save

자바 스크립트

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)

이렇게하면 위치 / 크기가 다음과 같은 보이지 않는 상자에 텍스트가 렌더링됩니다.

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

예제 바이올린

/* 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/canvas-txt@2.0.6/build/index.js"></script>

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


계속해서 예제를 "자체 문서화"하는 데 도움이되는 몇 가지 변수를 정의했습니다. 또한 캔버스 내에서 경계 상자의 중앙 정렬을 처리합니다. 또한 뒤에 직사각형을 추가 했으므로 실제로는 관계가 중앙에있는 것을 볼 수 있습니다. 훌륭한 일! +1 내가 알아 차린 한 가지 작은 점은 줄 바꿈하는 줄의 선행 공백이 억제되지 않는다는 것입니다. 각 줄을 다듬고 싶을 수도 있습니다. 예를 들어 ctx.fillText(txtline.trim(), textanchor, txtY)웹 사이트의 대화 형 데모에서만이 부분을 발견했습니다.
Mr. Polywhirl

@ Mr.Polywhirl 답변을 정리해 주셔서 감사합니다. 트림 문제를 수정하고 2.0.9버전을 게시했습니다 . 데모 사이트는 패키지 버전을 업데이트하여 수정되었습니다. 공백이 여러 개인 문제가 있습니다. 의견이 많은 패키지를 사용하거나 문제를 무시하는 것이 더 좋은지 모르겠습니다. 여러 곳에서 요청을 받고 있습니다. 어쨌든 트림을 추가했습니다. Lorem ipsum dolor, sit <many spaces> amet 이것이 제가 처음에하지 않은 이유입니다. 여러 개의 공백을 고려하고 하나만있는 경우에만 제거해야한다고 생각하십니까?
Geon George

편집 : StackOverflow 코드 블록도 다중 공백을 무시하는 것 같습니다
Geon George

2

나는 이것이 가능하다고 생각하지 않지만 이에 대한 해결 방법은 <p>요소 를 만들고 Javascript로 배치하는 것입니다.


네, 그게 제가 생각하는 것입니다. 그것은 단지 그와의 fillText()그리고 strokeText()당신은 CSS가 할 수있는 것 이상의 일을 할 수있다.
Tower

나는 이것을 테스트하지는 않았지만 이것이 더 나은 해결책이라고 생각합니다. 여기에 fillText ()를 사용하는 다른 솔루션은 텍스트를 선택하거나 붙여 넣을 수 없도록 만듭니다.
Jerry Asher

2

나는 같은 문제로 인해 이것을 겪었습니다. 가변 글꼴 크기로 작업하고 있으므로 다음 사항을 고려합니다.

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"입니다 (픽셀 크기가 먼저 표시됨).


0

캔버스 요소는 줄 바꿈 '\ n', 탭 '\ t'또는 <br /> 태그와 같은 문자를 지원하지 않습니다.

시도 해봐:

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

0

문제에 대한 내 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
  }
}

문제에 대한 자세한 정보는 내 블로그에 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.