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

在进行 measureText 之前,您需要在画布上下文中设置字体,否则您将获得上下文中的默认字体样式。您已经在 hack div 上设置了字体系列和大小,这就是它为您提供正确值的原因。

我观察到的是 Chrome 34 和 Firefox 28 都返回 92 的宽度,但 IE10 返回 95,Grrr。

于 2014-04-14T19:07:20.780 回答
9

在大多数浏览器中,对context.measureText的支持非常糟糕。但是有一个技巧可以让您更好地测量文本。<div>在您的 HTML 文档中创建一个节点visibility: hidden(因此它不会被渲染)但不是display: none(因此它占用空间)。然后将其样式设置为您要使用的相同样式context.fillText(请记住,当您使用外部字体时,该字体必须完全加载才能获得准确的测量值),将您的文本放入 div,并检查 div 的.width

于 2013-09-10T08:19:27.443 回答
6

过去,画布支持不太准确。

截至 2014 年 11 月,大多数浏览器似乎都可以正常工作。测试了 Chrome、IE 和 Firefox。另请注意,大多数浏览器的Canvas.measureText功能甚至会产生亚像素精度的结果。请参阅此小提琴以供参考。

为了省去您自己编写的麻烦,您可能需要使用现有的字符串测量函数

于 2014-11-28T06:20:36.190 回答
1

似乎 measureText 和“DOM 元素方法”仍然没有返回真实的文本宽度。但是 context2d.measureText 和“OM 元素方法”返回的值非常相似 :) 让我们尝试测量由单个字符 'y' 组成并用 'italic 90px arial' 打印的文本的宽度。你可以在 JSFiddle 上试试——我修改了 Domi 的代码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”打印为“斜体 90px 乘以新罗马” - y 的左侧部分在宽度矩形之外。您可以在同一个 JSFiddle 上试用它。

不幸的是,我不知道是否有办法测量字符串的全宽。

于 2014-11-29T13:05:41.360 回答