我对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>
答案 0 :(得分:8)
在大多数浏览器中,对context.measureText的支持非常糟糕。但是有一个hack可以让你更好地测量文本。使用<div>
在HTML文档中创建visibility: hidden
节点(因此不会呈现),但不会display: none
(因此会占用空间)。然后将其样式设置为您要用于context.fillText
的相同样式(请记住,当您使用外部字体时,必须完全加载该字体才能获得准确的测量值),将文本放入div中,然后检查div的.width
答案 1 :(得分:7)
您需要在执行measureText之前在画布上下文中设置字体,否则您将获得上下文中的默认字体样式。您已经在hack div上设置了字体系列和大小,这就是它为您提供正确值的原因。
我所观察到的是Chrome 34和Firefox 28的宽度都返回了92,但IE10返回了95,Grrr。
答案 2 :(得分:5)
Canvas支持过去不太准确。
截至2014年11月,大多数浏览器似乎工作正常。经过测试的Chrome,IE和Firefox。还要注意大多数浏览器&#39; Canvas.measureText
函数甚至可以产生亚像素精度的结果。 See this fiddle供参考。
为了省去编写自己的问题,you might want to use an existing string-measuring function。
答案 3 :(得分:0)
似乎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'部分位于'width rectangle'之外。 另一种情况是,当这些测量方法不正确时,'y'用'斜体90px倍新罗马'打印 - y的左边部分在宽度矩形之外。你可以在同一个JSFiddle上试一试。
不幸的是,我不知道是否有办法测量字符串的全宽。