加载中…
个人资料
陈在真Sunny_chen
陈在真Sunny_chen
  • 博客等级:
  • 博客积分:0
  • 博客访问:208,205
  • 关注人气:183
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

仿google canvas霜冻效果

(2012-03-27 15:11:22)
标签:

javascript

霜冻

google

合成

let

it

snow

frozen

path

arc

鼠标事件

画布

分类: Canvas
在去年圣诞节前后,在google打let it snow会下雪,而且伴随着一个霜冻效果,按下鼠标拖动还可以擦除霜冻,很神奇,当时只是在看JS,所以就模仿了一个《javascript 雪花飘落效果》,canvas完全没看所以没做霜冻效果出来,最近买了本《html5 canvas基础教程》外加看了网上一些文章,有点感觉,有点思路,这两天刚入职,还没有项目做,就写这个效果出来,因为当时没保存,所以也只是凭记忆写这个东西,如果有不像或者哪里少的,那是本人记忆力衰退,技术水平有限所致,望能见谅哈...

你可以通过这个链接,下载我的源代码:《仿google canvas霜冻效果

为方便下载,提供本人网盘帐号密码,请不要弄乱里面的页面,以方便其它人下载,谢谢。

帐号:287019674@qq.com

密码:123456


以下是对代码的简单分析:

里面有两个简单的构造函数:shape跟frozen

frozen构造出来的实例可以用来实现霜冻
shape构造出来的实例可以用来擦除霜冻

这里直接调用frosting函数,当页面载入的时候直接霜冻,利用setInterval来构造frozen实例,产生霜冻粒子,然后再调用粒子的frost方法,把它们画到canvas上,一个基本的程序流程。

function frozen(x,y,width,height,time,radius){}

frozen是在一个区域,如图:

仿google <wbr>canvas霜冻效果

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,在擦除的时候也会继承这个属性,所以擦除的时候,边界同样很柔和,感觉挺舒服的哈。

基本上就是这样一个思路,希望你会喜欢...欢迎关注我的博客,当我看了某本书某论坛某帖子某文章拆了某网站之后有所感慨,都会写出来跟大家一起分享,希望能多些交流,共同进步...




0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有