3

我正在尝试在页面顶部绘制一个巨大的画布矩形(某种灯箱背景),代码非常简单:

var el = document.createElement('canvas');
el.style.position = 'absolute';
el.style.top  = 0;
el.style.left = 0;
el.style.zIndex = 1000;
el.width  = window.innerWidth + window.scrollMaxX;
el.height = window.innerHeight + window.scrollMaxY;

...
document.body.appendChild(el);

// and later

var ctx = el.getContext("2d");
ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
ctx.fillRect(0, 0, el.width, el.height);

有时(并非总是)最后一行抛出:

组件返回失败代码:0x80004005 (NS_ERROR_FAILURE) [nsIDOMCanvasRenderingContext2D.fillRect]

我一直在猜测是否会因为图像大小或画布下方的内容类型(例如嵌入视频播放)而发生这种情况,但显然不是。

因此,我正在寻找有关如何隔离和/或解决此问题的任何想法。

4

2 回答 2

9

查看nsIDOMCanvasRenderingContext2D.fillRect()实现(并通过它调用的函数) - 没有太多的条件会返回NS_ERROR_FAILURE。只有在其中一个EnsureSurface()mThebes->CopyPath()失败的情况下才会发生。以下两行EnsureSurface()很可能是您的问题的根源:

// Check that the dimensions are sane
if (gfxASurface::CheckSurfaceSize(gfxIntSize(mWidth, mHeight), 0xffff)) {

这里检查的内容:

  • 画布的宽度和高度都不能超过 65535 像素。
  • 在 Mac OS X 上高度不能超过 32767 像素(平台限制)。
  • 画布数据 ( width * height * 4) 的大小不能超过 2 GB。

如果违反这些条件中的任何一个,EnsureSurface()将返回false并因此产生您所看到的异常。请注意,以上是可以随时更改的实现细节,您不应依赖它们。但他们可能会让您了解您的代码违反了哪些特定限制。

于 2012-09-28T16:40:32.137 回答
1

您可以应用 try-catch 逻辑。Firefox 似乎是唯一表现得有点奇怪的浏览器。

el.width  = window.innerWidth + window.scrollMaxX;
el.height = window.innerHeight + window.scrollMaxY;

// try first to draw something to check that the size is ok
try
{
  var ctx = el.getContext("2d");
  ctx.fillRect(0, 0, 1, 1);
}

// if it fails, decrease the canvas size
catch(err)
{
  el.width = el.width - 1000;
  el.height = el.height - 1000;
}

我还没有找到任何变量来告诉最大画布大小是多少。它因浏览器和设备而异。

检测最大画布大小的唯一跨浏览器方法似乎是减小画布大小的循环,例如。100px,直到它不产生错误。我测试了一个循环,这是检测最大画布大小的相当快的方法。因为其他浏览器在尝试在过大的画布上绘制时不会抛出错误,所以最好尝试绘制例如。红色矩形并读取一个像素并检查它是否为红色。

为了最大限度地提高检测性能:
- 在循环时,画布应该在 DOM 之外以最大限度地提高速度
- 将起始大小设置为众所周知的最大值,这似乎是 32,767 像素(SO:<canvas> 元素的最大大小
- 你可以创建一个更智能的循环来分叉最大尺寸:例如使用第一个更大的减小步骤(例如 1000 像素),当达到可接受的尺寸时,尝试将尺寸增加 500 像素。如果这是可接受的尺寸,则增加 250 像素,依此类推。这样,应该在最少的试验中找到最大值。

于 2015-06-01T21:17:45.720 回答