JavaScript动画实例:粒子文本
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 id="myCanvas1" style="position: absolute; " hidden></canvas>
<canvas id="myCanvas2" style="position: absolute;"></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所示的粒子文本。

图1 skip=1时显示的粒子文本
由图1可以看出拼凑文本的粒子非常密集,这是因为程序中遍历的步长skip=1,这样扫描了canvas1指定区域内的所有像素点。实际上在形成粒子文本时,无需所有像素点一个像素一个像素地扫,可以增大skip值,使得最后产生的粒子稀疏些。
例如,将程序中的语句“skip=1”修改为“skip=4”,则在浏览器窗口中绘制出如图2所示的粒子文本。

图2 skip=4时显示的粒子文本
2.粒子文本的动态效果
了解了普通粒子文本的实现原理后,可以为拼凑文本的粒子添加一些动态动效。从2个方面着手。
(1)给粒子赋予一些随机的位移,避免看上去过于整齐。
(2)粒子的大小随机产生,在创建粒子时对粒子初始半径radius 进行random 取随机值。另外为了让粒子半径动态改变,增加一个属性dynamicRadius,代表粒子的渲染半径,它根据粒子的初始半径radius,采用三角函数进行平滑改变。
编写如下的HTML代码。
<html>
<head>
<title>粒子文本的动态效果</title>
</head>
<body>
<canvas id="myCanvas1" style="position: absolute; " hidden></canvas>
<canvas id="myCanvas2" style="position: absolute;"></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所示的粒子文本动态效果。

图3 粒子文本的动态效果
JavaScript动画实例:粒子文本的更多相关文章
- JavaScript动画实例:李萨如曲线
在“JavaScript图形实例:阿基米德螺线”和“JavaScript图形实例:曲线方程”中,我们学习了利用曲线的方程绘制曲线的方法.如果想看看曲线是怎样绘制出来的,怎么办呢?编写简单的动画,就可以 ...
- JavaScript动画实例:递归分形图动态展示
在“JavaScript图形实例:SierPinski三角形” 和“JavaScript图形实例:Levy曲线及其变形”等文章中我们介绍了通过递归生成分形图形的方法.我们可以将绘制的分形图形每隔一定的 ...
- JavaScript动画实例:曲线的绘制
在“JavaScript图形实例:曲线方程”一文中,我们给出了15个曲线方程绘制图形的实例.这些曲线都是根据其曲线方程,在[0,2π]区间取一系列角度值,根据给定角度值计算对应的各点坐标,然后在计算出 ...
- JavaScript动画实例:旋转的圆球
1.绕椭圆轨道旋转的圆球 在Canvas画布中绘制一个椭圆,然后在椭圆上绘制一个用绿色填充的实心圆.之后每隔0.1秒刷新,重新绘制椭圆和实心圆,重新绘制时,实心圆的圆心坐标发生变化,但圆心坐标仍然位于 ...
- JavaScript动画实例:动感小球
已知圆的坐标方程为: X=R*SIN(θ) Y=R*COS(θ) (0≤θ≤2π) 将0~2π区间等分48段,即设定间隔dig的值为π/24.θ初始值从0开始,按曲线方程求得坐标值(x,y), ...
- JavaScript动画实例:旋转的正三角形
给定一个正三角形的重心坐标为(x0,y0),高为h,可以用如下的语句绘制一个底边水平的正三角形. ctx.beginPath(); ctx.moveTo(x0,y0-h*2/3); ctx.lineT ...
- JavaScript动画实例:沿五角星形线摆动的小圆
五角星形线的笛卡尔坐标方程式可设为: r=10+(3*sin(θ*2.5))^2 x=r*cos(θ) y=r*sin(θ) (0≤θ≤2π) 根据这个曲线方程,在[0,2 ...
- JavaScript动画实例:炸开的小球
1.炸开的小球 定义一个小球对象类Ball,它有6个属性:圆心坐标(x,y).小球半径radius.填充颜色color.圆心坐标水平方向的变化量speedX.圆心坐标垂直方向的变化量speedY. B ...
- JavaScript动画实例:螺旋线
数学中有各式各样富含诗意的曲线,螺旋线就是其中比较特别的一类.螺旋线这个名词来源于希腊文,它的原意是“旋卷”或“缠卷”.例如,平面螺旋便是以一个固定点开始向外逐圈旋绕而形成的曲线.在2000多年以前, ...
随机推荐
- Head_First_Python(中文版)完整版PDF免费下载_百度云盘
Head_First_Python(中文版)完整版PDF免费下载_百度云盘 提取码:bjbg 本书特色 根据认知科学和学习理论的最新研究成果,这本书采用一种适合大脑的丰富格式娓娓道来,而不是长篇累牍地 ...
- Java内存溢出OutOfMemoryError的产生与排查
在java的虚拟机异常中,有两个异常是大家比较关心的,一个是StackOverflowError,另一个是OutOfMemoryError.今天我们就来看看OutOfMemoryError是怎么产生的 ...
- 事务的特性ACID、隔离级别
1.事务特性ACID 1.1 事务的四大特性 1.原子性(Atomicity) 事务包装的一组sql,要么都执行成功,要么都失败.这些操作是不可分割的. 2.一致性(Consistency) 数据库的 ...
- hdoj3791
题目: Problem Description 判断两序列是否为同一二叉搜索树序列 Input 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束.接下去 ...
- Beta冲刺<4/10>
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺--第四天(05.22) 作业正文 如下 其他参考文献 ... B ...
- 微信小程序-工具的下载与安装
QQ讨论群:785071190 安装开发工具 前往 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装,有关开发者工具更详细的介绍可以查看 <开发者工具介绍> .工具安装非常 ...
- Java深拷贝和浅拷贝的区别
浅拷贝 被复制的对象的所有的变量都与原对象有相同的值,而所有的引用对象仍然指向原来的对象.换言之,浅拷贝 不复制引用对象. 1 class Experience { 2 private String ...
- Linux查看docker容器日志
docker logs -f 容器名或ID | grep fail | more grep fail:过滤包含fail的日志内容
- 在linux上安装jdk(转载)
软件环境: 虚拟机:VMware Workstation 10 操作系统:Ubuntu-12.04-desktop-amd64 JAVA版本:jdk-7u55-linux-x64 软件下载地址: JD ...
- python-多任务-进程
什么是进程? 程序是静态的,当程序运行起来就叫做进程. 进程是操作系统分配资源的基本单元. 进程.线程的区别与优缺点 1. 定义的不同: 进程是系统进行资源分配的最小单位. 线程是进程的一个实体,是C ...