【美高梅开户网址】小公式大乐趣,编织璀璨星空图

用 Canvas 编织璀璨星空图

2016/05/14 · CSS ·
Canvas,
画布

初稿出处: Cyandev   

先来看看最后的效益:

美高梅开户网址 1

GitHub项目: CyandevToys /
ParticleWeb
是还是不是还蛮酷的吧?本文我们就来一点一点分析怎么落实它!


canvas学习笔记:小公式大乐趣

2014/03/20 · HTML5 · 1
评论 ·
HTML5

原稿出处: WAxes   

近日想弄一个网页,把温馨学HTML5进程中做的部分DEMO放上去做集合,可是,倘诺就一味做个网页把拥有DEMO一个一个排列又觉得太掉价了。就想,既然学了canvas,那就来折腾下浏览器,做个细微开场动画吧。

开场动画的功效,想了一会,决定用粒子,因为觉得粒子相比较好玩。还记得在此从前我写的第一篇技术博文,就是讲文字图片粒子化的:文字图片粒子化 ,
那时就只是做的是直线运动,顺便加了少数3D意义。运动公式很简短。所以就想以此开场动画就做的更饱满一些吗。

先上DEMO:

功效是否比直线的位移更是奋发呢?而且也真的很简短,别忘了那篇博文的难题,小小滴公式,大大滴乐趣。要做出那样的作用,用的就单单是我们初中。。可能高中时候的物理知识,加快移动,减速运动的公式啦。所以的确是小小滴公式。楼主很喜爱折腾一些酷炫的事物,固然大概常常做事上用不上,可是,那乐趣确实很令人着迷啊。而且,做下那几个也可以进步一下编程的思维能力哈。

废话不多说,进入正题啦。就简单的解释一下原理吧~~~

粒子运动的骨干代码就那样一点:

JavaScript

update:function(time){ this.x += this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y; var xc =
this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za = 20; var
ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; }else { var gravity = 9.8; var vy = this.vy+gravity*time;
if(this.y>canvas.height){ vy = -vy*0.7; } this.vy = vy; } },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&&this.y>0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y>canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },

粒子总共有二种情景,一种是自由落体,一种就是受到吸力。自由落体就背着了。说吸力从前先贴出粒子的习性:

JavaScript

var Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y;
this.vx=vx; this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color
= color; this.visible = true; this.globleDown = false; this.setEnd(tox ,
toy); } setEnd:function(tox , toy){     this.tox = tox;
    this.toy = toy;     var yc = this.toy – this.y;     var
xc = this.tox – this.x; },

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
setEnd:function(tox , toy){
    this.tox = tox;
    this.toy = toy;
    var yc = this.toy – this.y;
    var xc = this.tox – this.x;
},

x,y就是粒子的岗位,vx是粒子水平速度,vy是粒子的垂直速度,nexttox之类知道照旧不知道道都不在乎,只是暂时保留变量的。tox,和toy就是粒子的目标地地点。

先是,先予以负有粒子一个目的地,那一个目标地上边再会说。也等于要粒子到达的地点,然后再定义一个变量za作为加快度,具体数值的话,就和好多测试下就会有大体参数的了,我设成20,感觉就基本上了。za是粒子和目标地之间连线的增速度,所以,我们经过粒子的地方和目标地的岗位,通过简单的三角形函数,就足以把粒子的程度加快度和垂直加速度求出来了,就那段

JavaScript

var ax = za*(xc/this.jl), ay = za*(yc/this.jl),

1
2
var ax = za*(xc/this.jl),
  ay = za*(yc/this.jl),

有了档次加快度和垂直加速度后,接下去就更不难了,直接计算水平速度和垂直速度的增量,从而改变程度速度和垂直速度的值

JavaScript

