Explosive dynamic effect sharing


preface

This sharing is a summary of self-component development, there are still a lot of shortcomings, I hope you give valuable suggestions greatly, learn from each other.

Share content introduction

Through the native JS code, realize the particle explosion effect component component development process, the use of the company’s internal very efficient engineering environment, we hereby advertise: Sina mobile sincerely recruit a variety of technology greatly! Can private chat cast resume!



Results the preview



Effect analysis


  • * Click as the starting point of the animation, automatically end
  • * Each effect produces multiple parabolic particles moving elements, with random directions, different display contents, and spatial z-axis size changes
  • * On demand, you can click without interval, that is, the second group of animation can be played before the end of the first group
  • * Animation basically has the same execution time


After the analysis of the above four points, what are the implementation schemes of animation?

  • CSS operand transitions (such as focus) animate child elements

‘Not desirable, the effect can be connected multiple times, CSS state change does not match the requirements’


  • Javascript controls the animation to start, write the CSS animation preset in advance, use the class include selector to switch the animation for example:.active. Items {animation: XXX… ; }

‘Not desirable, a single execution of the animation is fine, but there is a fixed effect, and the inability to continuously execute the animation’


  • A lot of animation is written in advance, a lot of DOM elements are hidden, and the animation starts to randomly select DOM elements to execute its unique animation keyframes

Implementation-wise, this works, but when the comment list is long, the DOM is huge and CSS is heavily animated, resulting in heavy, non-random code

  • Ditch CSS animation and use Canvas for animation

‘Feasible, but canvas maintenance cost is slightly higher, and custom function is difficult to design, screen adaptation also has a certain cost’

  • Js to do DOM creation, generate random CSS @keyframes

‘Yes, but creating a style style sheet, causing CSS to re-render the page, will lead to the performance of the page, and the complexity of parabolic CSS is not low, not as a preferred’

  • Js brush frames to do DOM rendering

‘Yes, but the brush operation will cause performance stress’



conclusion

Canvas is feasible, but due to its development drawbacks, canvas is not used as the content to be shared in this sharing. Instead, DOM operation of js brushing frame is used





Component structure


From the screenshot sharing, animation can be divided into two modules. First, randomly divergent particles have common characteristics: parabolic animation, fade out, and render expression


As the number of examples increases, it will look like a screenshot


However, due to performance reasons, we need to control the particles and realize resource reuse, so we also need a second module as a particle control component


So: this function can be developed using two modules: partical. Js particle function and boom.js particle management




Realize the Partical. Js

1. Pre-resource: The physical curve of parabolic motion needs to use the speed function provided by Tween.js


If you don’t want to introduce tween.js, you can use the following code

/** tween.js * t: current time; * B: beginning value; * c: change in value; * d: duration * you can visit 'easeIn' to get effect */ const Quad = {easeIn: function(t, b, c, d) {return c * (t /= d) * t + b; }, easeOut: function(t, b, c, d) { return -c *(t /= d)*(t-2) + b; }, easeInOut: function(t, b, c, d) { if ((t /= d / 2) < 1) return c / 2 * t * t + b; return -c / 2 * ((--t) * (t-2) - 1) + b; } } const Linear = function(t, b, c, d) { return c * t / d + b; }Copy the code


2. Particle implementation

Implementation idea:

We want to create particles in the new Partical way when controlling the particle component, each particle has its own animation start method, animation end callback.

Since there may be a large number of comments in the list, we hope to create a limited number of particles globally, so the function of container removing particles and container adding particles is provided to realize the reuse of particles

partical_style.css

