仿google canvas霜冻效果
(2012-03-27 15:11:22)
标签:
javascript霜冻合成letitsnowfrozenpatharc鼠标事件画布源 |
分类: Canvas |
在去年圣诞节前后,在google打let it
snow会下雪,而且伴随着一个霜冻效果,按下鼠标拖动还可以擦除霜冻,很神奇,当时只是在看JS,所以就模仿了一个《javascript 雪花飘落效果》,canvas完全没看所以没做霜冻效果出来,最近买了本《html5
canvas基础教程》外加看了网上一些文章,有点感觉,有点思路,这两天刚入职,还没有项目做,就写这个效果出来,因为当时没保存,所以也只是凭记忆写这个东西,如果有不像或者哪里少的,那是本人记忆力衰退,技术水平有限所致,望能见谅哈...
你可以通过这个链接,下载我的源代码:《仿google canvas霜冻效果》
以下是对代码的简单分析:
里面有两个简单的构造函数:shape跟frozen
frozen构造出来的实例可以用来实现霜冻
shape构造出来的实例可以用来擦除霜冻
这里直接调用frosting函数,当页面载入的时候直接霜冻,利用setInterval来构造frozen实例,产生霜冻粒子,然后再调用粒子的frost方法,把它们画到canvas上,一个基本的程序流程。
function frozen(x,y,width,height,time,radius){}
frozen是在一个区域,如图:
frozen实际上是一个区域,x表示区域的起点横坐标,y表示区域的起点纵坐标,width表示表示区域的宽度,height表示区域的高度,time本来想用来搞霜冻粒子的生命,不过算啦,这个很明显是多余的,radius表示霜冻粒子的半径。
frozen.prototype.frost=function(){
ctx.fillStyle="rgba(255,255,255,0.35)";
ctx.shadowBlur=5;
ctx.shadowColor="rgba(255,255,255,1)";
ctx.beginPath();
ctx.arc(
Math.random()*this.width+this.x,Math.random()*this.height+this.y,this.radius,0,Math.PI*2,false);
ctx.closePath();
ctx.fill();
}
这是把霜冻粒子画到画布的方法:
先定义粒子的填充样式为白色透明度0.35,有个白色5px投影,让粒子的边界柔和些,然后就用弧线arc方法在画布上画出一个霜冻粒子的路径,然后填充样式。
其中X的计算Math.random()*this.width+this.x,意思就是在x<粒子圆心的横坐标<width+x,Y的计算同理,目的是让产生的粒子在定义的虚线矩形内。
我记得当时霜冻是由上至下的,所以才会定义这样一个区域产生的方式,这样就可以控制粒子产生的位置,让他们由上至下的产生。
if(!(time0)){
y+=15; height+=15;
}
time++;
(new frozen(x,y,width,height,time,Math.random()*5+20)).frost();
这里用time计算粒子的数目,其实用count比较合适,算啦,都写了,懒得改,玩玩而已哈...当粒子是130的倍数时候就把y+=15; height+=15;把框住霜冻粒子的矩形向下拉15个像素;也就是说,我在一个(0,0,1000,20)的frozen区域内放了130个霜冻粒子,然后再往下(0,15,1000,35)的frozen区域放130个霜冻粒子,一直往下放,直到到达某一个高度后停止
if(height>=350){
ctx.clearRect(0,0,1000,700);
ctx.fillStyle="rgba(255,255,255,0.8)";
ctx.fillRect(0,0,1000,700);
clearInterval(timer);
}
清空画布后填充一个透明度为0.8的白色霜冻矩形,停止定时生成霜冻粒子。因为粒子的位置是随机产生的,有可能某些区域盖得过密,有些区域过于稀疏,所以我用这个方法把它们摸平。不过在这里有个现象,就是粒子的产生是一个path对应一个粒子,所以画出来的不同粒子叠加会让不透明度升高,而如果把粒子记录起来,合成到一个path里面再同时fill出来,这样可以让不透明度保持一致,不过这样的计算量过高,我做了之后还出现其他的新问题,所以没用,等以后我把canvas研究深入些后再弄吧。
在完成霜冻效果之后,就绑定鼠标事件,我不记得google那个可不可以在霜冻未完全的时候擦除,但是这样的话,在响应了擦除效果的同时,生成的霜冻粒子也变成了擦除模式,有点纠结,所以我把它设定成霜冻完全后才可以让用户擦除。让画布响应onmousedown、onmouseup、onmousemove事件,用paintFlag记录判断是否鼠标已经按下,如果按下后拖动,则产生shape实例放到clearArray里面,然后调用clean函数。
clearArray.push(new shape(eve.pageX,eve.pageY,30));
clean();
function clean(){
for(var
i=0;i<clearArray.length;i++){
ctx.beginPath();
ctx.arc(clearArray[i].x,clearArray[i].y,clearArray[i].radius,0,Math.PI*2,false);
ctx.closePath();
ctx.globalCompositeOperation="destination-out";
ctx.fill();
}
}
在clean里面做个循环,读出clearArray里面的shape对象,生成对应的path,不过这里我用到了一个画布路径元素的合成操作globalCompositeOperation,把值设置为destination-out,这里的意思是:
以透明度为0.8的白色霜冻矩形为 源,shape对象产生的path为 目标 进行合成,在源中剔除目标,把源给挖空,这样看起来就像是“手指擦除霜冻雾气”的效果,因为前面我有设置了个白色5px投影,即shadowBlur,在擦除的时候也会继承这个属性,所以擦除的时候,边界同样很柔和,感觉挺舒服的哈。
基本上就是这样一个思路,希望你会喜欢...欢迎关注我的博客,当我看了某本书某论坛某帖子某文章拆了某网站之后有所感慨,都会写出来跟大家一起分享,希望能多些交流,共同进步...
你可以通过这个链接,下载我的源代码:《仿google canvas霜冻效果》
为方便下载,提供本人网盘帐号密码,请不要弄乱里面的页面,以方便其它人下载,谢谢。
密码:123456
以下是对代码的简单分析:
里面有两个简单的构造函数:shape跟frozen
frozen构造出来的实例可以用来实现霜冻
shape构造出来的实例可以用来擦除霜冻
这里直接调用frosting函数,当页面载入的时候直接霜冻,利用setInterval来构造frozen实例,产生霜冻粒子,然后再调用粒子的frost方法,把它们画到canvas上,一个基本的程序流程。
function frozen(x,y,width,height,time,radius){}
frozen是在一个区域,如图:
frozen实际上是一个区域,x表示区域的起点横坐标,y表示区域的起点纵坐标,width表示表示区域的宽度,height表示区域的高度,time本来想用来搞霜冻粒子的生命,不过算啦,这个很明显是多余的,radius表示霜冻粒子的半径。
frozen.prototype.frost=function(){
这是把霜冻粒子画到画布的方法:
先定义粒子的填充样式为白色透明度0.35,有个白色5px投影,让粒子的边界柔和些,然后就用弧线arc方法在画布上画出一个霜冻粒子的路径,然后填充样式。
其中X的计算Math.random()*this.width+this.x,意思就是在x<粒子圆心的横坐标<width+x,Y的计算同理,目的是让产生的粒子在定义的虚线矩形内。
我记得当时霜冻是由上至下的,所以才会定义这样一个区域产生的方式,这样就可以控制粒子产生的位置,让他们由上至下的产生。
if(!(time0)){
}
time++;
(new frozen(x,y,width,height,time,Math.random()*5+20)).frost();
这里用time计算粒子的数目,其实用count比较合适,算啦,都写了,懒得改,玩玩而已哈...当粒子是130的倍数时候就把y+=15; height+=15;把框住霜冻粒子的矩形向下拉15个像素;也就是说,我在一个(0,0,1000,20)的frozen区域内放了130个霜冻粒子,然后再往下(0,15,1000,35)的frozen区域放130个霜冻粒子,一直往下放,直到到达某一个高度后停止
if(height>=350){
}
清空画布后填充一个透明度为0.8的白色霜冻矩形,停止定时生成霜冻粒子。因为粒子的位置是随机产生的,有可能某些区域盖得过密,有些区域过于稀疏,所以我用这个方法把它们摸平。不过在这里有个现象,就是粒子的产生是一个path对应一个粒子,所以画出来的不同粒子叠加会让不透明度升高,而如果把粒子记录起来,合成到一个path里面再同时fill出来,这样可以让不透明度保持一致,不过这样的计算量过高,我做了之后还出现其他的新问题,所以没用,等以后我把canvas研究深入些后再弄吧。
在完成霜冻效果之后,就绑定鼠标事件,我不记得google那个可不可以在霜冻未完全的时候擦除,但是这样的话,在响应了擦除效果的同时,生成的霜冻粒子也变成了擦除模式,有点纠结,所以我把它设定成霜冻完全后才可以让用户擦除。让画布响应onmousedown、onmouseup、onmousemove事件,用paintFlag记录判断是否鼠标已经按下,如果按下后拖动,则产生shape实例放到clearArray里面,然后调用clean函数。
clearArray.push(new shape(eve.pageX,eve.pageY,30));
clean();
function clean(){
在clean里面做个循环,读出clearArray里面的shape对象,生成对应的path,不过这里我用到了一个画布路径元素的合成操作globalCompositeOperation
以透明度为0.8的白色霜冻矩形为 源,shape对象产生的path为 目标 进行合成,在源中剔除目标,把源给挖空,这样看起来就像是“手指擦除霜冻雾气”的效果,因为前面我有设置了个白色5px投影,即shadowBlur,在擦除的时候也会继承这个属性,所以擦除的时候,边界同样很柔和,感觉挺舒服的哈。
基本上就是这样一个思路,希望你会喜欢...欢迎关注我的博客,当我看了某本书某论坛某帖子某文章拆了某网站之后有所感慨,都会写出来跟大家一起分享,希望能多些交流,共同进步...