之前我出了一个如何在网页里使用原生 JS 开发放烟花效果的教程。
竟然有一个前端小阿姨问我,如果想要烟花放出来是文字的话怎么实现,她要给男朋友做一个。
好家伙,这狗粮洒一地呀
那狗粮不能我一个人吃,分享出来,大家一起吃。
此文配有 视频教程,边吃边看,狗粮更香。
你身边有这样的程序员小姐姐吗?
之前烟花源码里的核心是,我们在创建烟花粒子的时候,赋值了烟花绽放的原点x
,y
和圆形烟花的半径radius
。在绘制烟花动效时,半径不断加大,烟花的动效就出来。
//篇幅限制,仅展现部分代码
function createFireworks(x, y) {
var count = 100;
for (var i = 0; i < count; i++) {
var p = {};
p.x = x;
p.y = y;
p.speed = (Math.random() * 5) + .4;
p.radius = p.speed;
}
}
function drawFireworks(){
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
var vx = Math.cos(p.radians) * p.radius;
var vy = Math.sin(p.radians) * p.radius + 0.4;
p.x += vx;
p.y += vy;
p.radius *= 1 - p.speed / 100;
}
}
但要实现文字烟花,我们一开始就要把烟花最后的x
,y
坐标全部精确的计算出来。所以这个烟花的绘制,我们要更改一下逻辑。在createFireworks
阶段,就计算出单个粒子的起点 x,y
和终点 fx,fy
。
代码修改后如下
//篇幅限制,仅展现部分代码
function createFireworks(x, y){
var count = 100;
for (var i = 0; i < count; i++) {
var angle = 360 / count * i;
var p = {};
p.x = x;
p.y = y;
p.radians = angle * Math.PI / 180;
p.radius = Math.random()*81+50;
p.fx = x + Math.cos(radians) * p.radius;
p.fy = y + Math.sin(radians) * p.radius;
}
}
function drawFireworks() {
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
p.x += (p.fx - p.x)/10;
p.y += (p.fy - p.y)/10-(p.alpha-1)*p.speed;
}
}
这样我们就完成了第一步改造,后续我们要把文字写在画布上,并且将其转换为点阵数组,也就是所有烟花粒子的终点坐标。
其实和之前那篇《使用 Javascript 制作 BadApple 字符画视频》的原理是一样的。通过canvas
的 APIgetImageData
来获得画布指定区域内的全部点阵信息(rgba
数组)。
将createFireworks
方法改造如下
function createFireworks(x,y,text=""){
if(text!=""){
//绘制文字
}else{
//原有的烟花代码
}
}
传递一个text
参数,当此参数不为空时,我们进入文字烟花的绘制逻辑。
var fontSize = 120;
var textHeight = fontSize;
context.font=fontSize+"px Verdana";
context.fillStyle = "#ffffff";
context.fillText(text,0,textHeight);
这样我们就能把字绘制在画布上了,接着我们使用getImageData
来获得并裁剪点阵信息,因为我们只要一部分的点阵。
var imgData = textctx.getImageData(0,0,textWidth,textHeight);
for (var h = 0; h < textHeight; h+=gap) {
for(var w = 0; w < textWidth; w+=gap){
var position = (textWidth * h + w) * 4;
var r = imgData.data[position], g = imgData.data[position + 1], b = imgData.data[position + 2], a = imgData.data[position + 3];
}
}
这样我们就拿到了画布里文字绘制区域的全部点阵数据,数据的格式为
[r,g,b,a,r,g,b,a,r,g,b,a]
我们通过一个gap
值来跳跃间隔裁剪数据。由于画布是黑色,所以r
,g
,b
都为0
的点阵我们就不绘制了,现在将间隔的点阵信息再次绘制到画布中。
var fx = x + w - textWidth/2;
var fy = y + h - textHeight/2;
context.fillStyle = "#ffffff";
context.fillRect(fx,fy,1,1);
我们就会看见~
太棒了,这就是我们最终需要的文字烟花粒子的终点信息呀!
现在我们遍历全部的点阵,并创建烟花粒子吧!
for (var h = 0; h < textHeight; h+=gap) {
for(var w = 0; w < textWidth; w+=gap){
var position = (textWidth * h + w) * 4;
var r = imgData.data[position], g = imgData.data[position + 1], b = imgData.data[position + 2];
if(r+g+b==0)continue;
var p = {};
p.x = x;
p.y = y;
p.fx = x + w - textWidth/2;
p.fy = y + h - textHeight/2;
p.size = Math.floor(Math.random()*2)+1;
p.speed = 1;
setupColors(p);
particles.push(p);
}
}
至此,文字烟花效果,我们就实现了!!!
createFireworks(x, y,["杨幂","我爱你","永远"][Math.floor(Math.random()*3)]);
微信搜索“大帅老猿
”并回复“烟花
”即可获得本文全部源码
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.