Canvas animation (PC-side movement end)
I. Introduction and demand
1.1 Introduction
HTML5 canvas tag is a new operation in the canvas HTML5 javascript API, it can achieve complete dynamic 2D and 3D image technology in the web page. <Canvas> between a tag and SVG and VML important difference is that, <canvas> there is a JavaScript-based drawing API, while SVG and VML XML document described using a drawing. SVG drawing generation and editing is easy, but the function is significantly weaker. canvas can do some of the features of the original need to complete Flash animation, games, graphics, image processing, etc.
1.2 Demand
Achieve special effects animation
Second, to achieve animation
To follow the mouse / finger movement, for example fire
Step 1: Create Canvas tag
1 <canvas id="fire"></canvas>
Step Two: Get the Canvas tag
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 }
Step Three: Draw a spark
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 }
Step Four: Draw Fire
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 }
Step five: draw fire
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(the this .ctx); 140 141 is } 142 143 144 } 145 146 Fire.prototype.updateMouse = function (E) { 147 // jump statements 148 IF (system.win system.mac || || system.xll) { / / the PC terminal 149 the this .mouse.x = e.clientX; 150 the this .mouse.y = e.clientY; 151 } the else { // movement end 152 e.preventDefault (); // prevent the default behavior 153 the this.mouse.x = e.changedTouches[0].clientX; 154 this.mouse.y = e.changedTouches[0].clientY; 155 } 156 157 158 }
Step Six: Call
1 var oCanvas; 2 init = function () { 3 4 oCanvas = new Fire(); 5 oCanvas.start(); 6 7 8 } 9 window.onload = init;
Random number function
1 rand = function (min, max) { return Math.random() * (max - min) + min; };
Results are as follows:
Three, PC and the mobile terminal side processing
3.1, judgment is PC or mobile terminal side
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">