JavaScript动画实例之粒子文本的实现方法详解


Posted in Javascript onJuly 28, 2020

1.粒子文本的实现原理

粒子文本的实现原理是:使用两张 canvas,一张是用户看不到的canvas1,用来绘制文本;另一张是用户看到的canvas2,用来根据canvas1中绘制的文本数据来生成粒子。

先在canvas1中用如下的语句绘制待显示的文本。

ctx1.font = '100px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

然后使用canvas API的getImageData方法,获取一个ImageData对象,这个对象用来描述 canvas 指定区域内的像素数据。语句为:var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

这样imgData中保存了canvas1指定区域内所有像素点的rgba值,它是一个数组。由于每个像素点有 rgba 四个值,所以这个数组的长度也就是“像素点数量 * 4”。

最后通过遍历imgData数组,可以判断在canvas1中,哪些点是有色彩的(处于文本中间),哪些点是没有色彩的(不在文本上),把那些有色彩的像素位置记下来,然后在用户可见canvas2上生成粒子并绘制粒子即可。具体编程遍历imgData数组时,可以根据透明度,也就是 rgba 中的第4个元素是否不为0来判断该像素是否在文本中。

为此,创建一个自定义的粒子类Particle,该类中每个粒子对象有坐标位置(x,y)、半径radius和颜色color等4个属性;有一个方法draw(),用于绘制粒子。

编写的HTML代码如下。

<html>

<head>

<title>普通粒子文本</title>

</head>

<body>

<canvas hidden></canvas>

<canvas></canvas>

<script>

var canvas1=document.getElementById('myCanvas1');

ctx1= canvas1.getContext('2d');

var canvas2=document.getElementById('myCanvas2');

ctx2= canvas2.getContext('2d');

canvas1.width = canvas2.width = window.innerWidth;

canvas1.height = canvas2.height = window.innerHeight;

ctx1.font = '100px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

function Particle(x,y,radius,color)

{

this.x = x;

this.y = y;

this.radius = radius;

this.color = color;

}

Particle.prototype.draw= function()

{

ctx2.beginPath();

ctx2.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);

ctx2.fillStyle = this.color;

ctx2.fill();

ctx2.closePath();

}

var particles = [];

var skip =1;

for (var y = 0; y < canvas1.height; y +=skip)

{

for (var x = 0; x < canvas1.width; x += skip)

{

var opacityIndex = (x + y * canvas1.width) * 4 + 3;

if (imgData[opacityIndex] > 0)

{

var hue = Math.floor(Math.random() * 360);

var color=`hsl(${hue}, 100%, 50%)`;

particles.push(new Particle(x,y,2,color));

}

}

}

for (var particle of particles)

{

particle.draw();

}

</script>

</body>

</html>

在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中绘制出如图1所示的粒子文本。

JavaScript动画实例之粒子文本的实现方法详解

图1 skip=1时显示的粒子文本

由图1可以看出拼凑文本的粒子非常密集,这是因为程序中遍历的步长skip=1,这样扫描了canvas1指定区域内的所有像素点。实际上在形成粒子文本时,无需所有像素点一个像素一个像素地扫,可以增大skip值,使得最后产生的粒子稀疏些。

例如,将程序中的语句“skip=1”修改为“skip=4”,则在浏览器窗口中绘制出如图2所示的粒子文本。

JavaScript动画实例之粒子文本的实现方法详解

图2 skip=4时显示的粒子文本

2.粒子文本的动态效果

了解了普通粒子文本的实现原理后,可以为拼凑文本的粒子添加一些动态动效。从2个方面着手。

(1)给粒子赋予一些随机的位移,避免看上去过于整齐。

(2)粒子的大小随机产生,在创建粒子时对粒子初始半径radius 进行random 取随机值。另外为了让粒子半径动态改变,增加一个属性dynamicRadius,代表粒子的渲染半径,它根据粒子的初始半径radius,采用三角函数进行平滑改变。

编写如下的HTML代码。

<html>

<head>

<title>粒子文本的动态效果</title>

</head>

<body>

<canvas hidden></canvas>

<canvas></canvas>

<script>

var canvas1=document.getElementById('myCanvas1');

ctx1= canvas1.getContext('2d');

var canvas2=document.getElementById('myCanvas2');

ctx2= canvas2.getContext('2d');

canvas1.width = canvas2.width = window.innerWidth;

canvas1.height = canvas2.height = window.innerHeight;

ctx1.font = '120px PingFang SC';

ctx1.textAlign = 'center';

ctx1.baseline = 'middle';

ctx1.fillText('Happy New Year',canvas1.width/2, canvas1.height/2);

var imgData = ctx1.getImageData(0, 0, canvas1.width, canvas1.height).data;

function Particle(x,y,radius,color)

{

this.x = x;

this.y = y;

this.radius = radius;

this.color = color;

this.dynamicRadius = radius;

}

Particle.prototype.draw= function()

{

ctx2.beginPath();

ctx2.arc(this.x, this.y,this.dynamicRadius, 0, 2 * Math.PI, false);

ctx2.fillStyle = this.color;

ctx2.fill();

ctx2.closePath();

}

Particle.prototype.update= function()

{

this.dynamicRadius =3+2*Math.sin(new Date()/1000%1000*this.radius);

}

function random(min,max)

{

return Math.random() * ( max - min ) + min;

}

var particles = [];

var skip =4;

