小公式大乐趣,边界判断与反弹

用 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 Victor在她的演讲中涉嫌过,视频做的十分好,有条(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地图