效果图:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Canvas</title> 8 <style> 9 canvas { 10 margin: 0 auto; 11 border: 1px solid #aaa; 12 display: block; 13 } 14 </style> 15 </head> 16 <body> 17 <canvas width="500px" height="500px" id="canvas"></canvas> 18 19 <script> 20 var canvas = document.querySelector("#canvas"); 21 var ctx = canvas.getContext("2d"); 22 var w = canvas.width; 23 var h = canvas.height; 24 25 /* 26 假设小球运动100次后,组合成文字 27 公式: 28 x1, y1: 小球初始位置 29 x2, y2: 小球所在的文字位置 30 xSpeed = (x2 - x1)/times 31 ySpeed = (y2 - y1)/times 32 */ 33 34 function drawCircle(x, y, r, color) { 35 ctx.beginPath(); 36 ctx.arc(x, y, r, 0, Math.PI * 2); 37 ctx.fillStyle = color || "#000"; 38 ctx.fill(); 39 } 40 41 function drawText(text, x, y) { 42 ctx.font = "400px 微软雅黑"; 43 ctx.textAlign = "center"; 44 ctx.textBaseline = "middle"; 45 ctx.fillText(text, x, y, w); 46 } 47 48 function drawFillText(text, x, y, color) { 49 ctx.font = "12px 微软雅黑"; 50 ctx.fillStyle = color; 51 ctx.textAlign = "center"; 52 ctx.textBaseline = "middle"; 53 ctx.fillText(text, x, y, w); 54 } 55 56 function randNum(num) { 57 return Math.random() * num; 58 } 59 60 // 动态_01 定义运动次数 61 var times = 100; 62 63 // 动态_02 定义小球类 64 function Ball(xEnd, yEnd) { 65 // 小球起始位置,随机 66 this.xStart = randNum(w); 67 this.yStart = randNum(h); 68 // 小球结束为止,文字内 69 this.xEnd = xEnd; 70 this.yEnd = yEnd; 71 // 小球中心点,即小球每次运动后的位置 72 this.x = this.xStart; 73 this.y = this.yStart; 74 // 计算运动速度,起始点和终点 75 this.xSpeed = (this.xEnd - this.xStart) / times; 76 this.ySpeed = (this.yEnd - this.yStart) / times; 77 // 设置半径和颜色 78 this.r = 3; 79 this.color = "#f00"; 80 81 // 设置填充颜色和文字 82 this.text = "♥"; 83 this.color = "rgb(" + parseInt(Math.random() * 255) + 84 "," + parseInt(Math.random() * 255) + 85 "," + parseInt(Math.random() * 255) + ")"; 86 } 87 Ball.prototype.show = function() { 88 // 计算每次小球运动后的坐标位置 89 this.x += this.xSpeed; 90 this.y += this.ySpeed; 91 // drawCircle(this.x, this.y, this.r, this.color); 92 drawFillText(this.text, this.x, this.y, this.color); 93 } 94 95 drawText("❤", w / 2, h / 2); 96 var copy = ctx.getImageData(0, 0, w, h); 97 ctx.clearRect(0, 0, w, h); 98 var leap = 10; 99 var ballArr = []; 100 for (var y = 0; y < h; y += leap) { 101 for (var x = 0; x < w; x += leap) { 102 var index = x + y * w; // 公式 103 var a = copy.data[index * 4 + 3]; 104 if (a > 128) { 105 // step_03 调用小球类,画圆 106 var ball = new Ball(x, y); 107 ballArr.push(ball); 108 ball.show(); 109 } 110 } 111 } 112 113 // step_04 让小球动起来 114 var count = 0; 115 var timer = setInterval(() => { 116 ctx.clearRect(0, 0, w, h); 117 for (var i = 0; i < ballArr.length; i++) { 118 ballArr[i].show(); 119 }; 120 count++; 121 if (count + 1 == times) { 122 clearInterval(timer) 123 } 124 }, 20) 125 </script> 126 </body> 127 128 </html>