一,介绍与需求
1.1,介绍
canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术。
1.2,需求
实现特殊的动画效果
二,动画实现
以跟随鼠标/手指移动的火为例
第一步:创建Canvas标签
1
第二步:获取Canvas标签
复制代码
1 let canvas = document.getElementById('fire');
2 if (canvas.getContext){
3 var ctx = canvas.getContext('2d');
4 // drawing code here
5 } else {
6 alert("不支持Canvas")
7 }
复制代码
第三步:绘制火花
复制代码
1 var Spark = function (mouse) {
2
3 this.cx = mouse.x;
4 this.cy = mouse.y;
5 this.x = rand(this.cx - 40, this.cx + 40);
6 this.y = rand(this.cy, this.cy + 5);
7 this.lx = this.x;
8 this.ly = this.y;
9 this.vy = rand(1, 3);
10 this.vx = rand(-4, 4);
11 this.r = rand(0, 1);
12 this.life = rand(4, 5);
13 this.alive = true;
14 this.c = {
15
16 h: Math.floor(rand(2, 40)),
17 s: 100,
18 l: rand(40, 100),
19 a: rand(0.8, 0.9)
20
21 }
22
23 }
24 Spark.prototype.update = function () {
25
26 this.lx = this.x;
27 this.ly = this.y;
28
29 this.y -= this.vy;
30 this.x += this.vx;
31
32 if (this.x < this.cx)
33 this.vx += 0.2;
34 else
35 this.vx -= 0.2;
36
37 this.vy += 0.08;
38 this.life -= 0.1;
39
40 if (this.life <= 0) {
41
42 this.c.a -= 0.05;
43
44 if (this.c.a <= 0)
45 this.alive = false;
46
47 }
48
49 }
50 Spark.prototype.draw = function (ctx) {
51
52 ctx.beginPath();
53 ctx.moveTo(this.lx, this.ly);
54 ctx.lineTo(this.x, this.y);
55 ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a / 2) + ")";
56 ctx.lineWidth = this.r * 2;
57 ctx.lineCap = 'round';
58 ctx.stroke();
59 ctx.closePath();
60
61 ctx.beginPath();
62 ctx.moveTo(this.lx, this.ly);
63 ctx.lineTo(this.x, this.y);
64 ctx.strokeStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
65 ctx.lineWidth = this.r;
66 ctx.stroke();
67 ctx.closePath();
68
69 }
复制代码
第四步:绘制火焰
复制代码
1 var Flame = function (mouse) {
2
3 this.cx = mouse.x;
4 this.cy = mouse.y;
5 this.x = rand(this.cx - 25, this.cx + 25);
6 this.y = rand(this.cy - 5, this.cy + 5);
7 this.vy = rand(1, 3);
8 this.vx = rand(-1, 1);
9 this.r = rand(20, 30);
10 this.life = rand(3, 6);
11 this.alive = true;
12 this.c = {
13
14 h: Math.floor(rand(2, 40)),
15 s: 100,
16 l: rand(80, 100),
17 a: 0,
18 ta: rand(0.8, 0.9)
19
20 }
21
22
23 }
24 Flame.prototype.update = function () {
25
26 this.y -= this.vy;
27 this.vy += 0.05;
28
29
30 this.x += this.vx;
31
32 if (this.x < this.cx)
33 this.vx += 0.1;
34 else
35 this.vx -= 0.1;
36
37
38
39
40 if (this.r > 0)
41 this.r -= 0.1;
42
43 if (this.r <= 0)
44 this.r = 0;
45
46
47
48 this.life -= 0.15;
49
50 if (this.life <= 0) {
51
52 this.c.a -= 0.05;
53
54 if (this.c.a <= 0)
55 this.alive = false;
56
57 } else if (this.life > 0 && this.c.a < this.c.ta) {
58
59 this.c.a += .08;
60
61 }
62
63 }
64 Flame.prototype.draw = function (ctx) {
65
66 ctx.beginPath();
67 ctx.arc(this.x, this.y, this.r * 3, 0, 2 * Math.PI);
68 ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + (this.c.a / 20) + ")";
69 ctx.fill();
70
71 ctx.beginPath();
72 ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
73 ctx.fillStyle = "hsla( " + this.c.h + ", " + this.c.s + "%, " + this.c.l + "%, " + this.c.a + ")";
74 ctx.fill();
75
76 }
复制代码
第五步:绘制火
复制代码
1 var Fire = function () {
2
3 this.canvas = document.getElementById('fire');
4 this.ctx = this.canvas.getContext('2d');
5 this.canvas.height = window.innerHeight;// window.innerHeight
6 this.canvas.width = window.innerWidth;//window.innerWidth
7
8 this.aFires = [];
9 this.aSpark = [];
10 this.aSpark2 = [];
11
12
13
14 this.mouse = {
15 x: this.canvas.width * .5,
16 y: this.canvas.height * .75,
17 }
18
19
20
21 this.init();
22
23 }
24 Fire.prototype.init = function () {
25 //跳转语句
26 if (system.win || system.mac || system.xll) {
27 this.canvas.addEventListener('mousemove', this.updateMouse.bind(this), false);//PC端
28 } else {
29 this.canvas.addEventListener('touchmove', this.updateMouse.bind(this), false);//移动端
30 }
31
32
33 }
34 Fire.prototype.run = function () {
35
36 this.update();
37 this.draw();
38
39 if (this.bRuning)
40 requestAnimationFrame(this.run.bind(this));
41
42 }
43 Fire.prototype.start = function () {
44
45 this.bRuning = true;
46 this.run();
47
48 }
49 Fire.prototype.stop = function () {
50
51 this.bRuning = false;
52
53 }
54 Fire.prototype.update = function () {
55
56 this.aFires.push(new Flame(this.mouse));
57 this.aSpark.push(new Spark(this.mouse));
58 this.aSpark2.push(new Spark(this.mouse));
59
60
61
62 for (var i = this.aFires.length - 1; i >= 0; i--) {
63
64 if (this.aFires[i].alive)
65 this.aFires[i].update();
66 else
67 this.aFires.splice(i, 1);
68
69 }
70
71 for (var i = this.aSpark.length - 1; i >= 0; i--) {
72
73 if (this.aSpark[i].alive)
74 this.aSpark[i].update();
75 else
76 this.aSpark.splice(i, 1);
77
78 }
79
80
81 for (var i = this.aSpark2.length - 1; i >= 0; i--) {
82
83 if (this.aSpark2[i].alive)
84 this.aSpark2[i].update();
85 else
86 this.aSpark2.splice(i, 1);
87
88 }
89
90 }
91
92 Fire.prototype.draw = function () {
93
94 this.ctx.globalCompositeOperation = "source-over";
95 this.ctx.fillStyle = "rgba( 15, 5, 2, 1 )";
96 this.ctx.fillRect(0, 0, window.innerWidth, window.innerHeight);
97
98 this.grd = this.ctx.createRadialGradient(this.mouse.x, this.mouse.y - 200, 200, this.mouse.x, this.mouse.y - 100, 0);
99 this.grd.addColorStop(0, "rgb( 15, 5, 2 )");
100 this.grd.addColorStop(1, "rgb( 30, 10, 2 )");
101 this.ctx.beginPath();
102 this.ctx.arc(this.mouse.x, this.mouse.y - 100, 200, 0, 2 * Math.PI);
103 this.ctx.fillStyle = this.grd;
104 this.ctx.fill();
105
106
107 this.ctx.font = "15em Amatic SC";
108 this.ctx.textAlign = "center";
109 this.ctx.strokeStyle = "rgb(50, 20, 0)";
110 this.ctx.fillStyle = "rgb(120, 10, 0)";
111 this.ctx.lineWidth = 2;
112 this.ctx.strokeText("", this.canvas.width / 2, this.canvas.height * .72);
113 this.ctx.fillText("", this.canvas.width / 2, this.canvas.height * .72);
114
115
116
117 this.ctx.globalCompositeOperation = "overlay";//or lighter or soft-light
118
119 for (var i = this.aFires.length - 1; i >= 0; i--) {
120
121 this.aFires[i].draw(this.ctx);
122
123 }
124
125 this.ctx.globalCompositeOperation = "soft-light";//"soft-light";//"color-dodge";
126
127 for (var i = this.aSpark.length - 1; i >= 0; i--) {
128
129 if ((i % 2) === 0)
130 this.aSpark[i].draw(this.ctx);
131
132 }
133
134
135 this.ctx.globalCompositeOperation = "color-dodge";//"soft-light";//"color-dodge";
136
137 for (var i = this.aSpark2.length - 1; i >= 0; i--) {
138
139 this.aSpark2[i].draw(this.ctx);
140
141 }
142
143
144 }
145
146 Fire.prototype.updateMouse = function (e) {
147 //跳转语句
148 if (system.win || system.mac || system.xll) {//PC端
149 this.mouse.x = e.clientX;
150 this.mouse.y = e.clientY;
151 } else {//移动端
152 e.preventDefault();//阻止默认行为
153 this.mouse.x = e.changedTouches[0].clientX;
154 this.mouse.y = e.changedTouches[0].clientY;
155 }
156
157
158 }
复制代码
第六步:调用
复制代码
1 var oCanvas;
2 init = function () {
3
4 oCanvas = new Fire();
5 oCanvas.start();
6
7
8 }
9 window.onload = init;
复制代码
随机数函数
1 rand = function (min, max) { return Math.random() * (max - min) + min; };
效果如下:
三,PC端与移动端处理
3.1,判断是PC端还是移动端
复制代码
1 //平台、设备和操作系统
2 var system = {
3 win: false,
4 mac: false,
5 xll: false
6 };
7 //检测平台
8 var p = navigator.platform;
9 system.win = p.indexOf("Win") == 0;
10 system.mac = p.indexOf("Mac") == 0;
11 system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);
12
13 //跳转语句
14 if (system.win || system.mac || system.xll) {
15 this.canvas.addEventListener('mousemove', this.updateMouse.bind(this), false);//PC端 鼠标移动
16 } else {
17 this.canvas.addEventListener('touchmove', this.updateMouse.bind(this), false);//移动端 手指滑动
18 }
复制代码
3.2,PC端还是移动端的事件处理
复制代码
1 //跳转语句
2 if (system.win || system.mac || system.xll) {//PC端
3 this.mouse.x = e.clientX;
4 this.mouse.y = e.clientY;
5 } else {//移动端
6 e.preventDefault();//阻止默认行为
7 this.mouse.x = e.changedTouches[0].clientX;
8 this.mouse.y = e.changedTouches[0].clientY;
9 }
复制代码
移动端需禁止缩放
1
东莞网站建设www.zg886.cn