Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
HTML5画布:为什么使用measureText和offsetWidth()测量文本会给出不同的值?_Html_Canvas - Fatal编程技术网

HTML5画布:为什么使用measureText和offsetWidth()测量文本会给出不同的值?

HTML5画布:为什么使用measureText和offsetWidth()测量文本会给出不同的值?,html,canvas,Html,Canvas,我对offsetWidth()和measureText进行了基准测试,得到了截然不同的值。它们不应该是一样的吗?为什么它们不同 下面是JSFIDLE和原始代码: 您的浏览器不支持HTML5画布标记。 text对齐=开始 var c=document.getElementById(“myCanvas”); var ctx=c.getContext(“2d”); //在位置150处创建一条红线 ctx.strokeStyle=“红色”; ctx.moveTo(150,20); ctx.lineT

我对offsetWidth()和measureText进行了基准测试,得到了截然不同的值。它们不应该是一样的吗?为什么它们不同

下面是JSFIDLE和原始代码:


您的浏览器不支持HTML5画布标记。
text对齐=开始
var c=document.getElementById(“myCanvas”);
var ctx=c.getContext(“2d”);
//在位置150处创建一条红线
ctx.strokeStyle=“红色”;
ctx.moveTo(150,20);
ctx.lineTo(150170);
ctx.stroke();
var measureTextWidth=ctx.measureText(“textAlign=start”).width;
var measureTextNode=document.createTextNode(“measureTextWidth:+measureTextWidth”);
document.getElementById(“结果”).appendChild(measureTextNode);
var swidth=document.getElementById(“visibilityHack”).offsetWidth;
var textnode=document.createTextNode(“offsetWidth:+swidth”);
document.getElementById(“结果”).appendChild(textnode);
ctx.font=“15px Arial”;
//显示不同的textAlign值
ctx.textAlign=“开始”;
ctx.fillText(“textAlign=start”,117,60);
ctx.textAlign=“中心”;
ctx.fillText(“textAlign=start”,150120);

大多数浏览器对的支持非常差。但是有一种方法可以让你更好地测量文本。在HTML文档中创建一个
节点,该节点具有
可见性:hidden
(因此不会呈现),但不具有
显示:none
(因此它会占用空间)。然后将其样式设置为要用于
上下文的相同样式。fillText
(请记住,当您使用外部字体时,必须完全加载该字体才能获得准确的测量值),将文本放入div,并检查div的
。在测量text之前,需要在画布上下文上设置字体,否则,您将获得上下文中的默认字体样式。您已经在hack div上设置了字体系列和大小,这就是它为您提供正确值的原因


不过我观察到的是Chrome34和Firefox28都返回了92的宽度,但IE10返回了95,Grrr。

画布支持在过去不太准确

截至2014年11月,大多数浏览器似乎工作正常。测试了Chrome、IE和Firefox。还要注意的是,大多数浏览器的Canvas.measureText
函数甚至产生亚像素精度的结果。供参考


为了省去编写自己的文档的麻烦,measureText和“DOM元素方法”似乎仍然不返回实际的文本宽度。 但是context2d.measureText和“OM元素方法”返回的值非常相似:) 让我们尝试测量由单个字符“y”组成的文本的宽度,并使用“italic 90px arial”打印。您可以在JSFIDLE上尝试它-我修改了Domi的代码

/**
*使用canvas.measureText计算并返回给定字体的给定文本的宽度(以像素为单位)。
* 
*@param text要呈现的文本。
*@param{String}font用于呈现文本的css字体描述符(例如“14px verdana”)。
* 
*@见http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
函数getTextWidth(文本、字体){
//如果给定,请使用缓存画布以获得更好的性能
//否则,创建新画布
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;
返回度量。宽度;
};
函数getTextWidthDOM(文本、字体){
var f=font | |“12px arial”,
o=$(''+文本+'')
.css({'font':f,'float':'left','white space':'nowrap'})
//.css({'visibility':'hidden'})
.appendTo($(“body”),
w=o.宽度();
o、 删除();
返回w;
}
var canvas=document.getElementById('myCanvas');
var context=canvas.getContext('2d');
context.clearRect(0,0,canvas.width,canvas.height);
var x=画布宽度/2;
变量y=画布高度/2-100;
var text='y';
var font='italic 90px Arial';
context.font=font;
context.fillStyle='blue';
填充文本(文本,x,y);
//获取文本度量
var-widthUsingDOM=getTextWidthDOM(文本,字体);
var widthUsingMeasureText=getTextWidth(文本,字体);
context.font='20pt Calibri';
context.textAlign='center';
context.fillStyle='red';
context.fillText(“(“+widthUsingDOM+”px-widthUsingDOM)”,x,y+100);
context.fillStyle='green';
context.fillText(“(“+widthsusingmeasuretext+”px-widthsingmeasuretext)”,x,y+150);
context.beginPath();
rect(x,y-75,宽度使用dom,125);
context.lineWidth=1;
context.strokeStyle='red';
stroke();
context.beginPath();
context.rect(x,y-75,宽度使用measuretext,125);
context.lineWidth=1;
context.strokeStyle='green';
stroke();
你会看到,右边的“y”部分在“宽度矩形”之外。 另一种情况是,当这些测量方法不正确时,用“斜体90px乘以新罗马”打印的“y”-y的左侧部分在宽度矩形之外。您可以在同一个JSFiddle上尝试它


不幸的是,我不知道是否有一种方法可以测量字符串的全宽。

因此,唯一100%准确测量跨浏览器的方法是进行可见性破解?@yoshyosh目前恐怕是这样,但我很高兴听到更好的解决方案,因为我目前正在我的一个项目中使用它,对此我也不太满意(尽管它对我的目的非常有效)。我一直依赖measureText来实现我的word wrap算法,可能不得不改变这一点:(@philippI正在比较measureText和这个可见性黑客的值,它们在Chrome上是完全相同的。所以这并不能解决measureText在不同浏览器上给出不同值的问题。@yoshyosh不需要再使用“可见性黑客”(visibility hack)。实际的
<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>
/**
 * 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();