🙇 preface
- In the twinkling of an eye, it's the Spring Festival again, and this year's Spring Festival is just my life year 🐯.
- Because of the epidemic, I may not be able to go home for the new year again. I still want to go back to see the fireworks and feel the flavor of the next year 🧧.
- Since you can't go back, make one by yourself ~ enjoy fireworks with everyone 🎆.
- Ps: This article does not involve performance optimization. Please do not use it in formal projects
🏮 ToDoList
- Get text pixels
- Initialize fireworks
- Fireworks emission
- Fireworks explosion
🧧 Just Do It
Get text pixels
- First, we create a canvas
<!-- index.html --> <canvas id="textFireWorks"></canvas>
- Initialize canvas and fill the canvas with the text you want to output
// 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 "Song style"'; textCtx.fillStyle = "#fff"; textCtx.fillText("Happy New Year", canvasWidth / 2, 0); }
- After canvas initialization, we need to get the corresponding position of each pixel
// fireWork.js let textPixels = []; function initCanvas() { // ... //Get canvas location 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) { // The index position of the current pixel block relative to the canvas 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, }); } } } }
- In canvas, we can get the information of canvas through getImageData method
- The data is color information, and every four elements represent a pixel color
- We can use the above algorithm to read the imageData pixel information with a fixed gap in the horizontal and vertical directions. If it is a completely opaque pixel, it will be saved as the key coordinates we need to be saved in the textPixels array for our subsequent fireworks rendering.
Initialize fireworks
- For the presentation of fireworks, I use a PixiJS library, which is an HTML5 creation engine, which can easily render 2D animation.
- First, after introducing the library, we create a container and renderer to add to our dom.
// fireWork.js // Create a Container const stage = new PIXI.Container(); //Auto detect renderer const renderer = PIXI.autoDetectRenderer(canvasWidth, canvasHeight); document.body.appendChild(renderer.view);
- Next, we need to fill the final position of fireworks with fireworks, that is, the position of the above pixels.
- Use Pixi Texture I use Fu's icon as a placeholder for fireworks.
- Replace each pixel with an icon.
- Add these child nodes in the stage container and record each firewall for future use.
// 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); }
- Because we have to render the page circularly in the end, we use requestAnimationFrame. I used this method before Product Manager: can you make the word cloud move? Yes, I will not go into detail here.
// fireWork.js function fireWorksShowBegin() { //... requestAnimationFrame(fireWorksAnimate); } function fireWorksAnimate() { requestAnimationFrame(fireWorksAnimate); // Render the object to its WebGL view. renderer.render(stage); }
- Let's see the effect now
Fireworks emission
- Now the final effect to be rendered has been done. We just need to slowly emit each icon to the corresponding pixel in the looping animation fireWorksAnimate method.
- The first thing we need to do in fireworks Animate is to move the position of the icon from one place to where we really want the fireworks to explode 💥 But before that, we have put the icon in the explosion position. Now we need to deal with the icon created by initialization, give a new starting point and record the explosion position to make it move slowly.
- We need to change the createemojifirewall method, set the starting position(x,y) and the ending explodeposition (x, y), and set the icon movement speed.
// fireWork.js function createEmojiFirework(text, pos, i) { //... // Record the location of the final explosion firework.explodePosition = { x: pos.x, y: pos.y + yOffset, }; //Give the icon a starting point firework.position.x = 20; firework.position.y = 30; //Set icon movement speed firework.speed = 0.02 }
- In fireworks animate, we need to calculate each displacement from the start point to the end point.
// 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; } }
-
Now the effect is like this
-
Good guy, the effect is moving, but it's too neat. We give fireworks a timer in createemoji fire work to delay the launch one by one. The effect is much better.
Fireworks explosion
- The fireworks were successfully launched. Next, we need to improve the effect of fireworks explosion.
- The principle of explosion is actually similar to generating icons.
- In each animation cycle, we have to calculate whether the icon is about to reach the end.
- If it is about to arrive, give it a mark and trigger an explosion.
- In an explosion, we need to generate multiple particles, initialize different displacement velocities of x-axis and y-axis for each particle, and record the size and position.
// fireWork.js let particles = []; function fireWorksAnimate() { //... for (let i = 0; i < fireworks.length; i++) { //... if (!fireworks[i].exploded) { //Calculate whether it is close to the end 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); } }
- So far, each icon fireworks will generate 20 examples of the same size after reaching the end point, but this example always exists in the canvas. We need to calculate its displacement to produce an explosive effect.
- In each canvas re rendering, we shift each particle in x and y respectively according to its own speed, and set alpha opacity decrement.
// 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; } //... }
-
The final effect is like this ~
-
But now the effect is too uniform. What will happen if we randomize the explosion size of the launch speed at the end of the launch position?
Final effect
- Well, the desired effect is finished. Next, add Xiao Lu's New Year greetings to everyone and it will be over (the greeting card has colored eggs ~ 😆).
- Source address
- Display address (please open it on the PC side ~)
👋 Write at the end
- First of all, thank you very much for seeing here. This article will be shared here. I wish you a happy Spring Festival in advance!!
- In the new year, I hope you will get better and better, and the epidemic will pass as soon as possible!!!!
- If you think this article is helpful to you, you might as well 🍉🍉 Follow + like + collect + comment + forward 🍉🍉 Support~~ 😛 Your support is the biggest driving force for me to update.
- If you want to discuss and learn more front-end knowledge with me, you can join my front-end communication and learning group and talk about the world together~~~