Canvas动画(PC端 移动端)

Canvas动画(PC端 移动端)

一,介绍与需求

 1.1,介绍

canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术。<canvas> 标记和 SVG以及 VML 之间的一个重要的不同是,<canvas> 有一个基于 JavaScript 的绘图 API,而 SVG 和 VML 使用一个 XML 文档来描述绘图。SVG 绘图很容易编辑与生成,但功能明显要弱一些。canvas可以完成动画、游戏、图表、图像处理等原来需要Flash完成的一些功能

 1.2,需求

实现特殊的动画效果

二,动画实现

以跟随鼠标/手指移动的火为例

第一步:创建Canvas标签

1 <canvas id="fire"></canvas>

第二步:获取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; };

效果如下:

Canvas动画(PC端 移动端)

三,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     <meta name="viewport" content="target-densitydpi=320,width=640,user-scalable=no">

 

上一篇:鼠标拖拽效果的实现


下一篇:python游戏开发:pygame事件与设备轮询