HTML 캔버스에서 텍스트 줄 바꿈 방법

HTML 캔버스에 텍스트를 추가하는 것은 매우 일반적이지만 내장된 줄 바꿈 기능은 없습니다. 즉, 텍스트가 너무 길면 텍스트가 끝에서 사라집니다. 텍스트가 "Hello, this text line is very long. It will overflow"라고 가정하는 아래 예를 들어보십시오. 캔버스에 맞추기에는 너무 길기 때문에 줄 바꿈 없이 오버플로만 됩니다.



이 예제의 코드:

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');

let grd = ctx.createLinearGradient(0, 853, 1352, 0);
grd.addColorStop(0, '#00a0ff');
grd.addColorStop(1, '#12cba6');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 1342, 853);

// More text
ctx.font = '700 95px Helvetica';
ctx.fillStyle = 'white';
ctx.fillText("Hello, this text line is very long. It will overflow.", 85, 200); 


위의 텍스트는 (85, 200)px에서 시작하고 줄바꿈 없이 계속됩니다. 이상하게도 HTML 캔버스에서 줄 바꿈이 있어야 하는 위치를 스스로 계산해야 합니다. 이를 위해 사용자 지정 함수를 사용하고 해당 함수의 데이터를 사용하여 줄 바꿈을 배치할 수 있습니다.

HTML 캔버스에서 텍스트 줄 바꿈 방법



HTML에서 텍스트를 줄 바꿈하는 사용자 지정 함수를 빌드할 때 줄 바꿈이 발생하는 시기를 고려해야 합니다. 줄 바꿈은 일반적으로 다음 단어가 상위 요소(이 경우 캔버스)의 너비를 초과할 때 발생합니다. 텍스트를 감싸는 함수를 만들 때 문장의 다음 단어가 오버플로를 일으키는지 확인해야 합니다.