vx = (this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97;

1
2
vx = (this.vx+ax*time)*0.97,
vy = (this.vy+ay*time)*0.97;

为此要乘于0.97是为了模仿能量消耗,粒子才会放慢。time是每一帧的时间差

算算出速度后就立异粒子地点就行了。

JavaScript

【美高梅开户网址】小公式大乐趣,编织璀璨星空图。this.x += this.vx*time; this.y += this.vy*time;

1
2
this.x += this.vx*time;
this.y += this.vy*time;

因为粒子在航空进度中,与目的地之间的连线方向是不停改变的,所以每一帧都要再度计算粒子的品位加快度和垂直加快度。

移步规律就是那样,是不是很不难吗。

运动规律说完了,再扯一下地点万分动画的切实落到实处吗:动画起始化,在一个离屏canvas上把想要的字或许图片画出来,然后再通过getImageData那么些点子赢得离屏canvas的像素。然后用一个循环,把离屏canvas中有绘制的区域找出来,因为imageData里的data值就是一个rgba数组,所以我们判断最后一个的值约等于透明度大于128就是有绘制过的区域。然后拿走该区域的xy值,为了以防粒子对象过多导致页面卡顿,所以大家就限制一下粒子的数量,取像素的时候x值和y值每便递增2,从而减弱粒子数量。

JavaScript

this.osCanvas = document.createElement("canvas"); var osCtx =
this.osCanvas.getContext("2d"); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = "center";
osCtx.textBaseline = "middle"; osCtx.font="70px
微软雅黑,石籀文 bold"; osCtx.fillStyle = "#1D181F"
osCtx.fillText("WelCome" , this.osCanvas.width/2 ,
this.osCanvas.height/2-40); osCtx.fillText("To wAxes'
HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
this.osCanvas = document.createElement(&quot;canvas&quot;);
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = &quot;center&quot;;
        osCtx.textBaseline = &quot;middle&quot;;
        osCtx.font=&quot;70px 微软雅黑,黑体 bold&quot;;
        osCtx.fillStyle = &quot;#1D181F&quot;
        osCtx.fillText(&quot;WelCome&quot; , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText(&quot;To wAxes&#039; HOME&quot; , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                    var dot = new Dot(
                        Math.random()&gt;0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }

通过轮回获取到粒子的职位xy值后,把岗位赋给粒子,成为粒子的目标地。然后动画起首,就能够做出文字图片粒子化的作用了。

下边贴出动画完毕的js代码。假使对其他代码也有趣味的,可以一贯看控制台哈,没压缩的。

JavaScript

var part_1 = (function(w){ var dots = [],DOT_SIZE = 2,cube=null; var
Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y; this.vx=vx;
this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color = color;
this.visible = true; this.globleDown = false; this.setEnd(tox , toy); }
Dot.prototype = { paint:function(){ ctx.fillStyle=this.color;
ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE ,
DOT_SIZE); }, setEnd:function(tox , toy){ this.tox = tox; this.toy =
toy; var yc = this.toy – this.y; var xc = this.tox – this.x; //
this.initjl = Math.sqrt(xc*xc+yc*yc); }, update:function(time){ this.x
+= this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y;
var xc = this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za =
20; var ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; //
if(Math.abs(this.vx)<1&&Math.abs(this.vy)<1){ // this.y =
this.toy // this.x = this.tox // } }else { var gravity = 9.8; var vy =
this.vy+gravity*time; if(this.y>canvas.height){ vy = -vy*0.7; }
this.vy = vy; } }, loop:function(time){ this.update(time); this.paint();
} } var animate = function(){ this.state = "before" } var ap =
animate.prototype; ap.init = function(){ this.osCanvas =
document.createElement("canvas"); var osCtx =
this.osCanvas.getContext("2d"); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = "center";
osCtx.textBaseline = "middle"; osCtx.font="70px
微软雅黑,草书 bold"; osCtx.fillStyle = "#1D181F"
osCtx.fillText("WelCome" , this.osCanvas.width/2 ,
this.osCanvas.height/2-40); osCtx.fillText("To wAxes'
HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }
console.log(dots.length) } ap.changeState = function(){ var osCtx =
this.osCanvas.getContext("2d");
osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
this.osCanvas.width = 460; this.osCanvas.height = 100;
osCtx.fillStyle="#5C5656" osCtx.fillRect(20,20,60,60)
drawLogo(this.osCanvas , osCtx); var bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); var
index=0; dots.sort(function(a , b){ return Math.random()-Math.random();
}) for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var d = dots[index];
if(d){ d.setEnd(x+(canvas.width/2-300) , y+50) d.color =
"rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)";
index++ } } } } setTimeout(function(){ var endindex = index; for(var
i=0;i<dots.length-endindex;i++){ if(dots[index]){ var d =
dots[index]; d.globleDown = true; d.vx = Math.random()*100-50; }
index++; } } , 2000) } function endState(){ canvas.width = 600;
canvas.height = 100; canvas.style.display="block";
canvas.style.top = "50px"; canvas.style.left =
(window.innerWidth-canvas.width)/2+"px"; cube = new Cube(50);
cube._initVector(50,50); } function drawLogo(canvas , ctx){
ctx.textAlign = "center"; ctx.textBaseline =
"middle"; ctx.font="65px 微软雅黑,石籀文 bold"
ctx.fillStyle="#E06D2F" ctx.fillText("DEMO" , 300 ,
canvas.height/2) ctx.font="40px 微软雅黑,陶文 bold"
ctx.fillStyle="#405159" ctx.fillText("吖猩的" , 160
, canvas.height/2) ctx.fillText("小窝" , 420 ,
canvas.height/2) } var num = 0; ap.update = function(time){ time =
time/100;
if(this.state==="first"||this.state==="before"){ var
completeNum = 0; dots.forEach(function(dot){ if(dot.visible)
dot.loop(time); if(dot.jl<5){ completeNum++ } });
if(completeNum>=5*dots.length/6){
if(this.state==="before"){ this.state = "first";
dots.forEach(function(dot){ dot.setEnd(dot.nextox , dot.nextoy); });
}else { this.state = "second"; this.changeState(); } } }else
if(this.state==="second"){ var completeNum = 0, allnum = 0;
dots.forEach(function(dot){ if(dot.visible) dot.loop(time);
if(dot.globleDown){ allnum++; if(Math.abs(dot.y-canvas.height)<2){
completeNum++ } } }); if(completeNum===allnum&&allnum!==0){
this.state = "third"; part_2.animate(); endState(); } }else
if(this.state==="third"){ cube.update(); drawLogo(canvas ,
ctx); } } return new animate(); })(window)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
var part_1 = (function(w){
    var dots = [],DOT_SIZE = 2,cube=null;
 
    var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
    Dot.prototype = {
        paint:function(){
            ctx.fillStyle=this.color;
            ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE , DOT_SIZE);
        },
 
        setEnd:function(tox , toy){
            this.tox = tox;
            this.toy = toy;
            var yc = this.toy – this.y;
            var xc = this.tox – this.x;
            // this.initjl = Math.sqrt(xc*xc+yc*yc);
        },
 
        update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&amp;&amp;this.y&gt;0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
                // if(Math.abs(this.vx)&lt;1&amp;&amp;Math.abs(this.vy)&lt;1){
                //     this.y = this.toy
                //     this.x = this.tox
                // }
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y&gt;canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },
 
        loop:function(time){
            this.update(time);
            this.paint();
        }
    }
 
    var animate = function(){
        this.state = &quot;before&quot;
    }
 
    var ap = animate.prototype;
 
    ap.init = function(){
        this.osCanvas = document.createElement(&quot;canvas&quot;);
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = &quot;center&quot;;
        osCtx.textBaseline = &quot;middle&quot;;
        osCtx.font=&quot;70px 微软雅黑,黑体 bold&quot;;
        osCtx.fillStyle = &quot;#1D181F&quot;
        osCtx.fillText(&quot;WelCome&quot; , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText(&quot;To wAxes&#039; HOME&quot; , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                    var dot = new Dot(
                        Math.random()&gt;0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }
        console.log(dots.length)
    }
 
    ap.changeState = function(){
        var osCtx = this.osCanvas.getContext(&quot;2d&quot;);
        osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
        this.osCanvas.width = 460;
        this.osCanvas.height = 100;
 
        osCtx.fillStyle=&quot;#5C5656&quot;
        osCtx.fillRect(20,20,60,60)
 
        drawLogo(this.osCanvas , osCtx);
 
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        var index=0;
        dots.sort(function(a , b){
            return Math.random()-Math.random();
        })
        for(var x=0;x&lt;bigImageData.width;x+=2){
            for(var y=0;y&lt;bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]&gt;128){
                        var d = dots[index];
                        if(d){
                            d.setEnd(x+(canvas.width/2-300) , y+50)
                            d.color = &quot;rgba(&quot;+bigImageData.data[i]+&quot;,&quot;+bigImageData.data[i+1]+&quot;,&quot;+bigImageData.data[i+2]+&quot;,1)&quot;;
                            index++
                        }
                }
            }
        }
 
        setTimeout(function(){
            var endindex = index;
            for(var i=0;i&lt;dots.length-endindex;i++){
                if(dots[index]){
                    var d = dots[index];
 
                    d.globleDown = true;
                    d.vx = Math.random()*100-50;
                }
                index++;
            }
        } , 2000)
    }
 
    function endState(){
        canvas.width = 600;
        canvas.height = 100;
        canvas.style.display=&quot;block&quot;;
        canvas.style.top = &quot;50px&quot;;
        canvas.style.left = (window.innerWidth-canvas.width)/2+&quot;px&quot;;
        cube = new Cube(50);
        cube._initVector(50,50);
    }
 
    function drawLogo(canvas , ctx){
        ctx.textAlign = &quot;center&quot;;
        ctx.textBaseline = &quot;middle&quot;;
        ctx.font=&quot;65px 微软雅黑,黑体 bold&quot;
        ctx.fillStyle=&quot;#E06D2F&quot;
        ctx.fillText(&quot;DEMO&quot; , 300 , canvas.height/2)
 
        ctx.font=&quot;40px 微软雅黑,黑体 bold&quot;
        ctx.fillStyle=&quot;#405159&quot;
        ctx.fillText(&quot;吖猩的&quot; , 160 , canvas.height/2)
        ctx.fillText(&quot;小窝&quot; , 420 , canvas.height/2)
    }
 
    var num = 0;
    ap.update = function(time){
        time = time/100;
        if(this.state===&quot;first&quot;||this.state===&quot;before&quot;){
            var completeNum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.jl&lt;5){
                    completeNum++
                }
            });
            if(completeNum&gt;=5*dots.length/6){
 
                if(this.state===&quot;before&quot;){
                    this.state = &quot;first&quot;;
                    dots.forEach(function(dot){
                        dot.setEnd(dot.nextox , dot.nextoy);
                    });
                }else {
                    this.state = &quot;second&quot;;
                    this.changeState();
                }
            }
        }else if(this.state===&quot;second&quot;){
            var completeNum = 0,
                allnum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.globleDown){
                    allnum++;
                    if(Math.abs(dot.y-canvas.height)&lt;2){
                        completeNum++
                    }
                }
            });
 
            if(completeNum===allnum&amp;&amp;allnum!==0){
                this.state = &quot;third&quot;;
                part_2.animate();
                endState();
            }
        }else if(this.state===&quot;third&quot;){
            cube.update();
            drawLogo(canvas , ctx);
        }
    }
 
    return new animate();
})(window)

