🙇 前言
- 大家好我是小卢,转眼间又到了一年春节,而往年的春节也正好是我的本命年🐯。
- 因为疫情的起因可能又回不了家过年了,还是很想回去看看烟花感触下年味的🧧。
- 既然回不去那就本人做一个吧~跟大家一起赏烟花🎆。
-
Ps: 本文没有波及到性能优化,请不要在正式我的项目应用喔~
🏮 ToDoList
- [ ] 获取文字像素点
- [ ] 初始化烟花
- [ ] 烟花发射
-
[ ] 烟花爆炸
🧧 Just Do It
获取文字像素点
-
首先咱们先创立一个
canvas
<!-- index.html --> <canvas id="textFireWorks"></canvas>
-
初始化
canvas
并在canvas
中填充想要输入的文字// fireWork.js let textCanvas, textCtx; const canvasWidth = window.innerWidth; const canvasHeight = window.innerHeight; const fontSize =180 function fireWorksShowBegin() { initCanvas(); } function initCanvas() { textCanvas = document.getElementById("textFireWorks"); textCtx = textCanvas.getContext("2d"); textCanvas.style.width = canvasWidth + "px"; textCanvas.style.height = canvasHeight + "px"; textCanvas.width = canvasWidth; textCanvas.height = canvasHeight; textCtx.textAlign = "center"; textCtx.textBaseline = "top"; textCtx.font = fontSize + 'px "宋体"'; textCtx.fillStyle = "#fff"; textCtx.fillText("新春快乐", canvasWidth / 2, 0); }
-
canvas
初始化实现后咱们须要获取每个像素点对应的地位// fireWork.js let textPixels = []; function initCanvas() { // ... //获取画布地位 let pix = textCtx.getImageData(0, 0, canvasWidth, canvasHeight).data; let gap = 6; for (let h = 0; h < canvasHeight; h += gap) { for (let w = 0; w < canvasWidth; w += gap) { // 以后像素块绝对于画布的索引地位 let position = (canvasWidth * h + w) * 4; let r = pix[position], g = pix[position + 1], b = pix[position + 2]; if (r + g + b !== 0) { textPixels.push({ x: w, y: h, }); } } } }
- 在
canvas
中咱们能够通过getImageData
办法拿到画布的信息 - 其中的
data
就是色调信息,每4
个元素示意一个像素色彩 -
咱们能够通过以上算法在程度和垂直方向均以固定间隙去读取
imageData
像素点信息,如果是齐全不通明的像素点,则作为咱们须要的要害坐标保留下来至textPixels
数组中用于咱们之后烟花渲染。初始化烟花
- 对于烟花的出现在这里我应用了一个
PixiJS
库,这是一个HTML5
创立引擎,用它能够很不便的渲染2D
动画。 -
首先引入该库后咱们创立一个容器和渲染器增加到咱们的
dom
中。// fireWork.js // 创立一个Container const stage = new PIXI.Container(); //自动检测渲染器 const renderer = PIXI.autoDetectRenderer(canvasWidth, canvasHeight); document.body.appendChild(renderer.view);
- 接下来咱们须要将烟花最终绽开的地位摆满烟花,也就是以上像素点的地位。
- 应用
PIXI.Texture
我将福的图标作为烟花占位符。 - 将每一个像素点都替换成福图标。
- 在
stage
容器中增加这些子节点,并把每一个firework
记录下来不便接下来应用。
// fireWork.js
const fireworks = [];
const yOffset = canvasHeight * 0.4;
const textures = PIXI.Texture.from("https://s3.bmp.ovh/imgs/2022/01/0d7afb4d0700761e.png");
function fireWorksShowBegin() {
//...
initFireworks();
}
function initFireworks() {
// shuffle(textPixels);
for (let i = 0, l = textPixels.length; i < l; i++) {
createEmojiFirework(textures, textPixels[i], i);
}
}
function createEmojiFirework(text, pos, i) {
const size = 20;
const firework = new PIXI.Sprite(text);
firework.position.x = pos.x;
firework.position.y = pos.y + yOffset;
firework.width = size;
firework.height = size;
firework.image = text;
fireworks.push(firework);
stage.addChild(firework);
}
- 因为最终咱们要始终循环渲染这个页面所以采纳
requestAnimationFrame
,这个办法之前我在产品经理:你能不能让词云动起来?介绍过了,这里我就不细讲了。
// fireWork.js
function fireWorksShowBegin() {
//...
requestAnimationFrame(fireWorksAnimate);
}
function fireWorksAnimate() {
requestAnimationFrame(fireWorksAnimate);
// 将对象渲染到其 WebGL 视图。
renderer.render(stage);
}
- 咱们来看看当初的成果吧
烟花发射
- 当初最终须要出现的成果曾经做好了,咱们只须要在循环动画
fireWorksAnimate
办法中将每一个图标都缓缓发射到对应的像素点即可。 - 在
fireWorksAnimate
中咱们首先须要做一件事件,那就是将图标的地位从一个中央位移到咱们真正想要烟花爆炸
💥的地位,然而在这之前咱们曾经将图标放到爆炸的地位了,当初咱们须要对初始化创立的图标做解决从新给定一个终点并记录爆炸的地位让他迟缓位移。 -
咱们须要改变
createEmojiFirework
办法,设置终点position(x,y)
和起点explodePositio(x,y)
并设置图标挪动速度speed
。// fireWork.js function createEmojiFirework(text, pos, i) { //... // 记录最终爆炸的地位 firework.explodePosition = { x: pos.x, y: pos.y + yOffset, }; //给图标一个终点地位 firework.position.x = 20; firework.position.y = 30; //设置图标挪动速度 firework.speed = 0.02 }
- 而在
fireWorksAnimate
中咱们须要计算从终点到起点的每次位移。
// fireWork.js
function fireWorksAnimate() {
for (let i = 0; i < fireworks.length; i++) {
fireworks[i].position.x +=
(fireworks[i].explodePosition.x - fireworks[i].position.x) *
fireworks[i].speed;
fireworks[i].position.y +=
(fireworks[i].explodePosition.y - fireworks[i].position.y) *
fireworks[i].speed;
}
}
- 当初的成果是这样的
- 好家伙成果是挪动了,然而太参差了,咱们在
createEmojiFirework
中给烟花一个定时器让他提早一个一个的发射,这下成果就好很多了。
烟花爆炸
- 烟花发射成功了,接下来咱们要欠缺烟花爆炸的成果。
-
爆炸的原理其实也是跟生成图标差不多。
- 在每一次的动画中循环中咱们都要计算图标是否快要达到起点。
- 如果快要达到就给它一个标记并触发爆炸事件。
- 在爆炸事件中咱们须要生成多个粒子,给每个粒子初始化不同的
x轴
和y轴
的位移速度,并且记录大小和地位。
// fireWork.js
let particles = [];
function fireWorksAnimate() {
//...
for (let i = 0; i < fireworks.length; i++) {
//...
if (!fireworks[i].exploded) {
//计算是否快要达到起点
if (
Math.abs(fireworks[i].position.x - fireworks[i].explodePosition.x) +
Math.abs(fireworks[i].position.y - fireworks[i].explodePosition.y) <
100
) {
fireworks[i].exploded = true;
explodeFirework(fireworks[i]);
}
}
}
//...
}
function explodeFirework(firework) {
for (let i = 0; i < 20; i++) {
const size = 20;
let particle = new PIXI.Sprite(firework.image);
particle.speed = {
x: (Math.random() - 0.5) * (Math.random() * 10),
y: (Math.random() - 0.5) * (Math.random() * 10),
};
particle.position.x = firework.position.x;
particle.position.y = firework.position.y;
particle.width = size;
particle.height = size;
particles.push(particle);
stage.addChild(particle);
}
}
- 至此每个图标烟花就会在达到起点后生成
20
个雷同大小的例子,然而这个例子始终存在于画布中,咱们须要计算他的位移产生一种爆炸
的成果。 - 在每次画布从新渲染中咱们将每一个粒子都依照它本身的速度别离在
x
和y
位移,并设置alpha
不透明度递加。
// fireWork.js
function fireWorksAnimate() {
//...
for (let i = 0, l = particles.length; i < l; i++) {
particles[i].position.x += particles[i].speed.x;
particles[i].position.y += particles[i].speed.y;
particles[i].speed.y += 0.03;
particles[i].alpha -= 0.01;
}
//...
}
- 最初出现的成果就是这样啦~~
- 然而当初的成果太对立了,如果当咱们将
发射地位
起点地位
发射速度
爆炸大小
全副随机之后会产生什么呢?
最终成果
- 好啦这样想要的成果就制作实现了,接下来就加上小卢给大家的新年贺语就完结了(贺卡有彩蛋喔~😆)。
- 源码地址
-
展现地址(请在PC端关上喔~)
👋 写在最初
- 首先还是很感激大家看到这里,这次的文章就分享到这里,提前祝大家春节快乐!!
- 在新的一年心愿大家越来越好,顺顺利利,疫情早日过来!!!!
- 如果您感觉这篇文章有帮忙到您的的话无妨🍉🍉关注+点赞+珍藏+评论+转发🍉🍉反对一下哟~~😛您的反对就是我更新的最大能源。
- 如果想跟我一起探讨和学习更多的前端常识能够退出我的
前端交流学习群
,大家一起畅谈天下~~~