大家好,我是小丞同学,一名前端爱好者
欢迎访问博主的个人网站:一口奶盖
“在人间贩卖声音 等凑够满天星辰 放烟花给你看”
上次的烟花有些许平淡,这次来放大招了,让你的名字在天空绽放!
喜欢的话可以私信源码去晒狗粮噢~
全程高能,无尿点,有部分内容在上期的文章中噢~
实现效果
你以为仅此而已吗,后面还有大招噢
实现过程
1. 在画布上绘制文字
通过ctx.font
设定字体的大小以及字体,再填充颜色,最后通过ctx.fillText
绘制到画布当中,这里有几个需要注意的地方:
注意:
-
ctx.font
至少需要两个参数,一个字体大小,一个字体 - 这里的颜色之所以设为
#000001
原因是背景是黑色的,这样这个字不会被看到,但是它是真实存在的,不然每次点击时都会有一个字体生成在左上角,影响视觉,当然也可以新建在一个画布,这里就简单处理了 -
ctx.measureText(text)
:返回一个对象,该对象包含以像素计的指定字体宽度。
// 填充字体样式
let font = 120
ctx.font = font + "px '微软雅黑'"
ctx.fillStyle = "#000001"
// 内容
let text = '小丞同学'
// 获取字体的宽度
let textWidth = ctx.measureText(text).width
// 在左上角填充字体
ctx.fillText(text,0 , font)
2. 获取像素点
通过ctx.getImageData
可以获取一个区域内的像素数据,返回的是一个imageData
对象
对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:
- R - 红色 (0-255)
- G - 绿色 (0-255)
- B - 蓝色 (0-255)
- A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
在前面的代码中我们在 (0,0) 的位置绘制了字体,我们通过getImageData
将这块区域的像素信息取出来。
let imgData = ctx.getImageData(0, 0, textWidth, font * 1.2)
我们先看看imgData
,可以看到里面的数据十分庞大,里面存储的是像素信息
这样我们可以通过判断这些像素点来实现粒子的效果
3. 实现文字粒子化
在上面一步中我们已经将文字的像素信息得到了,也就相当于我们复制了一个文字,我们可以遍历整个imgData.data
数组就能绘制出原先的文字,那我们要实现粒子化的效果,就需要隔几个像素格再绘制,这样绘制处理的图形就会是一个粒子化的效果,原因就是部分位置的像素,没有进行渲染
for (let h = 0; h < font * 1.2; h += 6) {
for (let w = 0; w < textWidth; w += 6) {
let position = (textWidth * h + w) * 4;
// 返回的数组是rgba的方式存储
let r = imgData.data[position],
g = imgData.data[position + 1],
b = imgData.data[position + 2],
a = imgData.data[position + 3];
if (r + g + b == 0) {
continue
}
//烟花代码
}
}
在上面的代码块中,遍历了从左到右,从上到下,遍历了整个图形区域的全部像素信息,r,g,b,a
对应一个某个像素点的颜色,当颜色不为黑色时,我们不对它进行操作,跳过此轮循环,当颜色不为黑色时,利用该点的信息生成一个烟花粒子
let firework = {};
firework.x = x;
firework.y = y;
firework.fx = x + w - textWidth / 2;
firework.fy = y + h - font / 2;
firework.size = Math.floor(Math.random() * 2) + 1;
firework.speed = 1;
setColors(firework);
fireworks.push(firework);
烟花粒子对象存入烟花数组中
4. 设置粒子动画
现在我们已经得到了一整个即将绽放的烟花数组,我们只需要给他们加上动画,通过每次渲染时改变当前粒子的坐标,降低透明度实现烟花殆尽的效果,直至烟花粒子透明度降为0
关键代码
firework.x += (firework.fx - firework.x) / 10;
firework.y += (firework.fy - firework.y) / 10 - (firework.alpha - 1) * firework.speed;
firework.alpha -= 0.01;
// 如果透明度小于0就删除这个粒子
if (firework.alpha <= 0) {
fireworks.splice(i, 1);
// 跳过这次循环,不进行绘制
continue;
}
5. 设置拖尾并渲染更新画布
拖尾实现的思路是不断的添加一个半透明的蒙层来实现,使用 requestAnimationFrame
于定时器的区别在上篇文章有讲过噢
function tick() {
// // 设置拖影
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(0,0,0,' + 10 / 100 + ')';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'lighter';
// 更新画布
drawFires();
requestAnimationFrame(tick);
}
总结
今天的烟花就到这里反映结束了,不过瘾的话,可以让我们一起期待下一篇图片烟花效果噢~摩尔庄园的烟花也很好看噢!