Boom-partical_holder {position: absolute; // Partical_Holder{position: absolute; left:0; right:0; top:0; bottom:0; margin:auto; }Copy the code

particle.js

import "partical_style.css"; Class Partical{// dom = null; // animation StartTime StartTime = -1; // The current particle animation direction, the difference between UP and down motion direction = "UP"; // Animation delay = 0; // targetZ = 0; targetY = 0; targetX = 0; // scaleNum = 1; Animating = false; Parent = null; parent = null; AnimEndCBList = []; // Particle render content container slot con = null; Dom this.dom = document.createElement("div"); this.dom.classList.add("Boom-Partical_Holder"); this.dom.innerHTML = ` <div class="Boom-Partical_con"> Boom </div> `; RenderIn (parent) {parent.appendChild(this.dom); this.parent = parent; // Initialize slot container here! this.con && ( this.con = this.dom.querySelector(".Boom-Partical_con")); } // use the parent container to remove the current particle deleteEl(){this.parent. } // Execute animation, need this particle to execute animation Angle, animation force, Animate ({deg, POw, delay} = {}){animate({deg, POw, delay} = {}){animate({deg, POw, delay} = {}){ == 'function') return; this.animEndCBList.push(cb); } // Animation end callback executes emitEndCB() {this.dom.style.csstext += '; - its - transform: translate3d (0, 0); opacity:1; `; this.animating = false; try { for (let cb of this.animEndCBList) { cb(); }} catch (error) {console.warn(" callback error :",cb); InsertChild (child){this.con.innerhtml = ''; this.con.appendChild(child); }}Copy the code



So, we’ve created a constructor for the particle object. Now let’s think about whether we’ve implemented our design idea.


  • * Use the constructor new Partical() particle
  • Particle power objects have animate methods that perform animation
  • * There are animation end callback functions stored and executed
  • Set the parent element of the particle: renderIn method
  • * Parent element delete particle: deleteEl method


For better display of particle content, we created a boom-Partical_con element in constructor to simulate the slot function and an insertChild method to display different content to explode 💥



Now let’s think about the implementation of animations, which are definitely parabolic animations, which can be implemented in code using physics formulas,

But we can also do it with a velocity curve, and if you think about the upthrow process you can think of it as an upward displacement of decreasing velocity due to gravity,

The downthrow process can be understood as the acceleration process;

Can correspond to easeOut and easeIn of the velocity curve,

The horizontal direction is linear.


We take the positive X direction 0 degrees horizontally to the right, and increase the Angle clockwise;

Less than 180 degrees is down, and greater than 180 degrees is up

Suppose the direction is four o ‘clock and the Angle is 30 degrees,

According to high school physics, a force of size N:

The X-axis component is going to be cosine of 30 times N and the Y-axis component is going to be sine of 30 times N


A diagram of the decomposition of forces


That is to say we know the magnitude of the force in one direction along the XY axis,

Suppose we convert the concept of force to the concept of displacement in our view,

Let’s call force 1 the magnitude of 10vh

So we can define global variables


const POWER = 10; // const G = 5; // const DEG = math.pi / 180; const Duration = .4e3; // Assume the animation takes 400 milliseconds to executeCopy the code


From this we complete the animate method


// Execute animation Angle, force 1 ~ 10; 1 = 10vh animate({ deg, pow, delay } = {}) { this.direction = deg > 180 ? "UP" : "DOWN"; this.delay = delay || 0; let r = Math.random(); this.targetZ = 0; this.targetY = Math.round(pow * Math.sin(deg * DEG) * POWER); this.targetX = Math.round(pow * Math.cos(deg * DEG) * POWER) * (r + 1); This. scaleNum = (r * 0.8) * (r < 0.5? 1:1); this.raf(); }Copy the code



The animte idea is to calculate the destination position of the target from the incoming Angle and force (because force is eventually converted to displacement, the greater the force, the greater the target displacement).


Use random number to calculate the zoom value change range of this animation (-0.8 ~ 0.8)


Then perform the brush frame operation RAF


Raf (){this.animating = true; This.starttime = +new Date(); let StartTime = this.StartTime; // Let delay = this.delay; // The animation will start after the delay, Let StartTimeAfterDelay = StartTime + delay let animate = () => {let timeGap = +new Date() - StartTimeAfterDelay; If (timeGap >= 0) {if (timeGap >= 0) {if (timeGap > Duration) {this.emitendcb (); return; } // Set the style for the position that should be set this.dom.style.csstext += '; will-change:transform; -webkit-transform:translate3d(${this.moveX(timeGap)}vh,${this.moveY(timeGap)}vh,0) scale(${this.scale(timeGap)}); opacity:${this.opacity(timeGap)}; `; } requestAnimationFrame(animate); } animate(); }Copy the code



The processing of delay time and the end of time processing callback are judged in the brush frame operation


All that remains is moveX, moveY, Scale, opacity Settings


/ * * * * * * * * * * * * * * * * * * * * * * * Return Linear(currentDuration, 0, this.targetX, Duration) * 2; } // Scale using easeOut curve, Scale (currentDuration) {return quad.easeOut (currentDuration, 1, this.scaleNum, Duration); Opacity (currentDuration) {return AD. EaseIn (currentDuration, 1, -1, Duration); }} moveY(currentDuration) {let direction = this.direction; If (direction === 'UP') {if (direction === 'UP') {if (currentDuration < Duration / 2) {if (currentDuration < Duration / 2) { Return quad.easeout (currentDuration, 0, this.targetY + G, Duration / 2); } // The drop process of the upthrow, Return this.targety + g-quad. EaseIn (currentDuration - Duration / 2, 0, this.targety / 2, Duration / 2); EaseIn return Quad. EaseIn (currentDuration, 0, this.targety, Duration); }Copy the code



At this point, partical. Js ends with a line at the end of the file


export default Partical;Copy the code



At this point our partical. Js outputs a constructor:


  • * New creates the particle element,
  • * Use onAnimtionEnd to implement the end-of-animation callback function
  • * insertChild can render a user – defined DOM into a particle
  • RenderIn can set particle parent elements
  • * deleteEl deletes particles from parent elements
  • Animate can perform brush frames, render computed positions, and trigger callbacks

All that remains for the particle is the magnitude, direction, and delay time of the incoming force when the animte is executed




Particle management boom.js

It was called Boom because the component was originally called Boom, but it was better called ParticalController, haha 😄


The functional requirements of boom.js are


  • Create a particle
  • Perform particle animation, giving animation force, Angle, delay
  • Setting the particle container


Results can be achieved:


  • Regardless of the business, the business consumer passes each particle slot content array
  • Particle components are reusable
  • Easy to maintain (probably hahaha)

So the particle manager architecture is:


import Partical from "partical.js"; Class Boom{// List of instantiated particles particalList = []; // particalNumbers = 6; BoomTimeGap =.1e3; boomTimeGap =.1e3; boomTimer = 0; ChildList = []; // Default rotation Angle rotate = 120; Spread = 180; // default random delayRange delayRange = 100; // Default power = 3; // the container that performs the particle explosion is con = null; constructor({ childList , container , boomNumber , rotate , spread , delayRange , power} = {}){ this.childList = childList || []; this.con = container || null; this.particalNumbers = boomNumber || 6; this.rotate = rotate || 120; this.spread = spread || 180; this.delayRange = delayRange || 100; this.power = power || 3; this.createParticals(this.particalNumbers); } setContainer(con){ this.con = con; } createParticals(num){for(let I = 0; i < num ; i++){ let partical = new Partical(); partical.onAnimationEnd(()=>{ partical.deleteEl(); }); This.particallist. Push (partical)}} // execute animation boom(){// limit animation execution interval let lasttimer = this.boomtimer; let now = +new Date(); If (now-lasttimegap < this.boomtimegap){// console.warn(" point too fast "); return; } this.boomTimer = now; Console. warn(" particalList :", this.particallist.length) let boomNums = 0; Hold atelist = this.particallist. Filter (partical => partical. Animating == false); let childList = this.childList; let childListLength = childList.length; let rotate = this.rotate; let spread = this.spread; let delayRange = this.delayRange; let power = this.power; For (let partical of harden){if(boomNums >= this.particalNumbers) return; boomNums++; let r = Math.random(); // Set the particle parent to partical. RenderIn (this.con); // Randomly select the slot content of the particle partical. InsertChild (childList[math.floor (r * childListLength)].clonenode (true)); Partical. Animate ({deg: (r * spread + rotate) % 360, pow: r * power + 1, delay: r * delayRange, }); } if(boomNums < this.particalNumbers){this.createparticals (boomnumbers-boomnums); } } } export default Boom;Copy the code


Use the demo


let boomChildList = [];
    
    
    for(let i = 0 ; i < 10; i++){
        let tempDom = document.createElement("div");
        tempDom.className = "demoDom";
        tempDom.innerHTML = i;
        boomChildList.push(tempDom);
    }
    
    let boom = new Boom({
        childList: boomChildList,
        boomNumber: 6,
        rotate: 0,
        spread: 360,
        delayRange: 100,
        power: 3,
    });Copy the code



Code resources


Source link​pan.baidu.com


Component preview

At the end

The possible effect of the realization of the thinking is not appropriate and lack, welcome to greatly put forward valuable opinions, mutual exchange, learning!