canvas文字粒子效果 html+css+js 3点饮茶,7点放工,美滋滋~
【摘要】 先言: 今天3点多在饮茶的时候,发现有好几天没发文章了,但是太难的玩意又不会啊,咋办,突然想起电脑里还有存着一个文字粒子特效,好家伙,这不就来了,先看效果如下: 实现步骤(完整源码放在最后): 1.获取画布 //获取画布 var canvas = document.getElementById('canvas'); var ctx = canvas.getCon...
先言:
今天3点多在饮茶的时候,发现有好几天没发文章了,但是太难的玩意又不会啊,咋办,突然想起电脑里还有存着一个文字粒子特效,好家伙,这不就来了,先看效果如下:
实现步骤(完整源码放在最后):
1.获取画布
//获取画布
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
2.绘制基本文字
// 先在画布绘制一串文字,大小可以自己调,我这30px,6个字,大概搞个180px*30px的大小,背景色为黑色
ctx.font = "30px fangsong";
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.fillText("北极光之夜。",0,30,180);
3.获取文字的像素位置等
// getImageData()可以获取画布上指定矩形的像素数据,把那上面文字所在区域的的像素保存起来
var pix = ctx.getImageData(0,0,180,35);
getImageData() 复制画布上指定矩形的像素数据。
getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
R - 红色 (0-255)
G - 绿色 (0-255)
B - 蓝色 (0-255)
A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
color/alpha 以数组形式存在,并存储于 ImageData 对象的 data 属性中。
4.画布动态适应屏幕大小
// 画布动态适应屏幕大小
window.addEventListener('resize',canvasResize);
function canvasResize(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
canvasResize();
5.设置变量
// 这是等会绘制粒子文字的处于窗口大概位置
var cx = canvas.width/2-(180*5/2);
var cy = canvas.height/2-(35*5/2);
6. 定义 Particle,实现粒子基本信息初始化方法,绘制粒子方法,更新位置方法
//定义一个Particle类
class Particle{
constructor(){
//定义一个数组,存放每个粒子的信息
this.arr = [];
}
//初始化每个粒子信息
init(){
//循环,像素是以4个数据为一组的
for(let i=0;i<pix.data.length/4;i++){
this.arr.push({
//文字像素本该的处于的水平位置
x:i%180,
//文字像素本该的处于的垂直位置
y:i/180,
// 透明度
alpha:pix.data[i*4+3],
//给个随机水平位置,粒子运动 mx ---》x
mx:Math.random()*canvas.width,
//给个随机垂直位置,粒子运动 my ---》y
my:Math.random()*canvas.height,
//粒子半径
radius:Math.random()*3,
//粒子速度
speed:Math.random()*40+40,
//粒子随机颜色
color:`rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255},${pix.data[i*4+3]}`
})
}
}
//绘制
draw(){
//遍历arr数组
this.arr.forEach(item=>{
//下面就是绘制每个小圆了
ctx.beginPath();
ctx.fillStyle = item.color;
ctx.arc(item.mx,item.my,item.radius,0,Math.PI*2,false);
ctx.fill();
})
}
//粒子位置更新
update(){
for(let i=0;i<this.arr.length;i++){
//粒子运动 mx ---》x , my ---》y , 采用缓动动画原理
//当然,如果粒子移动到原先的位置的话,岂不是太小,就文字就30px大小,所以位置改为x*5+cx,y*5+cy
this.arr[i].mx = this.arr[i].mx + ((this.arr[i].x*5+cx)-this.arr[i].mx)/this.arr[i].speed;
this.arr[i].my = this.arr[i].my + ((this.arr[i].y*5+cy)-this.arr[i].my)/this.arr[i].speed;
}
}
}
7. new一个 Particle,然后初始化
const particle = new Particle();
particle.init();
8.执行粒子运动动画
function step(){
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.fillRect(0,0,canvas.width,canvas.height);
particle.draw();
particle.update();
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
9. 窗口大小改变重新初始化:
window.addEventListener('resize',function(){
particle.arr = [];
particle.init();
cx = canvas.width/2-(180*5/2);
cy = canvas.height/2-(35*5/2);
})
完整代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>北极光之夜。</title>
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: rgb(0, 0, 0);
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.font = "30px fangsong";
ctx.fillStyle = "rgb(0, 0, 0)";
ctx.fillText("北极光之夜。",0,30,180);
var pix = ctx.getImageData(0,0,180,35);
window.addEventListener('resize',canvasResize);
function canvasResize(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
canvasResize();
var cx = canvas.width/2-(180*5/2);
var cy = canvas.height/2-(35*5/2);
class Particle{
constructor(){
this.arr = [];
}
init(){
for(let i=0;i<pix.data.length/4;i++){
this.arr.push({
x:i%180,
y:i/180,
alpha:pix.data[i*4+3],
mx:Math.random()*canvas.width,
my:Math.random()*canvas.height,
radius:Math.random()*3,
speed:Math.random()*40+40,
color:`rgba(${Math.random()*255}, ${Math.random()*255}, ${Math.random()*255},${pix.data[i*4+3]}`
})
}
}
draw(){
this.arr.forEach(item=>{
ctx.beginPath();
ctx.fillStyle = item.color;
ctx.arc(item.mx,item.my,item.radius,0,Math.PI*2,false);
ctx.fill();
})
}
update(){
for(let i=0;i<this.arr.length;i++){
this.arr[i].mx = this.arr[i].mx + ((this.arr[i].x*5+cx)-this.arr[i].mx)/this.arr[i].speed;
this.arr[i].my = this.arr[i].my + ((this.arr[i].y*5+cy)-this.arr[i].my)/this.arr[i].speed;
}
}
}
const particle = new Particle();
particle.init();
window.addEventListener('resize',function(){
particle.arr = [];
particle.init();
cx = canvas.width/2-(180*5/2);
cy = canvas.height/2-(35*5/2);
})
function step(){
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.fillRect(0,0,canvas.width,canvas.height);
particle.draw();
particle.update();
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
</script>
</body>
</html>
总结:
大功告成,又可以继续饮茶了,饮到7点放工~
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)