6

offsetWidth() と measureText のベンチマークを行ったところ、大幅に異なる値が得られました。それらは同じであるべきではありませんか?なぜ違うのですか?

以下はjsfiddleと生のコードです: http://jsfiddle.net/WhGk7/2/

<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<span id="visibilityHack" style="visibility: hidden; font: 15px Arial;">textAlign=start</span>
<div id="results"></div>

<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

// Create a red line in position 150
ctx.strokeStyle="red";
ctx.moveTo(150,20);
ctx.lineTo(150,170);
ctx.stroke();
var measureTextWidth = ctx.measureText("textAlign=start").width;
var measureTextNode =  document.createTextNode("measureTextWidth: " + measureTextWidth);
document.getElementById("results").appendChild(measureTextNode);

var swidth = document.getElementById("visibilityHack").offsetWidth;
var textnode = document.createTextNode("     offsetWidth: " + swidth);
document.getElementById("results").appendChild(textnode);


ctx.font="15px Arial";    

// Show the different textAlign values
ctx.textAlign="start";      
ctx.fillText("textAlign=start",117,60);        
ctx.textAlign="center";     
ctx.fillText("textAlign=start",150,120);
</script>
4

4 に答える 4

9

context.measureTextのサポートは、ほとんどのブラウザで非常に悪いです。しかし、テキストをより正確に測定できるハックがあります。<div>HTML ドキュメントにノードを作成しますvisibility: hidden(レンダリングされないため) ではなくdisplay: none(スペースを占有するため)。次に、そのスタイルを使用したい同じスタイルに設定しcontext.fillText(外部フォントを使用する場合、正確な測定値を得るにはそのフォントを完全にロードする必要があることに注意してください)、テキストをdivに入れ、divの.width

于 2013-09-10T08:19:27.443 に答える
9

measureText を実行する前に、キャンバス コンテキストでフォントを設定する必要があります。そうしないと、コンテキストのデフォルトのフォント スタイルが何であれ取得されます。ハック div でフォント ファミリとサイズを既に設定しているため、正しい値が得られます。

私が観察したことは、Chrome 34 と Firefox 28 の両方が幅に対して 92 を返しましたが、IE10 は 95、Grrr を返したことです。

于 2014-04-14T19:07:20.780 に答える
6

Canvas のサポートは、以前はあまり正確ではありませんでした。

2014 年 11 月現在、ほとんどのブラウザーは問題なく動作しているようです。テスト済みの Chrome、IE、および Firefox。Canvas.measureTextまた、ほとんどのブラウザーの機能では、サブピクセル精度の結果が得られることにも注意してください。このフィドルを参照してください。

独自に作成する手間を省くために、既存の string-measuring function を使用することをお勧めします

于 2014-11-28T06:20:36.190 に答える
1

measureText と "DOM element method" の両方がまだ実際のテキスト幅を返していないようです。しかし、context2d.measureText と「OM 要素メソッド」は非常に似た値を返します:) 'y' という 1 文字で構成され、'italic 90px arial' で印刷されたテキストの幅を測定してみましょう。JSFiddleで試すことができます-ドミのコードを変更しましたhttp://jsfiddle.net/White_Falkon/a23z6ryL/2/

/**
 * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
 * 
 * @param text The text to be rendered.
 * @param {String} font The css font descriptor that text is to be rendered with (e.g. "14px verdana").
 * 
 * @see http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
 */
function getTextWidth(text, font) {
    // if given, use cached canvas for better performance
    // else, create new canvas
    var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.getElementById("myCanvas"));
    var context = canvas.getContext("2d");
    var oldFont = context.font;
    context.font = font;
    var metrics = context.measureText(text);
    context.font = oldFont;
    return metrics.width;
};

function getTextWidthDOM(text, font) {
  var f = font || '12px arial',
      o = $('<span>' + text + '</span>')
            .css({'font': f, 'float': 'left', 'white-space': 'nowrap'})
            //.css({'visibility': 'hidden'})
            .appendTo($('body')),
      w = o.width();

  o.remove();

  return w;
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
var x = canvas.width / 2;
var y = canvas.height / 2 - 100;
var text = 'y';
var font = 'italic 90px Arial';

context.font = font;
context.fillStyle = 'blue';    
context.fillText(text, x, y);      
// get text metrics
var widthUsingDOM = getTextWidthDOM(text, font);
var widthUsingMeasureText = getTextWidth(text, font);

context.font = '20pt Calibri';
context.textAlign = 'center';
context.fillStyle = 'red';
context.fillText('(' + widthUsingDOM + 'px wide using DOM)', x, y + 100);
context.fillStyle = 'green';
context.fillText('(' + widthUsingMeasureText + 'px wide using measureText)', x, y + 150);

context.beginPath();
context.rect(x, y-75, widthUsingDOM, 125);
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
context.beginPath();
context.rect(x, y-75, widthUsingMeasureText, 125);
context.lineWidth = 1;
context.strokeStyle = 'green';
context.stroke();

右側の「y」の部分が「幅の長方形」の外側にあることがわかります。これらの測定方法が正しくない別のケースとして、'y' が 'italic 90px times new roman' で印刷されている場合があります。y の左側の部分は、幅の長方形の外側にあります。同じ JSFiddle で試すことができます。

残念ながら、文字列の全幅を測定する方法があるかどうかはわかりません。

于 2014-11-29T13:05:41.360 に答える