iT邦幫忙

1

如何讓html的canvas使用ctx.fillText的時候自動換行

  • 分享至 

  • xImage

問題描述

各位前輩大家好,想請問大家如何在canvas裡,遇到超過maxWidth或是遇到換行符的時候自動換行。

找過的解決方案

  1. 這一個function的缺點就是沒辦法在遇到\n的時候換行。
function wrapText(context, text, x, y, maxWidth, lineHeight) {
 var words = text.split(' '),
     line = '',
     lineCount = 0,
     i,
     test,
     metrics;
 for (i = 0; i < words.length; i++) {
     test = words[i];
     metrics = context.measureText(test);
     while (metrics.width > maxWidth) {
         test = test.substring(0, test.length - 1);
         metrics = context.measureText(test);
     }
     if (words[i] != test) {
         words.splice(i + 1, 0, words[i].substr(test.length))
         words[i] = test;
     }
     test = line + words[i] + ' ';
     metrics = context.measureText(test);
     if (metrics.width > maxWidth && i > 0) {
         context.fillText(line, x, y);
         line = words[i] + ' ';
         y += lineHeight;
         lineCount++;
     }
     else {
         line = test;
     }
 }
 context.fillText(line, x, y);
}
  1. 這一個則是無法在沒有空格的情況下換行,就是換行一定要有空格。這樣的function就幾乎對中文毫無作用,因為中文幾乎不會用到空格。
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;
  }
}

謝謝大家的幫忙

froce iT邦大師 1 級 ‧ 2024-05-18 22:13:23 檢舉
https://jsbin.com/hohobohuwo/edit?html,output

2的wrapText這函式改的,想法就把中文拉出來,每個字都當成英文的一個word去處理就好。
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
純真的人
iT邦大師 1 級 ‧ 2024-05-19 21:39:17
最佳解答

參考自動斷行~

    <style>
        #myCanvas {
            width: 100%;
            max-width: 800px;
            height: 300px;
            border: 1px solid #d3d3d3;
        }
    </style>
    <div align="center">
        <canvas id="myCanvas"></canvas>
        <p><textarea cols="40" rows="5">測試測試測試測試</textarea></p>
        <p><button id="test">變更繪圖</button></p>
    </div>
    <script>
        CanvasRenderingContext2D.prototype.wrapText = function (clientWidth, text, x, y, maxWidth, lineHeight) {
            if (typeof text != 'string' || typeof x != 'number' || typeof y != 'number') {
                return;
            }

            var context = this;
            var canvas = context.canvas;

            if (typeof maxWidth == 'undefined') {
                maxWidth = (canvas && canvas.width) || clientWidth;
            }
            if (typeof lineHeight == 'undefined') {
                lineHeight = (canvas && parseInt(window.getComputedStyle(canvas).lineHeight)) || parseInt(window.getComputedStyle(document.body).lineHeight);
            }

            var arrText = text.split('');
            var line = '';

            for (var n = 0; n < arrText.length; n++) {
                var testLine = line + arrText[n];

                var metrics = context.measureText(testLine);
                var testWidth = metrics.width;
                if (arrText[n] == "\\" && arrText[n + 1] == "n") {
                    context.fillText(line, x, y);
                    n += 2;
                    line = arrText[n];
                    y += lineHeight;
                } else if (arrText[n].charCodeAt(0) == 10) {
                    context.fillText(line, x, y);
                    n += 1;
                    line = arrText[n];
                    y += lineHeight;
                } else {
                    if (testWidth > maxWidth && n > 0) {
                        context.fillText(line, x, y);
                        line = arrText[n];
                        y += lineHeight;
                    } else {
                        line = testLine;
                    }
                }
            }
            context.fillText(line, x, y);
        };

        var textarea = document.querySelector('textarea');
        var button = document.getElementById("test");

        var myCanvas = document.getElementById("myCanvas");
        var context = myCanvas.getContext('2d');
        context.font = '16px sans-serif';
        context.textBaseline = 'top';

        button.addEventListener('click', function () {
            context.clearRect(0, 0, myCanvas.width, myCanvas.height);
            context.wrapText(myCanvas.clientWidth, textarea.value, 0, 5);
        });
        window.addEventListener('resize', function () {
            context.clearRect(0, 0, myCanvas.width, myCanvas.height);
            context.wrapText(myCanvas.clientWidth, textarea.value, 0, 5);
        });
        textarea.addEventListener('keyup', function () {
            context.clearRect(0, 0, myCanvas.width, myCanvas.height);
            context.wrapText(myCanvas.clientWidth, textarea.value, 0, 5);
        });
        button.click();
    </script>


參考網址:
https://www.zhangxinxu.com/wordpress/2018/02/canvas-text-break-line-letter-spacing-vertical/

應需求~加上\n及按下斷行@@
還有我再把程式碼稍微優化調整了一下...
froce

froce iT邦大師 1 級 ‧ 2024-05-20 10:50:34 檢舉

這個只有超出長度換行吧?他要的除了遇到\n換行,還有像word的自動換行。

froce
所謂的 \n換行 以及 word的自動換行(按下Enter)嗎
我更新程式碼了~/images/emoticon/emoticon06.gif

謝謝你

我要發表回答

立即登入回答