赞 1 收藏 1
评论

美高梅开户网址 2

初稿出处: WAxes   

备考:本文前面的代码,若是加载了ball.js,那么请使用那篇小说[js高手之路]
html5 canvas动画教程 –
匀速运动的ball.js代码.

分析

第一大家看看这么些功用具体有那个要点。首先,这么炫酷的职能一定是要用到
Canvas
了,各个星星可以看作为一个粒子,由此,整个效能其实就是粒子系统了。其余,我们得以窥见每种粒子之间是相互连接的,只但是离的近的粒子之间的连线较粗且透明度较低,而离的远的则相反。

前不久想弄一个网页,把自身学HTML5历程中做的片段DEMO放上去做集合,可是,假设就只是做个网页把持有DEMO一个一个排列又以为太丢人了。就想,既然学了canvas,那就来折腾下浏览器,做个细微开场动画吧。

分界反弹:

开始 Coding

开场动画的意义,想了一会,决定用粒子,因为觉得粒子比较好玩。还记得以前我写的第一篇技术博文,就是讲文字图片粒子化的:文字图片粒子化 ,
那时就唯有做的是直线运动,顺便加了一些3D功能。运动公式很不难。所以就想以此开场动画就做的更饱满一些吗。

当小球遭逢canvas的七个方向的时候,保持地点不变,把速度变成相反的样子

HTML 部分

这有的自己就大约放了一个 “ 标签,设置样式使其填写全屏。

<canvas height=”620″ width=”1360″ id=”canvas” style=”position:
absolute; height: 100%;”/>

1
<canvas height="620" width="1360" id="canvas" style="position: absolute; height: 100%;"/>

下一场为了让拥有因素没有距离和内补,我还加了一条全局样式:

* { margin: 0; padding: 0; }

1
2
3
4
    * {
      margin: 0;
      padding: 0;
    }

先上DEMO:

 1 <head>
 2     <meta charset='utf-8' />
 3     <style>
 4         #canvas {
 5             border: 1px dashed #aaa;
 6         }
 7     </style>
 8     <script src="./ball.js"></script>
 9     <script>
10         window.onload = function () {
11             var oCanvas = document.querySelector("#canvas"),
12                 oGc = oCanvas.getContext('2d'),
13                 width = oCanvas.width, height = oCanvas.height,
14                 ball = new Ball(width / 2, height / 2),
15                 vx = Math.random() * 2 + 5,
16                 vy = Math.random() * 2 + 5;
17             ball.fill(oGc);
18             ( function move(){
19                 oGc.clearRect( 0, 0, width, height );
20                 ball.x += vx;
21                 ball.y += vy;
22                 ball.fill( oGc );
23 
24                 if ( ball.x < ball.radius ) { //碰到左边的边界
25                     ball.x = ball.radius;
26                     vx = -vx;
27                 }else if ( ball.y < ball.radius ){
28                     ball.y = ball.radius;
29                     vy = -vy;
30                 }else if ( ball.x > width - ball.radius ){
31                     ball.x = width - ball.radius;
32                     vx = -vx;
33                 }else if ( ball.y > height - ball.radius ){
34                     ball.y = height - ball.radius;
35                     vy = -vy;
36                 }
37                 requestAnimationFrame( move );
38             } )();
39         }
40     </script>
41 </head>
42 
43 <body>
44     <canvas id="canvas" width="1200" height="600"></canvas>
45 </body>

JavaScript 部分

上面大家来写大旨的代码。首先我们要获取那一个 canvas 并拿走绘制上下文:

var canvasEl = document.getElementById(‘canvas’); var ctx =
canvasEl.getContext(‘2d’); var mousePos = [0, 0];

1
2
3
var canvasEl = document.getElementById(‘canvas’);
var ctx = canvasEl.getContext(‘2d’);
var mousePos = [0, 0];

跟着大家评释多个变量,分别用于存储“星星”和边:

var nodes = []; var edges = [];

1
2
var nodes = [];
var edges = [];

下一步,大家做些准备干活,就是让画布在窗口大小发生变化时再一次绘制,并且调动自我分辨率:

window.onresize = function () { canvasEl.width =
document.body.clientWidth; canvasEl.height = canvasEl.clientHeight; if
(nodes.length == 0) { constructNodes(); } render(); };
window.onresize(); // trigger the event manually.