for (var y = 0; y < canvas1.height; y +=skip)

{

for (var x = 0; x < canvas1.width; x += skip)

{

var opacityIndex = (x + y * canvas1.width) * 4 + 3;

if (imgData[opacityIndex] > 0)

{

var hue = Math.floor(Math.random() * 360);

var color=`hsl(${hue}, 100%, 50%)`;

particles.push(new Particle(x+random(1,3),y+random(1,3),random(1,4),color));

}

}

}

for (var particle of particles)

{

particle.draw();

}

function loop()

{

requestAnimationFrame(loop);

ctx2.clearRect(0,0,canvas2.width,canvas2.height);

for (var particle of particles)

{

particle.update();

particle.draw();

}

}

loop();

</script>

</body>

</html>

在浏览器中打开包含这段HTML代码的html文件,可以看到在浏览器窗口中呈现出如图3所示的粒子文本动态效果。

JavaScript动画实例之粒子文本的实现方法详解

图3 粒子文本的动态效果

到此这篇关于JavaScript动画实例之粒子文本的实现方法详解的文章就介绍到这了,更多相关JavaScript动画实例之粒子文本内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Jquery乱码的一次解决过程 图解教程
Feb 20 Javascript
JavaScript基础语法让人疑惑的地方小结
May 23 Javascript
javascript中的nextSibling使用陷(da)阱(keng)
May 05 Javascript
js实现随屏幕滚动的带缓冲效果的右下角广告代码
Sep 04 Javascript
jQuery实现文本框邮箱输入自动补全效果
Nov 17 Javascript
jquery插件Jplayer使用方法简析
Apr 22 Javascript
微信小程序之获取当前位置经纬度以及地图显示详解
May 09 Javascript
在vue项目中使用Nprogress.js进度条的方法
Jan 31 Javascript
深入理解与使用keep-alive(配合router-view缓存整个路由页面)
Sep 25 Javascript
node 标准输入流和输出流代码实例
Sep 19 Javascript
vue3中provide && inject的使用
Jul 01 Vue.js
vue如何实现关闭对话框后刷新列表
Apr 08 Vue.js
Vue $emit()不能触发父组件方法的原因及解决
Jul 28 #Javascript
vue 遮罩层阻止默认滚动事件操作
Jul 28 #Javascript
JavaScript实现沿五角星形线摆动的小圆实例详解
Jul 28 #Javascript
处理JavaScript值为undefined的7个小技巧
Jul 28 #Javascript
vue中touch和click共存的解决方式
Jul 28 #Javascript
JS实现audio音频剪裁剪切复制播放与上传(步骤详解)
Jul 28 #Javascript
JavaScript中window和document用法详解
Jul 28 #Javascript
You might like
编写PHP脚本来实现WordPress中评论分页的功能
2015/12/10 PHP
Mootools 1.2教程 输入过滤第一部分(数字)
2009/09/15 Javascript
判断多个input type=file是否有已经选择好文件的代码
2012/05/23 Javascript
jquery 简单应用示例总结
2013/08/09 Javascript
JS JQUERY实现滚动条自动滚到底的方法
2015/01/09 Javascript
如何使用PHP+jQuery+MySQL实现异步加载ECharts地图数据(附源码下载)
2016/02/23 Javascript
Bootstrap基本插件学习笔记之按钮(21)
2016/12/08 Javascript
解决vue 绑定对象内点击事件失效问题
2018/09/05 Javascript
vue滑动吸顶及锚点定位的示例代码
2020/05/10 Javascript
浅谈vue使用axios的回调函数中this不指向vue实例,为undefined
2020/09/21 Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
2020/10/21 Javascript
浅谈Vue开发人员的7个最好的VSCode扩展
2021/01/20 Vue.js
[51:17]VGJ.T vs Mineski 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
使用python开发vim插件及心得分享
2014/11/04 Python
numpy中实现ndarray数组返回符合特定条件的索引方法
2018/04/17 Python
基于windows下pip安装python模块时报错总结
2018/06/12 Python
python单例设计模式实现解析
2020/01/07 Python
收集的22款给力的HTML5和CSS3帮助工具
2012/09/14 HTML / CSS
拥有超过850家商店的美国在线派对商店:Party City
2018/10/21 全球购物
英国购买威士忌网站:Master of Malt
2019/09/26 全球购物
俄罗斯最大的香水和化妆品网上商店:Randewoo
2020/11/05 全球购物
机械专业毕业生自荐信
2013/11/02 职场文书
往来会计岗位职责
2013/12/19 职场文书
简洁的英文求职信范文
2014/05/03 职场文书
优秀工会工作者事迹材料
2014/06/02 职场文书
2014企业领导班子四风对照检查材料思想汇报
2014/09/17 职场文书
专题民主生活会对照检查材料思想汇报
2014/09/29 职场文书
党员四风问题个人对照检查材料
2014/10/26 职场文书
安全责任书
2015/01/29 职场文书
行政主管岗位职责
2015/02/03 职场文书
防暑降温通知书
2015/04/27 职场文书
2015迎新晚会开场白
2015/05/29 职场文书
幼儿园小朋友毕业感言
2015/07/30 职场文书
redis 限制内存使用大小的实现
2021/05/08 Redis
Python 统计序列中元素的出现频度
2022/04/26 Python
Redis基本数据类型Zset有序集合常用操作
2022/06/01 Redis