1

私がやろうとしているのは、キャンバス要素の真ん中に複数行のテキストを表示することです。ユーザーがテキスト ボックスを使用してテキストを入力すると、テキストは動的になり、ユーザーが入力したテキストでキャンバスが更新されます (以下に示すコード)。CSS で vertical-align: middle プロパティを使用してテキストを表示する方法と同様の方法でテキストをキャンバスに表示したいと考えています。私の質問は、この問題にアプローチする最も簡単な方法は何かということです。

私が抱えている大きな問題は、ユーザーがフォントを変更できることです。フォントが異なれば高さも異なるため (たとえそれらが px の高さで定義されていても、一貫してその高さではありません)。これまでのところ、キャンバス上のテキストの高さを計算するのが最善のアイデアです。サイトでこの記事を読みました HTML キャンバス上のテキストの高さをどのように見つけることができますか? 、ダニエルによる2番目の回答を参照してください。これにより、テキストの実際の高さが計算され、これを使用してテキストの正しい開始位置が計算され、キャンバスの中央に配置されます。以下のコードに基づいて、基本的に同様のコードを実行して、フォントの正しい開始位置を事前に決定する必要があると思います。

これは、キャンバス上のテキストを適切にラップして表示するための私のアプローチです。

    function wrapText(context, text, x, y, maxWidth, lineHeight) {
    //manage carriage return
    text = text.replace(/(\r\n|\n\r|\r|\n)/g, "\n");
    //manage tabulation
    text = text.replace(/(\t)/g, "    "); // I use 4 spaces for tabulation, but you can use anything you want
    //array of lines
    var sections = text.split("\n"); 

     for (s = 0, len = sections.length; s < len; s++) {
          var words = sections[s].split(' ');
          var line = '';

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

         //new line for new section of the text
         y += lineHeight;
      }
}

      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
      var maxWidth = 350;
      var lineHeight = 25;
      var x = (canvas.width - maxWidth) / 2;
      var y = 60;
      var text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industry's standard dummy text ever since the 1500s.";

      context.font = '14pt Verdana';
      context.fillStyle = '#000';

      wrapText(context, text, x, y, maxWidth, lineHeight); 

問題を単純化する、私が考慮していない別のアプローチがあるかどうか、またはこのアプローチが最善の方法であるかどうか疑問に思っていますか? CSS と同様に、canvas 要素でテキストを垂直方向に配置する簡単な方法はありますか?

4

3 に答える 3

3

涼しい!

私はあなたの参考文献を見ました:HTMLキャンバス上のテキストの高さをどのように見つけることができますか?

キャンバスを実際に使用してテキストの下限と上限をピクセルチェックするPrestaul の回答の時間テストを設定しました。私のテストでは、彼の小さな/大きな「gM」の代わりに、すべての大文字と小文字 (az と AZ) を使用しました。また、DOM に追加していない JS で作成されたキャンバスも使用しました。

結果: テストを毎秒 900 +/- 回繰り返し実行できました。

測定のために DOM 要素を操作する Daniel のテストは実行しませんでしたが、 Prestaulの 1+ ミリ秒 (!) の結果よりも遅いと思います。

私の結論は、ユーザーがフォントを変更するたびに Prestaul の方法を使用して max-height をテストするということです。

個人的には、DOM のハッキングはうまくいくかもしれませんが、私には、ブラウザーの更新後にいつか爆弾が入っているかもしれないブラック ボックスを使用しているように感じます。

私の好奇心を働かせてくれてありがとう - 私はそれを楽しんだ!

[ストレステスト用のコードを含めるように編集]

ストレス テストと Fiddle のコードは次のとおりです: http://jsfiddle.net/m1erickson/ttsjq/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; padding:50px; }
</style>

<script>
$(function(){

    var canvas=document.createElement("canvas");
    canvas.width=1000;
    canvas.height=50;
    var ctx=canvas.getContext("2d");

    function measureTextHeight(left, top, width, height,text) {

        // Draw the text in the specified area
        ctx.save();
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.fillText(text, 0, 35); // This seems like tall text...  Doesn't it?
        ctx.restore();

        // Get the pixel data from the canvas
        var data = ctx.getImageData(left, top, width, height).data,
            first = false, 
            last = false,
            r = height,
            c = 0;

        // Find the last line with a non-white pixel
        while(!last && r) {
            r--;
            for(c = 0; c < width; c++) {
                if(data[r * width * 4 + c * 4 + 3]) {
                    last = r;
                    break;
                }
            }
        }

        // Find the first line with a non-white pixel
        while(r) {
            r--;
            for(c = 0; c < width; c++) {
                if(data[r * width * 4 + c * 4 + 3]) {
                    first = r;
                    break;
                }
            }

            // If we've got it then return the height
            if(first != r) return last - first;
        }

        // We screwed something up...  What do you expect from free code?
        return 0;
    }

    ctx.font='32px Arial';
    var start = new Date().getTime();
    var text="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    for(var x=0;x<1000;x++){
      var height = measureTextHeight(0, 0, canvas.width, canvas.height,text);
    }
    console.log(measureTextHeight(0, 0, canvas.width, canvas.height,text));
    console.log((new Date().getTime()-start));



}); // end $(function(){});
</script>

</head>

<body>
    <div>Stress testing Prestaul's measureTextHeight function...</div>
</body>
</html>
于 2013-03-23T05:14:32.897 に答える