1
2
3
4
5
6
7
8
9
10
11
12
window.onresize = function () {
    canvasEl.width = document.body.clientWidth;
    canvasEl.height = canvasEl.clientHeight;
 
    if (nodes.length == 0) {
      constructNodes();
    }
 
    render();
};
 
window.onresize(); // trigger the event manually.

大家在第一遍修改尺寸后营造了拥有节点,那里就要用到下一个函数(constructNodes)了

这一个函数中大家随便创立多少个点,大家用字典对象的点子存储那些点的顺序新闻:

function constructNodes() { for (var i = 0; i < 100; i++) { var node
= { drivenByMouse: i == 0, x: Math.random() * canvasEl.width, y:
Math.random() * canvasEl.height, vx: Math.random() * 1 – 0.5, vy:
Math.random() * 1 – 0.5, radius: Math.random() > 0.9 ? 3 +
Math.random() * 3 : 1 + Math.random() * 3 }; nodes.push(node); }
nodes.forEach(function (e) { nodes.forEach(function (e2) { if (e == e2)
{ return; } var edge = { from: e, to: e2 } addEdge(edge); }); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function constructNodes() {
    for (var i = 0; i < 100; i++) {
      var node = {
        drivenByMouse: i == 0,
        x: Math.random() * canvasEl.width,
        y: Math.random() * canvasEl.height,
        vx: Math.random() * 1 – 0.5,
        vy: Math.random() * 1 – 0.5,
        radius: Math.random() > 0.9 ? 3 + Math.random() * 3 : 1 + Math.random() * 3
      };
 
      nodes.push(node);
    }
 
    nodes.forEach(function (e) {
      nodes.forEach(function (e2) {
        if (e == e2) {
          return;
        }
 
        var edge = {
          from: e,
          to: e2
        }
 
        addEdge(edge);
      });
    });
  }

为了兑现前面一个更炫酷的意义,我给第二个点加了一个 drivenByMouse
属性,这些点的地点不会被粒子系统管理,也不会绘制出来,但是它会与其他点连线,那样就落到实处了鼠标跟随的职能了。

此地稍微解释一下 radius
属性的取值,我梦想让绝半数以上点都以小半径的,而极个其他点半径比较大,所以本人那里用了少数小
tricky,就是用几率控制点的半径取值,不断调整那个概率阈值就能赢得期待的半径随机分布。

点都创设完毕了,就要营造点与点之间的连线了,大家用到再也遍历,把多个点捆绑成一组,放到
edges 数组中。注意那里我用了此外一个函数来已毕那件事,而从不直接用
edges.push() ,为什么?

如若大家事先接连了
A、B两点,约等于外界循环是A,内侧循环是B,那么在下一次巡回中,外侧为B,内侧为A,是还是不是也会创制一条边呢?而实际上,那四个边除了方向差距以外是截然一致的,那全然没有须要而且占用资源。由此我们在
addEdge 函数中进行一个判定:

function addEdge(edge) { var ignore = false; edges.forEach(function (e)
{ if (e.from == edge.from & e.to == edge.to) { ignore = true; } if (e.to
== edge.from & e.from == edge.to) { ignore = true; } }); if (!ignore) {
edges.push(edge); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function addEdge(edge) {
    var ignore = false;
 
    edges.forEach(function (e) {
      if (e.from == edge.from & e.to == edge.to) {
        ignore = true;
      }
 
      if (e.to == edge.from & e.from == edge.to) {
        ignore = true;
      }
    });
 
    if (!ignore) {
      edges.push(edge);
    }
  }

从那之后,大家的准备工作就停止了,上边大家要让点动起来:

function step() { nodes.forEach(function (e) { if (e.drivenByMouse) {
return; } e.x += e.vx; e.y += e.vy; function clamp(min, max, value) { if
(value > max) { return max; } else if (value < min) { return min;
} else { return value; } } if (e.x <= 0 || e.x >= canvasEl.width)
{ e.vx *= -1; e.x = clamp(0, canvasEl.width, e.x) } if (e.y <= 0 ||
e.y >= canvasEl.height) { e.vy *= -1; e.y = clamp(0,
canvasEl.height, e.y) } }); adjustNodeDrivenByMouse(); render();
window.requestAnimationFrame(step); } function adjustNodeDrivenByMouse()
{ nodes[0].x += (mousePos[0] – nodes[0].x) / easingFactor;
nodes[0].y += (mousePos[1] – nodes[0].y) / easingFactor; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function step() {
    nodes.forEach(function (e) {
      if (e.drivenByMouse) {
        return;
      }
 
      e.x += e.vx;
      e.y += e.vy;
 
      function clamp(min, max, value) {
        if (value > max) {
          return max;
        } else if (value < min) {
          return min;
        } else {
          return value;
        }
      }
 
      if (e.x <= 0 || e.x >= canvasEl.width) {
        e.vx *= -1;
        e.x = clamp(0, canvasEl.width, e.x)
      }
 
      if (e.y <= 0 || e.y >= canvasEl.height) {
        e.vy *= -1;
        e.y = clamp(0, canvasEl.height, e.y)
      }
    });
 
    adjustNodeDrivenByMouse();
    render();
    window.requestAnimationFrame(step);
  }
 
  function adjustNodeDrivenByMouse() {
    nodes[0].x += (mousePos[0] – nodes[0].x) / easingFactor;
    nodes[0].y += (mousePos[1] – nodes[0].y) / easingFactor;
  }

看样子那样一大段代码不要惧怕,其实做的事情很不难。那是粒子系统的宗旨,就是遍历粒子,并且更新其场馆。更新的公式就是

v = v + a s = s + v

1
2
v = v + a
s = s + v

a是加快度,v是速度,s是位移。由于我们那里不涉及加快度,所以就不写了。然后咱们必要作一个边缘的碰撞检测,不然大家的“星星”都无拘无束地一点点飞~走~了~。边缘碰撞后的处理格局就是让速度矢量反转,这样粒子就会“掉头”回来。

还记得大家要求做的鼠标跟随吗?也在这处理,大家让第二个点的职位一点一点移动到鼠标的地点,下边这一个公式很有意思,可以轻松完成缓动:

x = x + (t – x) / factor

1
x = x + (t – x) / factor

中间 factor 是缓动因子,t 是最后地方,x
是当前岗位。至于这几个公式的解说还有个互相大神 Bret 维克托在他的讲演中关系过,录制做的可怜好,有条(ti)件(zi)世家自然要探望:
Bret Victor – Stop Drawing Dead
Fish

好了,回到主旨。大家在上头的函数中拍卖完了一帧中的数据,我们要让任何粒子系统连续地运转起来就需要一个timer了,可是丰盛不提倡我们利用
setInterval,而是尽量使用
requestAnimationFrame,它能保障你的帧率锁定在

结余的就是绘制啦:

function render() { ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0,
canvasEl.width, canvasEl.height); edges.forEach(function (e) { var l =
lengthOfEdge(e); var threshold = canvasEl.width / 8; if (l >
threshold) { return; } ctx.strokeStyle = edgeColor; ctx.lineWidth = (1.0

  • l / threshold) * 2.5; ctx.globalAlpha = 1.0 – l / threshold;
    ctx.beginPath(); ctx.moveTo(e.from.x, e.from.y); ctx.lineTo(e.to.x,
    e.to.y); ctx.stroke(); }); ctx.globalAlpha = 1.0; nodes.forEach(function
    (e) { if (e.drivenByMouse) { return; } ctx.fillStyle = nodeColor;
    ctx.beginPath(); ctx.arc(e.x, e.y, e.radius, 0, 2 * Math.PI);
    ctx.fill(); }); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function render() {
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, canvasEl.width, canvasEl.height);
 
    edges.forEach(function (e) {
      var l = lengthOfEdge(e);
      var threshold = canvasEl.width / 8;
 
      if (l > threshold) {
        return;
      }
 
      ctx.strokeStyle = edgeColor;
      ctx.lineWidth = (1.0 – l / threshold) * 2.5;
      ctx.globalAlpha = 1.0 – l / threshold;
      ctx.beginPath();
      ctx.moveTo(e.from.x, e.from.y);
      ctx.lineTo(e.to.x, e.to.y);
      ctx.stroke();
    });
    ctx.globalAlpha = 1.0;
 
    nodes.forEach(function (e) {
      if (e.drivenByMouse) {
        return;
      }
 
      ctx.fillStyle = nodeColor;
      ctx.beginPath();
      ctx.arc(e.x, e.y, e.radius, 0, 2 * Math.PI);
      ctx.fill();
    });
  }

常规的 Canvas 绘图操作,注意 beginPath
一定要调用,不然你的线就全部穿在协同了…
要求证实的是,在绘制边的时候,我们先要总计两点距离,然后依照一个阈值来判定是还是不是要绘制那条边,那样我们才能落成距离远的点之间连线不可知的功用。

到那边,我们的上上下下职能就完事了。即使不知情大家也可以去我文章开端放的
repo 离去看完整的源码。Have fun!!

2 赞 4 收藏
评论

美高梅开户网址 3

效益是或不是比直线的位移更是奋发呢?而且也真正很简短,别忘了那篇博文的标题,小小滴公式,大大滴乐趣。要做出如此的功效,用的就独自是大家初中。。大概高中时候的物理知识,加速移动,减速运动的公式啦。所以的确是小小滴公式。楼主很喜爱折腾一些酷炫的东西,固然只怕日常做事上用不上,不过,那乐趣确实很令人着迷啊。而且,做下这么些也能够增长一下编程的思维能力哈。

 原理跟从前写的稿子[js高手之路]html5 canvas动画教程 –
边界判断与小球粒子模拟喷泉,散弹效果大概,只是在蒙受边界的时候,把速度调成反向的,小球就会反弹.

废话不多说,进入正题啦。就概括的解释一下原理吧~~~

<head> <meta charset=’utf-8′ /> <style> #canvas {
border: 1px dashed #aaa; } </style> <script> function
Ball(x, y, r, color) { this.x = x || 0; this.y = y || 0; this.radius = r
|| 20; this.color = color || ‘#09f’; } Ball.prototype = { constructor:
Ball, stroke: function (cxt) { cxt.strokeStyle = this.color;
cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
cxt.closePath(); cxt.stroke(); }, fill: function (cxt) { cxt.fillStyle =
this.color; cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2
* Math.PI); cxt.closePath(); cxt.fill(); } } </script>
<script> window.onload = function () { var oCanvas =
document.querySelector(“#canvas”), oGc = oCanvas.getContext(‘2d’),
width = oCanvas.width, height = oCanvas.height, ball = new Ball(width /
2, height / 2), vx = Math.random() * 2 + 5, vy = Math.random() * 2 +
5; ball.fill(oGc); (function move() { oGc.clearRect(0, 0, width,
height); ball.x += vx; ball.y += vy; ball.fill(oGc); if (ball.x <
ball.radius) { //蒙受左手的边界 ball.x = ball.radius; vx = -vx; } else
if (ball.y < ball.radius) { ball.y = ball.radius; vy = -vy; } else if
(ball.x > width – ball.radius) { ball.x = width – ball.radius; vx =
-vx; } else if (ball.y > height – ball.radius) { ball.y = height –
ball.radius; vy = -vy; } requestAnimationFrame(move); })(); }
</script> </head> <body> <canvas id=”canvas”
width=”1200″ height=”600″></canvas> </body>

粒子运动的主导代码就这么一点:

run code

JavaScript

 几个物体的反弹

update:function(time){ this.x += this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y; var xc =
this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za = 20; var
ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; }else { var gravity = 9.8; var vy = this.vy+gravity*time;
if(this.y>canvas.height){ vy = -vy*0.7; } this.vy = vy; } },

 1 <head>
 2     <meta charset='utf-8' />
 3     <style>
 4         #canvas {
 5             border: 1px dashed #aaa;
 6         }
 7     </style>
 8     <script src="./ball.js"></script>
 9     <script>
10         window.onload = function () {
11             var oCanvas = document.querySelector("#canvas"),
12                 oGc = oCanvas.getContext('2d'),
13                 width = oCanvas.width, height = oCanvas.height,
14                 balls = [], n = 50;
15             function getRandColor() {
16                 return '#' + (function (color) {
17                     return (color += '0123456789abcdef'[Math.floor(Math.random() * 16)]) && (color.length == 6) ? color : arguments.callee(color);
18                 })('');
19             }
20             for (var i = 0; i < n; i++) {
21                 var ball = new Ball(width / 2, height / 2, 20, getRandColor());
22                 ball.vx = (Math.random() * 2 - 1) * 5;
23                 ball.vy = (Math.random() * 2 - 1) * 5;
24                 balls.push(ball);
25             }
26             (function move() {
27                 oGc.clearRect(0, 0, width, height);
28                 balls.forEach(function (ball) {
29                     ball.x += ball.vx;
30                     ball.y += ball.vy;
31                     ball.fill(oGc);
32 
33                     if (ball.x < ball.radius) { //碰到左边的边界
34                         ball.x = ball.radius;
35                         ball.vx = -ball.vx;
36                     } else if (ball.y < ball.radius) {
37                         ball.y = ball.radius;
38                         ball.vy = -ball.vy;
39                     } else if (ball.x > width - ball.radius) {
40                         ball.x = width - ball.radius;
41                         ball.vx = -ball.vx;
42                     } else if (ball.y > height - ball.radius) {
43                         ball.y = height - ball.radius;
44                         ball.vy = -ball.vy;
45                     }
46                 });
47                 requestAnimationFrame(move);
48             })();
49         }
50     </script>
51 </head>
52 
53 <body>
54     <canvas id="canvas" width="1200" height="600"></canvas>
55 </body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&&this.y>0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y>canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },

规律是同等的,只是把坐标和进程的判定,基于一个个小球对象.

粒子总共有两种情景,一种是自由落体,一种就是饱受吸力。自由落体就不说了。说吸力此前先贴出粒子的习性:

 

var Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y;
this.vx=vx; this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color
= color; this.visible = true; this.globleDown = false; this.setEnd(tox ,
toy); } setEnd:function(tox , toy){     this.tox = tox;
    this.toy = toy;     var yc = this.toy – this.y;     var
xc = this.tox – this.x; },

<head> <meta charset=’utf-8′ /> <style> #canvas {
border: 1px dashed #aaa; } </style> <script> function
Ball(x, y, r, color) { this.x = x || 0; this.y = y || 0; this.radius = r
|| 20; this.color = color || ‘#09f’; } Ball.prototype = { constructor:
Ball, stroke: function (cxt) { cxt.strokeStyle = this.color;
cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
cxt.closePath(); cxt.stroke(); }, fill: function (cxt) { cxt.fillStyle =
this.color; cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 2
* Math.PI); cxt.closePath(); cxt.fill(); } } </script>
<script> window.onload = function () { var oCanvas =
document.querySelector(“#canvas”), oGc = oCanvas.getContext(‘2d’),
width = oCanvas.width, height = oCanvas.height, balls = [], n = 50;
function getRandColor() { return ‘#’ + (function (color) { return
(color += ‘0123456789abcdef'[Math.floor(Math.random() * 16)]) &&
(color.length == 6) ? color : arguments.callee(color); })(”); } for
(var i = 0; i < n; i++) { var ball = new Ball(width / 2, height / 2,
20, getRandColor()); ball.vx = (Math.random() * 2 – 1) * 5; ball.vy =
(Math.random() * 2 – 1) * 5; balls.push(ball); } (function move() {
oGc.clearRect(0, 0, width, height); balls.forEach(function (ball) {
ball.x += ball.vx; ball.y += ball.vy; ball.fill(oGc); if (ball.x <
ball.radius) { //碰着左手的分界 ball.x = ball.radius; ball.vx =
-ball.vx; } else if (ball.y < ball.radius) { ball.y = ball.radius;
ball.vy = -ball.vy; } else if (ball.x > width – ball.radius) { ball.x
= width – ball.radius; ball.vx = -ball.vx; } else if (ball.y > height

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
setEnd:function(tox , toy){
    this.tox = tox;
    this.toy = toy;
    var yc = this.toy – this.y;
    var xc = this.tox – this.x;
},
  • ball.radius) { ball.y = height – ball.radius; ball.vy = -ball.vy; }
    }); requestAnimationFrame(move); })(); } </script> </head>
    <body> <canvas id=”canvas” width=”1200″
    height=”600″></canvas> </body>

x,y就是粒子的任务,vx是粒子水平速度,vy是粒子的垂直速度,nexttox之类知道仍然不知道道都不在乎,只是暂时保留变量的。tox,和toy就是粒子的目标地地方。

run code

率先,先予以负有粒子一个目标地,这几个目标地上边再会说。相当于要粒子到达的地点,然后再定义一个变量za作为加快度,具体数值的话,就协调多测试下就会有大约参数的了,我设成20,感觉就基本上了。za是粒子和目标地之间连线的增速度,所以,大家通过粒子的职位和目标地的职位,通过简单的三角函数,就足以把粒子的品位加速度和垂直加快度求出来了,就那段

var ax = za*(xc/this.jl), ay = za*(yc/this.jl),

1
2
var ax = za*(xc/this.jl),
  ay = za*(yc/this.jl),

有了档次加速度和垂直加速度后,接下去就更简便了,直接总括水平速度和垂直速度的增量,从而改变程度速度和垂直速度的值

vx = (this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97;

1
2
vx = (this.vx+ax*time)*0.97,
vy = (this.vy+ay*time)*0.97;

所以要乘于0.97是为着仿功用量消耗,粒子才会放慢。time是每一帧的时日差

测算出速度后就立异粒子地点就行了。

this.x += this.vx*time; this.y += this.vy*time;

1
2
this.x += this.vx*time;
this.y += this.vy*time;

因为粒子在宇航进度中,与目标地之间的连线方向是不停改变的,所以每一帧都要再一次总结粒子的程度加快度和垂直加快度。

举手投足规律就是这样,是不是很粗略吗。

移动规律说完了,再扯一下下边卓殊动画的有血有肉落到实处啊:动画初步化,在一个离屏canvas上把想要的字依旧图片画出来,然后再通过getImageData这几个方法拿到离屏canvas的像素。然后用一个巡回,把离屏canvas中有绘制的区域找出来,因为imageData里的data值就是一个rgba数组,所以我们判断最后一个的值相当于透明度大于128就是有绘制过的区域。然后拿走该区域的xy值,为了以免万一粒子对象过多导致页面卡顿,所以我们就限制一下粒子的多寡,取像素的时候x值和y值每便递增2,从而收缩粒子数量。

this.osCanvas = document.createElement(“canvas”); var osCtx =
this.osCanvas.getContext(“2d”); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = “center”;
osCtx.textBaseline = “middle”; osCtx.font=”70px 微软雅黑,金鼎文 bold”;
osCtx.fillStyle = “#1D181F” osCtx.fillText(“WelCome” ,
this.osCanvas.width/2 , this.osCanvas.height/2-40); osCtx.fillText(“To
wAxes’ HOME” , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*美高梅开户网址 ,4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
“rgba(“+bigImageData.data[i]+”,”+bigImageData.data[i+1]+”,”+bigImageData.data[i+2]+”,1)”
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
this.osCanvas = document.createElement("canvas");
        var osCtx = this.osCanvas.getContext("2d");
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = "center";
        osCtx.textBaseline = "middle";
        osCtx.font="70px 微软雅黑,黑体 bold";
        osCtx.fillStyle = "#1D181F"
        osCtx.fillText("WelCome" , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText("To wAxes’ HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x<bigImageData.width;x+=2){
            for(var y=0;y<bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]>128){
                    var dot = new Dot(
                        Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        "rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }

透过轮回获取到粒子的职责xy值后,把岗位赋给粒子,成为粒子的目标地。然后动画早先,就可以做出文字图片粒子化的成效了。

上面贴出动画完成的js代码。即便对别的代码也有趣味的,可以直接看控制台哈,没压缩的。

var part_1 = (function(w){ var dots = [],DOT_SIZE = 2,cube=null; var
Dot = function(x,y,vx,vy,tox,toy,color){ this.x=x; this.y=y; this.vx=vx;
this.vy=vy; this.nextox = tox; this.nextoy = toy; this.color = color;
this.visible = true; this.globleDown = false; this.setEnd(tox , toy); }
Dot.prototype = { paint:function(){ ctx.fillStyle=this.color;
ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE ,
DOT_SIZE); }, setEnd:function(tox , toy){ this.tox = tox; this.toy =
toy; var yc = this.toy – this.y; var xc = this.tox – this.x; //
this.initjl = Math.sqrt(xc*xc+yc*yc); }, update:function(time){ this.x
+= this.vx*time; this.y += this.vy*time;
if(!this.globleDown&&this.y>0){ var yc = this.toy – this.y; var xc =
this.tox – this.x; this.jl = Math.sqrt(xc*xc+yc*yc); var za = 20; var
ax = za*(xc/this.jl), ay = za*(yc/this.jl), vx =
(this.vx+ax*time)*0.97, vy = (this.vy+ay*time)*0.97; this.vx = vx;
this.vy = vy; // if(Math.abs(this.vx)<1&&Math.abs(this.vy)<1){ //
this.y = this.toy // this.x = this.tox // } }else { var gravity = 9.8;
var vy = this.vy+gravity*time; if(this.y>canvas.height){ vy =
-vy*0.7; } this.vy = vy; } }, loop:function(time){ this.update(time);
this.paint(); } } var animate = function(){ this.state = “before” } var
ap = animate.prototype; ap.init = function(){ this.osCanvas =
document.createElement(“canvas”); var osCtx =
this.osCanvas.getContext(“2d”); this.osCanvas.width = 1000;
this.osCanvas.height = 150; osCtx.textAlign = “center”;
osCtx.textBaseline = “middle”; osCtx.font=”70px 微软雅黑,燕体 bold”;
osCtx.fillStyle = “#1D181F” osCtx.fillText(“WelCome” ,
this.osCanvas.width/2 , this.osCanvas.height/2-40); osCtx.fillText(“To
wAxes’ HOME” , this.osCanvas.width/2 , this.osCanvas.height/2+40); var
bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); dots =
[]; for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var dot = new Dot(
Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
-Math.random()*canvas.height*2, 0, 0,
x+(canvas.width/2-this.osCanvas.width/2),
y+(canvas.height/2-this.osCanvas.height/2),
“rgba(“+bigImageData.data[i]+”,”+bigImageData.data[i+1]+”,”+bigImageData.data[i+2]+”,1)”
); dot.setEnd(canvas.width/2,canvas.height/2) dots.push(dot); } } }
console.log(dots.length) } ap.changeState = function(){ var osCtx =
this.osCanvas.getContext(“2d”);
osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
this.osCanvas.width = 460; this.osCanvas.height = 100;
osCtx.fillStyle=”#5C5656″ osCtx.fillRect(20,20,60,60)
drawLogo(this.osCanvas , osCtx); var bigImageData =
osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height); var
index=0; dots.sort(function(a , b){ return Math.random()-Math.random();
}) for(var x=0;x<bigImageData.width;x+=2){ for(var
y=0;y<bigImageData.height;y+=2){ var i = (y*bigImageData.width +
x)*4; if(bigImageData.data[i+3]>128){ var d = dots[index];
if(d){ d.setEnd(x+(canvas.width/2-300) , y+50) d.color =
“rgba(“+bigImageData.data[i]+”,”+bigImageData.data[i+1]+”,”+bigImageData.data[i+2]+”,1)”;
index++ } } } } setTimeout(function(){ var endindex = index; for(var
i=0;i<dots.length-endindex;i++){ if(dots[index]){ var d =
dots[index]; d.globleDown = true; d.vx = Math.random()*100-50; }
index++; } } , 2000) } function endState(){ canvas.width = 600;
canvas.height = 100; canvas.style.display=”block”; canvas.style.top =
“50px”; canvas.style.left = (window.innerWidth-canvas.width)/2+”px”;
cube = new Cube(50); cube._initVector(50,50); } function
drawLogo(canvas , ctx){ ctx.textAlign = “center”; ctx.textBaseline =
“middle”; ctx.font=”65px 微软雅黑,钟鼓文 bold” ctx.fillStyle=”#E06D2F”
ctx.fillText(“DEMO” , 300 , canvas.height/2) ctx.font=”40px
微软雅黑,草书 bold” ctx.fillStyle=”#405159″ ctx.fillText(“吖猩的” , 160
, canvas.height/2) ctx.fillText(“小窝” , 420 , canvas.height/2) } var
num = 0; ap.update = function(time){ time = time/100;
if(this.state===”first”||this.state===”before”){ var completeNum = 0;
dots.forEach(function(dot){ if(dot.visible) dot.loop(time);
if(dot.jl<5){ completeNum++ } });
if(completeNum>=5*dots.length/6){ if(this.state===”before”){
this.state = “first”; dots.forEach(function(dot){ dot.setEnd(dot.nextox
, dot.nextoy); }); }else { this.state = “second”; this.changeState(); }
} }else if(this.state===”second”){ var completeNum = 0, allnum = 0;
dots.forEach(function(dot){ if(dot.visible) dot.loop(time);
if(dot.globleDown){ allnum++; if(Math.abs(dot.y-canvas.height)<2){
completeNum++ } } }); if(completeNum===allnum&&allnum!==0){ this.state =
“third”; part_2.animate(); endState(); } }else
if(this.state===”third”){ cube.update(); drawLogo(canvas , ctx); } }
return new animate(); })(window)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
var part_1 = (function(w){
    var dots = [],DOT_SIZE = 2,cube=null;
 
    var Dot = function(x,y,vx,vy,tox,toy,color){
        this.x=x;
        this.y=y;
        this.vx=vx;
        this.vy=vy;
        this.nextox = tox;
        this.nextoy = toy;
        this.color = color;
        this.visible = true;
        this.globleDown = false;
        this.setEnd(tox , toy);
    }
 
    Dot.prototype = {
        paint:function(){
            ctx.fillStyle=this.color;
            ctx.fillRect(this.x-DOT_SIZE/2 , this.y-DOT_SIZE/2 , DOT_SIZE , DOT_SIZE);
        },
 
        setEnd:function(tox , toy){
            this.tox = tox;
            this.toy = toy;
            var yc = this.toy – this.y;
            var xc = this.tox – this.x;
            // this.initjl = Math.sqrt(xc*xc+yc*yc);
        },
 
        update:function(time){
            this.x += this.vx*time;
            this.y += this.vy*time;
 
            if(!this.globleDown&&this.y>0){
                var yc = this.toy – this.y;
                var xc = this.tox – this.x;
 
                this.jl = Math.sqrt(xc*xc+yc*yc);
 
                var za = 20;
 
                var ax = za*(xc/this.jl),
                    ay = za*(yc/this.jl),
                    vx = (this.vx+ax*time)*0.97,
                    vy = (this.vy+ay*time)*0.97;
 
                this.vx = vx;
                this.vy = vy;
 
                // if(Math.abs(this.vx)<1&&Math.abs(this.vy)<1){
                //     this.y = this.toy
                //     this.x = this.tox
                // }
            }else {
                var gravity = 9.8;
                var vy = this.vy+gravity*time;
 
                if(this.y>canvas.height){
                    vy = -vy*0.7;
                }
 
                this.vy = vy;
            }
        },
 
        loop:function(time){
            this.update(time);
            this.paint();
        }
    }
 
    var animate = function(){
        this.state = "before"
    }
 
    var ap = animate.prototype;
 
    ap.init = function(){
        this.osCanvas = document.createElement("canvas");
        var osCtx = this.osCanvas.getContext("2d");
 
        this.osCanvas.width = 1000;
        this.osCanvas.height = 150;
 
        osCtx.textAlign = "center";
        osCtx.textBaseline = "middle";
        osCtx.font="70px 微软雅黑,黑体 bold";
        osCtx.fillStyle = "#1D181F"
        osCtx.fillText("WelCome" , this.osCanvas.width/2 , this.osCanvas.height/2-40);
        osCtx.fillText("To wAxes’ HOME" , this.osCanvas.width/2 , this.osCanvas.height/2+40);
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        dots = [];
 
        for(var x=0;x<bigImageData.width;x+=2){
            for(var y=0;y<bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]>128){
                    var dot = new Dot(
                        Math.random()>0.5?Math.random()*20+10:Math.random()*20+canvas.width-40,
                        -Math.random()*canvas.height*2,
                        0,
                        0,
                        x+(canvas.width/2-this.osCanvas.width/2),
                        y+(canvas.height/2-this.osCanvas.height/2),
                        "rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)"
                    );
                    dot.setEnd(canvas.width/2,canvas.height/2)
                    dots.push(dot);
                }
            }
        }
        console.log(dots.length)
    }
 
    ap.changeState = function(){
        var osCtx = this.osCanvas.getContext("2d");
        osCtx.clearRect(0,0,this.osCanvas.width,this.osCanvas.height);
        this.osCanvas.width = 460;
        this.osCanvas.height = 100;
 
        osCtx.fillStyle="#5C5656"
        osCtx.fillRect(20,20,60,60)
 
        drawLogo(this.osCanvas , osCtx);
 
        var bigImageData = osCtx.getImageData(0,0,this.osCanvas.width,this.osCanvas.height);
 
        var index=0;
        dots.sort(function(a , b){
            return Math.random()-Math.random();
        })
        for(var x=0;x<bigImageData.width;x+=2){
            for(var y=0;y<bigImageData.height;y+=2){
                var i = (y*bigImageData.width + x)*4;
                if(bigImageData.data[i+3]>128){
                        var d = dots[index];
                        if(d){
                            d.setEnd(x+(canvas.width/2-300) , y+50)
                            d.color = "rgba("+bigImageData.data[i]+","+bigImageData.data[i+1]+","+bigImageData.data[i+2]+",1)";
                            index++
                        }
                }
            }
        }
 
        setTimeout(function(){
            var endindex = index;
            for(var i=0;i<dots.length-endindex;i++){
                if(dots[index]){
                    var d = dots[index];
 
                    d.globleDown = true;
                    d.vx = Math.random()*100-50;
                }
                index++;
            }
        } , 2000)
    }
 
    function endState(){
        canvas.width = 600;
        canvas.height = 100;
        canvas.style.display="block";
        canvas.style.top = "50px";
        canvas.style.left = (window.innerWidth-canvas.width)/2+"px";
        cube = new Cube(50);
        cube._initVector(50,50);
    }
 
    function drawLogo(canvas , ctx){
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";
        ctx.font="65px 微软雅黑,黑体 bold"
        ctx.fillStyle="#E06D2F"
        ctx.fillText("DEMO" , 300 , canvas.height/2)
 
        ctx.font="40px 微软雅黑,黑体 bold"
        ctx.fillStyle="#405159"
        ctx.fillText("吖猩的" , 160 , canvas.height/2)
        ctx.fillText("小窝" , 420 , canvas.height/2)
    }
 
    var num = 0;
    ap.update = function(time){
        time = time/100;
        if(this.state==="first"||this.state==="before"){
            var completeNum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.jl<5){
                    completeNum++
                }
            });
            if(completeNum>=5*dots.length/6){
 
                if(this.state==="before"){
                    this.state = "first";
                    dots.forEach(function(dot){
                        dot.setEnd(dot.nextox , dot.nextoy);
                    });
                }else {
                    this.state = "second";
                    this.changeState();
                }
            }
        }else if(this.state==="second"){
            var completeNum = 0,
                allnum = 0;
            dots.forEach(function(dot){
                if(dot.visible) dot.loop(time);
                if(dot.globleDown){
                    allnum++;
                    if(Math.abs(dot.y-canvas.height)<2){
                        completeNum++
                    }
                }
            });
 
            if(completeNum===allnum&&allnum!==0){
                this.state = "third";
                part_2.animate();
                endState();
            }
        }else if(this.state==="third"){
            cube.update();
            drawLogo(canvas , ctx);
        }
    }
 
    return new animate();
})(window)

赞 收藏 1
评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图