温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用Canvas怎么实现一个炫丽的粒子运动效果

发布时间:2021-04-16 17:09:27 来源:亿速云 阅读:209 作者:Leah 栏目:web开发

使用Canvas怎么实现一个炫丽的粒子运动效果?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

html 代码

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Canvas 实现炫丽的粒子运动效果-云库前端</title> <style> * {     margin: 0;     padding: 0; } html, body {     width: 100%;     height: 100%; } canvas {     display: block;     background: #000; } body::-webkit-scrollbar{     display: none; } .operator-box{     position: fixed;     top: 0;     left: 50%;     border: 1px solid #fff;     background: rgba(255,255,255,0.5);     padding: 20px 10px;     -webkit-transform: translateX(-50%);     transform: translateX(-50%); } .back-type,.back-animate{     margin-right: 20px; } .flex-box{     display: flex;     justify-content: center;     align-items: center; } #input-text{     line-height: 35px;     width: 260px;     height: 35px;     background: rgba(0, 0, 0,0.7);     color: #fff;     font-size: 16px;     border: none;     outline: none;     text-indent: 12px;     box-shadow: inset 0 0 12px 1px rgba(0,0,0,0.7); } #input-text::placeholder{     color: #ccc;     line-height: 55px;     height: 55px; } select{     -webkit-appearance: none;     -moz-appearance: none;     appearance: none;     border: none;     padding: 0px 20px 0px 6px;     height: 35px;     color: #fff;     text-align: left;     background: rgba(0, 0, 0,0.7) url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAICAYAAAAx8TU7AAAAOUlEQ&hellip;R4gPgWEIMAiOYBCS4C8ZDAIrBq4gigNkztQEFMi6AuQHESAPMeXiEMiWfpAAAAAElFTkSuQmCC) no-repeat 190px 12px;     background-size: 5px 8px;     box-shadow: inset 0 0 12px 1px rgba(0,0,0,0.7); } </style> </head> <body> <div class="operator-box"> <div class="flex-box">     <div class="back-type">散开类型:         <select name="" id="selectType">             <option value="back">归位</option>             <option value="auto">随机</option>         </select>     </div>     <div class="back-animate">散开效果(对归位有效):        <select class="back-dynamics" id="selectDynamics">            <option value="spring">dynamics.spring</option>            <option value="bounce">dynamics.bounce</option>            <option value="forceWithGravity">dynamics.forceWithGravity</option>            <option value="gravity">dynamics.gravity</option>            <option value="easeInOut">dynamics.easeInOut</option>            <option value="easeIn">dynamics.easeIn</option>            <option value="easeOut">dynamics.easeOut</option>            <option value="linear">dynamics.linear</option>        </select>     </div>     <div class="input-box"><input type="text" placeholder="输入汉字后回车" id="input-text"></div> </div> </div> <script src="dynamics.min.js"></script> <script src="index.js"></script> <script> var iCircle = new Circle(); </script> </body> </html>

HTML 代码不多,只要是几个操作元素。这里一看就明白。不费过多口舌。我们来看看本文的主角 JavaScript 代码,不过,在看代码前,我们不妨先听听实现这个效果的思路:

  1. 首先,我们得先生成一堆群众演员(粒子);

  2. 把每个粒子的相关参数挂到自身的一些属性上,因为第个粒子都会有自己的运动轨迹;

  3. 接着得让它们各自运动起来。运动有两种(自由运动和生成文字的运动);

JavaScript 代码中使用了三个 Canvas 画布,this.iCanvas(主场)、this.iCanvasCalculate(用来计算文字宽度)、this.iCanvasPixel(用于画出文字,并从中得到文字对应的像素点的位置坐标)。

this.iCanvasCalculate 和 this.iCanvasPixel 这两个无需在页面中显示出来,只是辅助作用。

下面就献上棒棒的 JS 实现代码

function Circle() {     var This = this;     this.init();     this.generalRandomParam();     this.drawCircles();     this.ballAnimate();     this.getUserText();     // 窗口改变大小后,生计算并获取画面     window.onresize = function(){         This.stateW = document.body.offsetWidth;         This.stateH = document.body.offsetHeight;         This.iCanvasW = This.iCanvas.width = This.stateW;         This.iCanvasH = This.iCanvas.height = This.stateH;         This.ctx = This.iCanvas.getContext("2d");     } } // 初始化 Circle.prototype.init = function(){     //父元素宽高     this.stateW = document.body.offsetWidth;     this.stateH = document.body.offsetHeight;     this.iCanvas = document.createElement("canvas");     // 设置Canvas 与父元素同宽高     this.iCanvasW = this.iCanvas.width = this.stateW;     this.iCanvasH = this.iCanvas.height = this.stateH;     // 获取 2d 绘画环境     this.ctx = this.iCanvas.getContext("2d");     // 插入到 body 元素中     document.body.appendChild(this.iCanvas);     this.iCanvasCalculate = document.createElement("canvas");     // 用于保存计算文字宽度的画布     this.mCtx =  this.iCanvasCalculate.getContext("2d");     this.mCtx.font = "128px 微软雅黑";     this.iCanvasPixel = document.createElement("canvas");     this.iCanvasPixel.setAttribute("style","position:absolute;top:0;left:0;");     this.pCtx = null; // 用于绘画文字的画布     // 随机生成圆的数量     this.ballNumber = ramdomNumber(1000, 2000);     // 保存所有小球的数组     this.balls = [];     // 保存动画中最后一个停止运动的小球     this.animte = null;     this.imageData = null;     this.textWidth = 0; // 保存生成文字的宽度     this.textHeight = 150; // 保存生成文字的高度     this.inputText = ""; // 保存用户输入的内容     this.actionCount = 0;     this.ballActor = []; // 保存生成文字的粒子     this.actorNumber = 0; // 保存生成文字的粒子数量     this.backType = "back"; // 归位     this.backDynamics = ""; // 动画效果     this.isPlay = false; // 标识(在生成文字过程中,不能再生成) } // 渲染出所有圆 Circle.prototype.drawCircles = function () {     for(var i=0;i<this.ballNumber;i++){         this.renderBall(this.balls[0]);     } } // 获取用户输入文字 Circle.prototype.getUserText = function(){     This = this; // 保存 this 指向     ipu = document.getElementById("input-text");     ipu.addEventListener("keydown",function(event){         if(event.which === 13){ // 如果是回车键             ipu.value = ipu.value.trim(); // 去头尾空格             var pat = /[\u4e00-\u9fa5]/; // 中文判断             var isChinese = pat.test(ipu.value);             if(ipu.value.length !=0 && isChinese){                 This.inputText = ipu.value;             }else{                 alert("请输入汉字");                 return;             }             if(This.isPlay){                 return             }             This.getAnimateType();             This.getTextPixel();             This.isPlay = true;         }     }); } // 计算文字的宽 Circle.prototype.calculateTextWidth = function () {     this.textWidth = this.mCtx.measureText(this.inputText).width; } // 获取文字像素点 Circle.prototype.getTextPixel = function () {     if(this.pCtx){         this.pCtx.clearRect(0,0,this.textWidth,this.textHeight);     }     this.calculateTextWidth(this.inputText);     this.iCanvasPixel.width = this.textWidth;     this.iCanvasPixel.height = this.textHeight;     this.pCtx =  this.iCanvasPixel.getContext("2d");     this.pCtx.font = "128px 微软雅黑";     this.pCtx.fillStyle = "#FF0000";     this.pCtx.textBaseline = "botom";     this.pCtx.fillText(this.inputText,0,110);     this.imageData = this.pCtx.getImageData(0,0,this.textWidth,this.textHeight).data;     this.getTextPixelPosition(this.textWidth,this.textHeight); } // 获取文字粒子像素点位置 Circle.prototype.getTextPixelPosition = function (width,height) {     var left = (this.iCanvasW - width)/2;     var top = (this.iCanvasH - height)/2;     var space = 4;     this.actionCount = 0;     for(var i=0;i<this.textHeight;i+=space){         for(var j=0;j<this.textWidth;j+=space){             var index = j*space+i*this.textWidth*4;             if(this.imageData[index] == 255){                 if(this.actionCount<this.ballNumber){                     this.balls[this.actionCount].status = 1;                     this.balls[this.actionCount].targetX = left+j;                     this.balls[this.actionCount].targetY = top+i;                     this.balls[this.actionCount].backX = this.balls[this.actionCount].x;                     this.balls[this.actionCount].backY = this.balls[this.actionCount].y;                     this.ballActor.push(this.balls[this.actionCount]);                     this.actionCount++;                 }             }         }         this.actorNumber = this.ballActor.length;     }     this.animateToText(); } // 粒子运动到指定位置 Circle.prototype.animateToText = function(){     for(var i=0;i<This.actorNumber;i++){         dynamics.animate(This.ballActor[i], {           x: this.ballActor[i].targetX,           y: this.ballActor[i].targetY         },{             type: dynamics.easeIn,             duration: 1024,         });     }     setTimeout(function(){         This.ballbackType();     },3000); } // 粒子原路返回 Circle.prototype.ballBackPosition = function(){     for(var i=0;i<This.actorNumber;i++){         var ball = This.ballActor[i];         dynamics.animate(ball, {           x: ball.backX,           y: ball.backY         },{             type: dynamics[this.backDynamics],             duration: 991,             complete:this.changeStatus(ball)         });     } } // 获取类型|动画效果 Circle.prototype.getAnimateType = function() {     var selectType = document.getElementById("selectType");     var selectDynamics = document.getElementById("selectDynamics");     this.backType = selectType.options[selectType.options.selectedIndex].value;     this.backDynamics = selectDynamics.options[selectDynamics.options.selectedIndex].value; } // 复位散开 Circle.prototype.ballbackType = function(){     if(this.backType == "back"){         this.ballBackPosition();     }else{         this.ballAutoPosition();     }     this.ballActor = []; } // 随机散开 Circle.prototype.ballAutoPosition = function(ball){     for(var i=0;i<this.actorNumber;i++){         this.changeStatus(this.ballActor[i])     } } // 更改小球状态 Circle.prototype.changeStatus = function(ball){     ball.status = 0;     if(this.isPlay == true){         this.isPlay = false;     } } // 随机生成每个圆的相关参数 Circle.prototype.generalRandomParam = function(){     for(var i=0;i<this.ballNumber;i++){         var ball = {};         ball.size = 1; // 随机生成圆半径         // 随机生成圆心 x 坐标         ball.x = ramdomNumber(0+ball.size, this.iCanvasW-ball.size);         ball.y = ramdomNumber(0+ball.size, this.iCanvasH-ball.size);         ball.speedX = ramdomNumber(-1, 1);         ball.speedY = ramdomNumber(-1, 1);         this.balls.push(ball);         ball.status = 0;         ball.targetX = 0;         ball.targetY = 0;         ball.backX = 0;         ball.backY = 0;     } } // 改变圆的位置 Circle.prototype.changeposition = function(){     for(var i=0;i<this.ballNumber;i++){         if( this.balls[i].status == 0){             this.balls[i].x += this.balls[i].speedX;             this.balls[i].y += this.balls[i].speedY;         }     } } // 画圆 Circle.prototype.renderBall = function(ball){     this.ctx.fillStyle = "#fff";     this.ctx.beginPath(); // 这个一定要加     this.ctx.arc(ball.x, ball.y, ball.size, 0, 2 * Math.PI);     this.ctx.closePath(); // 这个一定要加     this.ctx.fill(); } // 小球碰撞判断 Circle.prototype.collision = function(ball){     for(var i=0;i<this.ballNumber;i++){        if(ball.x>this.iCanvasW-ball.size || ball.x<ball.size){             if(ball.x>this.iCanvasW-ball.size){                 ball.x = this.iCanvasW-ball.size;             }else{                 ball.x = ball.size;             }             ball.speedX = - ball.speedX;        }        if(ball.y>this.iCanvasH-ball.size || ball.y<ball.size){             if(ball.y>this.iCanvasH-ball.size){                 ball.y = this.iCanvasH-ball.size;             }else{                 ball.y = ball.size;             }             ball.speedY = - ball.speedY;        }     } } // 开始动画 Circle.prototype.ballAnimate = function(){     var This = this;     var animateFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;     (function move(){         animte = animateFrame(move);         This.ctx.clearRect(0, 0, This.iCanvasW, This.iCanvasH);         This.changeposition();         for(var i=0;i<This.ballNumber;i++){            This.collision(This.balls[i]);            This.renderBall(This.balls[i]);         }     })(); } // 生成一个随机数 function ramdomNumber(min, max) {     return Math.random() * (max - min) + min; }

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI