一、项目说明及效果
- github地址
- 一次基于Canvas和ES6中的Class类知识点的练习
- 实现效果:在画布上,随着鼠标移动,会产生一组绚丽的运动小球
- 效果截图:

二、实现思路
- 初始化
canvas、设置初始参数
- HTML结构
<div id="canvas-wrapper"> <canvas id="canvas"> 当前浏览器不支持canvas,请更换后重新尝试 </canvas> <!--左上方控件--> <div id="controller"> <h1>Canvas-炫彩小球</h1> <a id="canvas-btn">停止运动</a> <a class="color-btn" id="white-color-btn"> </a> <a class="color-btn" id="black-color-btn"> </a> </div> </div> - 初始化
canvas// 1. 获取当前画布 const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); canvas.width = 1000; canvas.height = 600; // 2. 保存生成的小球 let ballArr = [];
- 设计静态小球
- 首先我们应该在画布上绘制出静态的小球,即设计
Ball类,分析可知,要初始化小球,必须指定4个属性:x坐标、y坐标、color(小球颜色)、radius(小球半径),这一部分可以在constructor构造函数中初始化,同时Ball还需要有render方法来绘制小球// 小球类 class Ball{ // 构造器 constructor(x, y, radius, color){ this.x = x; this.y = y; this.color = color; this.r = radius; } // 绘制小球 render(){ ctx.save(); ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI); ctx.fillStyle = this.color; ctx.fill(); ctx.restore(); } }
- 让小球动起来
- 要实现小球动起来的效果,即小球
x坐标、y坐标属性的变化;同时要让小球动起来时逐渐变小直至消失,即小球radius半径属性的变化,由于这是个实时变化的过程,我们想到了用setInterval函数,同时我们可以设计一个MoveBall类,这个类继承Ball类的同时,将会有upDate方法,来操作小球属性的变化// 移动小球类 class MoveBall extends Ball{ constructor(x, y, radius, color){ super(x, y, radius, color); // 随机生成参数变化量 this.dX = _.random(-5,5); // Underscore-min.js this.dY = _.random(-5,5); this.dR = _.random(1,3); } // 更新参数值 upDate(){ this.x += this.dX; this.y += this.dY; this.r -= this.dR; if(this.r <= 0){ this.r = 0; // 移除小球 ballArr = _.without(ballArr, this); } } }
- 在画布上绘制小球
- 鼠标在画布上移动时,就生成小球,统一用数组变量
ballArr来保存小球变量;为了视觉效果,我们可以选择较亮丽的颜色封装成数组colorArr,此后生成的小球颜色将是随机的数组成员;同时的生成的小球初始坐标应该是当前鼠标的坐标// 3. 实例化小球 let ballArr = []; // 存放所有小球 let colorArr = ['red', 'green', 'blue', 'yellow', 'orange', 'purple', 'pink', 'skyblue']; // 小球颜色 // 4. 监听鼠标移动事件 canvas.addEventListener('mousemove',function(e){ e = e || window.event; let radius = _.random(30, 50); ballArr.push(new MoveBall(e.offsetX, e.offsetY, radius, colorArr[_.random(0, colorArr.length - 1)])); }); - 开启定时器,实现小球动态变化
// 5. 开启定时器 setInterval(function(){ // 清屏 ctx.clearRect(0, 0, canvas.width, canvas.height); for(let i = 0; i < ballArr.length; i++){ // 绘制小球 ballArr[i].render(); ballArr[i].upDate(); } },50);
- 扩展
- 可以在画布的左上方添加控件组,实现画布背景的切换,以及控制小球的运动状态(停止或运动)
// 2. 设置初始值 let isMoving = true; // 小球是否运动 let themeColor = "white"; // 画布背景颜色 // 5. 监听小球是否开启运动 document.getElementById('canvas-btn').addEventListener('click', function(e){ if(isMoving){ isMoving = false; this.text = "开始运动"; }else{ isMoving = true; this.text = "停止运动"; } return false; }); // 6. 监听画布背景颜色 document.getElementById('white-color-btn').addEventListener('click', function(e){ themeColor = "white"; return false; }); document.getElementById('black-color-btn').addEventListener('click', function(e){ themeColor = "black"; return false; }); // 7. 开启定时器 setInterval(function(){ // 清屏 ctx.clearRect(0, 0, canvas.width, canvas.height); // 设置画布背景颜色 if(themeColor == "black"){ ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); } for(let i = 0; i < ballArr.length; i++){ ctx.globalCompositeOperation = "xor"; // 绘制小球 ballArr[i].render(); // 如果处在运动状态,则更新小球 if(isMoving){ ballArr[i].upDate(); } } },50); - 这时候要注意的是,在停止运动状态下,仍需处理监听鼠标在画布上移动时,不该继续实例化小球
// 4. 监听鼠标移动事件 canvas.addEventListener('mousemove',function(e){ e = e || window.event; // 如果停止运动,则不产生新的小球 if(isMoving){ let radius = _.random(30, 50); ballArr.push(new MoveBall(e.offsetX, e.offsetY, radius, colorArr[_.random(0, colorArr.length - 1)])); } });