이와 같이 몇 가지 다른 변수를 허용하는 함수를 빌드합니다.
  • ctx - 텍스트를 감싸고자 하는 캔버스의 컨텍스트입니다.
    text - 래핑하려는 텍스트.
  • x - 캔버스에 있는 텍스트의 X 시작점.
  • y - 캔버스에 있는 텍스트의 Y 시작점.
  • maxWidth - 줄 바꿈을 시작하려는 너비, 즉 캔버스의 최대 너비입니다.
  • lineHeight - 각 줄의 높이로 서로 아래에 간격을 둘 수 있습니다.
    이를 위해 내가 만든 함수를 살펴보겠습니다.

  • // @description: wrapText wraps HTML canvas text onto a canvas of fixed width
    // @param ctx - the context for the canvas we want to wrap text on
    // @param text - the text we want to wrap.
    // @param x - the X starting point of the text on the canvas.
    // @param y - the Y starting point of the text on the canvas.
    // @param maxWidth - the width at which we want line breaks to begin - i.e. the maximum width of the canvas.
    // @param lineHeight - the height of each line, so we can space them below each other.
    // @returns an array of [ lineText, x, y ] for all lines
    const wrapText = function(ctx, text, x, y, maxWidth, lineHeight) {
        // First, start by splitting all of our text into words, but splitting it into an array split by spaces
        let words = text.split(' ');
        let line = ''; // This will store the text of the current line
        let testLine = ''; // This will store the text when we add a word, to test if it's too long
        let lineArray = []; // This is an array of lines, which the function will return
    
        // Lets iterate over each word
        for(var n = 0; n < words.length; n++) {
            // Create a test line, and measure it..
            testLine += `${words[n]} `;
            let metrics = ctx.measureText(testLine);
            let testWidth = metrics.width;
            // If the width of this test line is more than the max width
            if (testWidth > maxWidth && n > 0) {
                // Then the line is finished, push the current line into "lineArray"
                lineArray.push([line, x, y]);
                // Increase the line height, so a new line is started
                y += lineHeight;
                // Update line and test line to use this word as the first word on the next line
                line = `${words[n]} `;
                testLine = `${words[n]} `;
            }
            else {
                // If the test line is still less than the max width, then add the word to the current line
                line += `${words[n]} `;
            }
            // If we never reach the full max width, then there is only one line.. so push it into the lineArray so we return something
            if(n === words.length - 1) {
                lineArray.push([line, x, y]);
            }
        }
        // Return the line array
        return lineArray;
    }
    


    이 기능은 몇 가지 전제에서 작동합니다.
  • measureText() 를 사용하여 새 줄을 테스트합니다. 컨테이너에 비해 너무 길면 새 줄을 시작합니다. 그렇지 않으면 현재 상태를 유지합니다.
  • 미리 정의된 선 높이를 사용하여 일관된 선 높이를 가질 수 있습니다.
  • 각 줄에 대해 [ lineText, x, y ]의 배열을 반환합니다. 여기서 lineText는 해당 줄의 텍스트이고 x/y는 해당 특정 줄의 시작 위치입니다.
  • 한 줄만 있는 경우 해당 줄을 lineArray 에 반환합니다.
  • 캔버스에 적용하려면 배열의 각 요소를 반복해야 합니다. 그런 다음 ctx.fillText를 사용하여 wrapText() 함수에 의해 계산된 좌표에 각 선을 그립니다. 그러면 궁극적으로 줄 바꿈이 생성됩니다.

  • // Set up our font and fill style
    ctx.font = '700 95px Helvetica';
    ctx.fillStyle = 'white';
    // we pass in ctx, text, x, y, maxWidth, lineHeight to wrapText()
    // I am using a slightly smaller maxWidth than the canvas width, since I wanted to add padding to either side of the canvas.
    let wrappedText = wrapText(ctx, "This line is way too long. It's going to overflow - but it should line break.", 85, 200, 1050, 140);
    // wrappedTe
    wrappedText.forEach(function(item) {
        // item[0] is the text
        // item[1] is the x coordinate to fill the text at
        // item[2] is the y coordinate to fill the text at
        ctx.fillText(item[0], item[1], item[2]); 
    })
    


    그리고 우리는 래핑된 텍스트로 끝납니다.


    이제 캔버스에서 텍스트를 래핑할 수 있습니다. 위 예제의 최종 코드는 다음과 같습니다.

    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    
    canvas.width = 1200;
    canvas.height = 800;
    
    // @description: wrapText wraps HTML canvas text onto a canvas of fixed width
    // @param ctx - the context for the canvas we want to wrap text on
    // @param text - the text we want to wrap.
    // @param x - the X starting point of the text on the canvas.
    // @param y - the Y starting point of the text on the canvas.
    // @param maxWidth - the width at which we want line breaks to begin - i.e. the maximum width of the canvas.
    // @param lineHeight - the height of each line, so we can space them below each other.
    // @returns an array of [ lineText, x, y ] for all lines
    const wrapText = function(ctx, text, x, y, maxWidth, lineHeight) {
        // First, start by splitting all of our text into words, but splitting it into an array split by spaces
        let words = text.split(' ');
        let line = ''; // This will store the text of the current line
        let testLine = ''; // This will store the text when we add a word, to test if it's too long
        let lineArray = []; // This is an array of lines, which the function will return
    
        // Lets iterate over each word
        for(var n = 0; n < words.length; n++) {
            // Create a test line, and measure it..
            testLine += `${words[n]} `;
            let metrics = ctx.measureText(testLine);
            let testWidth = metrics.width;
            // If the width of this test line is more than the max width
            if (testWidth > maxWidth && n > 0) {
                // Then the line is finished, push the current line into "lineArray"
                lineArray.push([line, x, y]);
                // Increase the line height, so a new line is started
                y += lineHeight;
                // Update line and test line to use this word as the first word on the next line
                line = `${words[n]} `;
                testLine = `${words[n]} `;
            }
            else {
                // If the test line is still less than the max width, then add the word to the current line
                line += `${words[n]} `;
            }
            // If we never reach the full max width, then there is only one line.. so push it into the lineArray so we return something
            if(n === words.length - 1) {
                lineArray.push([line, x, y]);
            }
        }
        // Return the line array
        return lineArray;
    }
    
    
    // Add gradient
    let grd = ctx.createLinearGradient(0, 1200, 800, 0);
    grd.addColorStop(0, '#00a0ff');
    grd.addColorStop(1, '#12cba6');
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 1200, 800);
    
    // More text
    ctx.font = '700 95px Helvetica';
    ctx.fillStyle = 'white';
    let wrappedText = wrapText(ctx, "This line is way too long. It's going to overflow - but it should line break.", 85, 200, 1050, 140);
    wrappedText.forEach(function(item) {
        ctx.fillText(item[0], item[1], item[2]); 
    })
    


    결론



    HTML 캔버스에서 텍스트를 감싸기 위해 사용자 지정 함수를 작성해야 하지만 작동 방식을 이해하면 그리 어렵지 않습니다. HTML 캔버스로 텍스트를 래핑하는 방법에 대한 이 가이드가 도움이 되었기를 바랍니다. HTML 캔버스에 대한 자세한 내용은 check out my full length guide here .

    좋은 웹페이지 즐겨찾기