临近圣诞,我一直在尝试使用HTML5 canvas在圣诞树图片上面绘制泡泡。由于不知道哪种绘制的方法最好,最终在Stack Overflow上找到了使用radial gradients(辐射渐变)绘制圆圈的答案。
圆圈
你可能已经知道,标准地画圆圈的方法是使用arc()
:
1
2
3
4
5
6
|
// Drawing a circle the traditional way
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2,
true
);
ctx.fillStyle =
'rgba(195, 56, 56, 1)'
;
ctx.fill();
ctx.closePath();
|
以我之见,与SVG的例子相比这种绘制圆圈的方法有点笨重。我认为仅仅使用radial gradients是一种更明智的选择,只是不知道它的性能如何。
1
2
3
4
5
6
|
// Drawing a circle with a radial gradient
var
gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0.95,
'rgba(195, 56, 56, 1)'
);
gradient.addColorStop(1,
'rgba(195, 56, 56, 0)'
);
ctx.fillStyle = gradient;
ctx.fillRect(x - radius, y - radius, x + radius, y + radius);
|
毫无疑问地,使用radial gradients会比arc()
更慢。慢了好几倍!你可以在测试页面尝试下,就可以了解到速度的差距。
如果我正确地思考,我应该意识到这点而不需要去测试它,这样可以节省些时间。但是我接下来尝试使用了球体(当然不是3D地球体,是有色差渐变地圆圈)。
球体
在canvas中有两种通用地方法来绘制球体:
Radial grandients
1
2
3
4
5
6
7
8
|
// Drawing a sphere with radial gradients
var
gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
gradient.addColorStop(0,
'rgba(255, 255, 255, 1)'
);
gradient.addColorStop(0.2,
'rgba(255, 85, 85, 1)'
);
gradient.addColorStop(0.95,
'rgba(128, 0, 0, 1)'
);
gradient.addColorStop(1,
'rgba(128, 0, 0, 0)'
);
ctx.fillStyle = gradient;
ctx.fillRect(x - radius, y - radius, x + radius, y + radius);
|
使用drawImage()绘制边缘颜色与背景色相同(或透明、可以和背景融合)的图片
1
2
3
4
|
// Drawing a sphere with an existing image
var
img =
new
Image();
img.src =
'images/baubles.png'
;
ctx.drawImage(img, x, y, width, height);
|
和之前地例子一样,radial gradients要慢好几倍。当然优势就是radial gradients是可以即时地动态改变,而画图片地方法则需要预先制作好图片。那些图片没办法通过javascript来直接修改,虽然你可以很容易地修改它们显示大小。你也可以通过以下几种方法来控制颜色:
-
使用包含指定颜色图片地图片sprite
-
使用灰度图片,并且使用
arc()
来设置半透明浮层
别忘了,使用图片意味着它们需要被下载,所以记得如果可能预加载图片。
你可以在测试页面上测试下性能。
你可以看到,很明显浮层方法较慢,但是和gradients相比还是快地。在控制颜色方面,它也给了你更多自由,不过所有地方法都要比单纯绘制原始图片要慢。
总结
通常情况下,对于简单地地程序或者是快速地硬件来说,这些速度地差别是很难注意到地。但是如果你在使用动画、制作高性能游戏或是为TV/机顶盒之类地硬件设计程序,那么它们就会成为一个问题了。一如既往,所有的决定都是一种妥协,所以这里列出了各种权衡情况的总结:
-
如果你想要绘制圆圈,使用
arc()
-
如果你想要绘制球体,使用一张图片(预加载它)
-
如果你绘制各种各样的图片,使用图片sprites
-
如果你想要球体可以动态改变颜色,考虑使用一张图片和半透明浮层
-
只有在万不得已的情况下才使用radial gradients
更新:
Marcelo提出了一种很酷的方法:在一个隐藏的canvas上面创建一个简单的图片,然后使用drawImage()
重复绘制它。这种方法避免了创建图片的步骤,并且也可以即时修改颜色。最棒的是,不考虑初始化gradient的时间,它比绘制一张已有的图片还要快!代码如下:
1
2
3
4
5
6
|
// Create a second "buffer" canvas but don't append it to the document
var
tmpCanvas = document.createElement('canvas
');
var tmpCtx = tmpCanvas.getContext('
2d');
// Add the necessary gradients here, as above
// Draw the image from the second "buffer" canvas
ctx.drawImage(tmpCanvas, x, y, width, height);
|
所以,如果你正在绘制很多的圆圈或是球体,我推荐使用这种方法。