用Canvas制作剪纸效果
在做剪纸效果之前,先介绍剪纸效果运用到的一些知识:
阴影
在Canvas之中进行绘制时,可以通过修改绘图环境中的如下4个属性值来指定阴影效果:
- shadowColor:CSS格式的颜色字串。默认值为rgba(0,0,0,0),即完全透明的黑色。
- shadowOffsetX:阴影在X轴方向的偏移量,以像素为单位。默认值为0
- shadowOffsetY:阴影在Y轴方向的偏移量,以像素为单位。默认值为0
- shadowBlur:表示阴影效果如何延伸的double值。默认值为0.该值用于高斯模糊方程中,以便对阴影进行模糊化处理。
如果满足一下条件,那么使用Canvas的绘图环境对象就可以绘制出阴影效果了:
- 指定的shadowColor值不是全透明的。
- 在其余的阴影属性中,存在一个非0的值
不过,通常来说,使用半透明色来绘制阴影是个不错的选择,因为这样一来,背景就可以透过阴影显示出来了。
如果要禁用阴影效果,那就将shadowColor的属性设置为underfined。
如果为shadowOffsetX与shadowOffsetY属性设置了非0的正数值,无论绘制什么内容,它看起来都像是浮在了canvas之上,而且这些属性的值越大,我们就会觉得它在canvas上面浮动的越高。而负偏移量可以用来制作内嵌阴影效果。
非零环绕原则
在介绍非零环绕准则之前,先介绍一下CanvasRenderingContext2D之中与路径有关的arc()方法。arc()方法在当前路径中增加一段表示圆弧或圆形的子路径,可以通过一个boolean参数来控制该段子路径的方向。如果此参数是true,那么arc()所创建的子路径就是顺时针的,否则就是逆时针的。
如果当前路径是循环的,或者包含多个交叉的子路径,那么Canvas的绘图变量就必须要判断。
非零环绕原则指的是对于路径中的任意给定区域,从该区域内部画一条足够长的线段,使此线段的终点完全落在路径范围之外。如图所示,那三个箭头所描述的就是这个步骤。接下来,将计数器初始化为0,然后,每当这条线段与路径上的直线或曲线相交时,就改变计数器的值。如果是与路径的顺时针部分相交,则加1,如果是与路径的逆时针部分相交,则减1。若计数器的最终值不是0,那么此区域就在路径里面,在调用fill()方法时,浏览器就会对其进行填充。如果最终值是0,那么此区域就不在路径内部,浏览器也就不会对其进行填充了。
剪纸效果
如图所示为剪纸效果的图。
剪纸效果由两个圆形组成,其中一个圆形在另一个圆形的内部。通过设定arc()方法的最后一个参数,该程序以顺时针方向绘制了内部的圆形,并且以逆时针方向绘制了外围的圆形。浏览器运用“非零环绕规则”,对外围圆形的内部进行了填充,不过填充的范围并不包括里面的圆,这就产生了一种剪纸图案的效果。
代码如下:
1 var canvas = document.getElementById("canvas"), 2 context = canvas.getContext('2d'); 3 //Function------------------------------------------------- 4 function drawTwoArcs(){ 5 context.beginPath(); 6 context.arc(300,190,150,0,Math.PI*2,false); 7 context.arc(300,190,100,0,Math.PI*2,true); 8 9 context.fill(); 10 context.shadowColor = undefined; 11 context.shadowOffsetX = 0; 12 context.shadowOffsetY = 0; 13 context.stroke(); 14 } 15 function draw(){ 16 context.clearRect(0,0,canvas.width,canvas.height); 17 context.save(); 18 19 context.shadowColor = 'rgba(0,0,0,0.8)'; 20 context.shadowOffsetX = 12; 21 context.shadowOffsetY = 12; 22 context.shadowBlur = 15; 23 24 drawTwoArcs(); 25 context.restore(); 26 } 27 28 //Initialzation--------------------------------------------------------------- 29 context.fillStyle = 'rgba(100,140,230,0.5)'; 30 context.strokeStyle = context.fillStyle; 31 draw();