源码动态 源码评测 源码技巧 网站运营 网页制作 网站开发 安全相关 软件教程 IDC资讯 业界消息
高级搜索
关键字:Discuz!  Axure  团购系统
最新更新发布资源提建议收藏本站
当前位置:A5源码 > 资讯报道 > 网页制作 > 详解Canvas 实现炫丽的粒子运动效果(粒子生成文字)

详解Canvas 实现炫丽的粒子运动效果(粒子生成文字)

作者:zy来源:未知浏览:时间:2018-02-02 14:38我要评论
没有最好,只有更好,如题所示,这篇文章只要是分享一个用 Canvas 来实现的粒子运动效果。感觉有点标题党了,但换个角度,勉勉强强算是炫丽吧,虽然色彩上与炫丽无关,但运动效果上还是算得上有点点炫的。不管怎么样,我们还是开始这个所谓的炫丽效果吧!

没有最好,只有更好,如题所示,这篇文章只要是分享一个用 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…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 代码,不过,在看代码前,我们不妨先听听实现这个效果的思路:

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

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

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

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; }

看了代码估计也只是心里炫了一下,也没有让你想把这个东西做出来的欲望,为此我知道必需得让你眼睛心服口服才行。在线 DEMO: 动感的粒子示例。

人无完人,代码也一样。看起来运行顺畅的代码也或多或少有一些瑕疵,日前这个效果还只支持中文。英文的话,我得再努力一把,不管怎么样,英文后面肯定是会加入来的,只是时间问题了。还有代码中用于标记是否可再次执行生成文字的 属性:this.isPlay ,还是一点瑕疵,this.isPlay 的状态更改没有准确的在粒子归位的那一瞬间更改,而是提前更改了状态。但这个状态不会影响本例子效果的完整实现。

这个例子中用到了 dynamics.js 库,主要是用到它里面的一些运动函数,让粒子动起来更感人一些,仅此而已。

相关文章
网友对“详解Canvas 实现炫丽的粒子运动效果(粒子生成文字)”的评论
资讯分类
本类热门资讯
  • 源码推荐
  • 软件推荐
关于我们联系我们发布资源广告服务合作伙伴网站地图版权声明与我们对话