preface

After readingH5 live crazy like animation is how to achieve? (Attached with full source code)After this article, I feel that the effect of the thumbs-up is very good, and I also followed the author to achieve this animation effect. The CSS implementation method is easy to understand, but I have different implementation ideas after reading the author’s canvas implementation method, so I implemented it according to my own ideas. The implementation effect is as follows:

Implementation approach

The first thing THAT came to my mind when I saw this animation was to declare an array of small icon objects, and to implement the thumbs-up animation by drawing these small ICONS in different positions. So first we implement a little icon animation.

Animation process decomposition

To do animation, we first decompose the entire animation process, which includes the following:

  • There is an enlarged animation when the enlarged image first appears
  • Y translation
  • X-axis translation is the animation of the icon swinging from side to side
  • Transparency animation when the transparency icon disappears

Single icon animation

Let’s first simplify the problem and animate a single icon. Here, for future action on icon animation, I write an Ani class representing icon animation, which contains the icon’s position properties, size, image object and animation track-related properties, as well as a draw method for drawing. The definition is as follows:

        // Icon animation class
         class Ani{
             constructor(img,x,y,w,h){
                this.x=x;
                this.y=y;
                this.width=w;
                this.height=h;
                this.image=img;
                // Randomly generate the amplitude of the sinusoidal curve
                this.step=getRandom(10.60);
                // Randomly generate the Y-axis moving speed
                this.spite=getRandom(2.6);
                // The oscillation frequency of the sine function
                this.frequency=getRandom(50.100);
                // Small icon transparency
                this.op=0;
                // Random curve type
                Math.random()>=0.5?this.type=1:this.type=2;
                // The y offset, as the sine function argument
                this.dy=0;
             }
             // The global context is not used here for reuse purposes
             draw(context){ 
                 // Y panning animation
                 this.y-=this.spite;
                 // X-axis swing animation
                 this.dy+=this.spite;
                 let dx=0;
                 // Different wave directions
                 this.type==1? dx=Math.sin(this.dy/this.frequency):dx=Math.sin(-this.dy/this.frequency);
                 let x=this.x+dx*this.step;  
                 // Zoom in animation
                 if(this.width<50) {this.width+=0.5;
                    this.height+=0.5;
                 }
                 context.drawImage(this.image,x,this.y,this.width,this.height);
                 // Transparency animation when vanishing
                 if(this.y<50) {this.op+=0.05
                    context.fillStyle = `rgba(255,255,255,The ${this.op}) `;
                    context.fillRect(x,this.y,this.width,this.height); }}}Copy the code

The getRandom() method is a simple function used to getRandom numbers between intervals. The code implementation is provided in the full source code below.

Here, the transparency of the icon is set by adding transparent background color at the specified position. After searching a lot on the Internet, I failed to find a method to directly modify the transparency of the image object, so I used this method.

The Ani class draw() method changes the ATTRIBUTES of the Ani object, such as y, x, width, height, and op, for each animation process. Here we will focus on the realization of the X-axis swing animation, X-axis motion animation is achieved with the help of sine function, JS has a ready-made math.sin () function for us to use, sine function 0->1->0->-1 curve perfectly fit our need for the motion curve. Here we take the y offset dy as a parameter of the sine function, generate the value dx between 0 and -1, and then use dx*step to obtain the x offset.

Once the Ani class is complete we also need a function to start the animation:

    const canvas = document.getElementById('thumsCanvas');
    let context = canvas.getContext('2d');
    let image=new Image("./img/star.png");
    let ani=new Ani(image,250/2- 50/2.500- 50.20.20);
       // Render function
    function render(){
        / / the context clearRect,0,250,500 (0); // clear canvas
        // Add a transparent background color fill to achieve a trailing effect
        context.fillStyle = 'rgba (255255255,0.5)';
        context.fillRect(0.0.250.500);
        ani.draw(context);
        window.requestAnimationFrame(render)
    }    
    render();
Copy the code

Multiple icon animation

Once a single icon is animated, it is easy to animate multiple ICONS. We simply create an array that holds multiple icon objects and iterate over them each time the Render function executes.

Since we need multiple image ICONS, we need to implement a loadImge function to cache the loaded image in an imageList array. This method refers to the above article. (Attached with full source code). The code is as follows:

        // Load the image
        function loadImage(){
            const images=[
                '.. /img/red.png'.'.. /img/dog.png'.'.. /img/cat.png'.'.. /img/star.png'.'.. /img/zan.png',];const promiseList=[];
            images.forEach(element= > {
                let p=new Promise((resolve) = >{
                    const img=new Image();
                    img.onload=resolve.bind(null,img)
                    img.src=element;
                })
                promiseList.push(p)
            });
            return new Promise(resolve= >{
                Promise.all(promiseList).then(imgs= >{                        
                        this.imageList=imgs; resolve(); })})}Copy the code

Then we need to add a method to the icon object:

        // Add icon object to array
        function tapAdd(){
            let image=this.imageList[this.getRandom(0.5)];
            let ani=new Ani(image,250/2- 50/2.500- 50.20.20)
            aniList.push(ani)
        }
Copy the code

Finally we also need a render function:

       // Render function
        function render(){
            / / the context clearRect,0,250,500 (0); // clear canvas
            context.fillStyle = 'rgba (255255255,0.5)';
            context.fillRect(0.0.250.500);
            aniList.forEach((ani,index) = >{
                if(ani.y<- 50){
                    ani=null;
                }else{ ani.draw(context); }})window.requestAnimationFrame(render)
        }        
        loadImage().then((a)= >{
            console.log('Image load completed')
            render();
            setInterval(tapAdd,100);
        });
Copy the code

Context. FillStyle = ‘rgba(255,255,255,0.5)’; ,0,250,500 context. FillRect (0); ClearRect (0,0,250,500); clearRect(0,0,250,500); .

Complete source code

 
      
 <html>
     <head>
        <title>Cavans praised the animation</title>
     </head>
     <body>
        <canvas onclick="tapAdd()" id="thumsCanvas" width="250" height="500" style="width:250px; height:500px; background-color: #f4f4f4;"></canvas>
     </body>
     <script>
         // Icon animation class
         class Ani{
             constructor(img,x,y,w,h){
                this.x=x;
                this.y=y;
                this.width=w;
                this.height=h;
                this.image=img;
                // Randomly generate the amplitude of the sinusoidal curve
                this.step=getRandom(10.60);
                // Randomly generate the Y-axis moving speed
                this.spite=getRandom(2.6);
                this.frequency=getRandom(50.100);
                // Small icon transparency
                this.op=0;
                // Random curve type
                Math.random()>=0.5?this.type=1:this.type=2;
                this.dy=0;
             }
             draw(context){ 
                // Y-axis animation effect
                 this.y-=this.spite;
                // X-axis animation effect
                 this.dy+=this.spite;
                 let dx=0;
                 // Different wave directions
                 this.type==1? dx=Math.sin(this.dy/this.frequency):dx=Math.sin(-this.dy/this.frequency);
                 let x=this.x+dx*this.step;  
                 // Enlarge the image animation
                 if(this.width<50) {this.width+=0.5;
                    this.height+=0.5;
                 }
                 context.drawImage(this.image,x,this.y,this.width,this.height);
                 // The image disappears and animates from 0-1
                 if(this.y<50) {this.op+=0.05
                    context.fillStyle = `rgba(255,255,255,The ${this.op}) `;
                    context.fillRect(x,this.y,this.width,this.height); }}}// Array of small icon animated objects
        let aniList=[];
        const canvas = document.getElementById('thumsCanvas');
        let imageList=[];
        let context = canvas.getContext('2d');
        // Load the image
        function loadImage(){
            const images=[
                '.. /img/red.png'.'.. /img/dog.png'.'.. /img/cat.png'.'.. /img/start.png'.'.. /img/zan1.png',];const promiseList=[];
            images.forEach(element= > {
                let p=new Promise((resolve) = >{
                    const img=new Image();
                    img.onload=resolve.bind(null,img)
                    img.src=element;
                })
                promiseList.push(p)
            });
            return new Promise(resolve= >{
                Promise.all(promiseList).then(imgs= >{                        
                        this.imageList=imgs; resolve(); })})}// Get a random number
        function getRandom(min,max){
            return Math.floor(Math.random()*(max-min))+min
        }
        // Add ICONS
        function tapAdd(){
            let image=this.imageList[this.getRandom(0.5)];
            let ani=new Ani(image,250/2- 50/2.500- 50.20.20)
            aniList.push(ani)
        }
        // Render function
        function render(){
            / / the context clearRect,0,250,500 (0); // clear canvas
            context.fillStyle = 'rgba (255255255,0.5)';
            context.fillRect(0.0.250.500);
            aniList.forEach((ani,index) = >{
                if(ani.y<- 50){
                    ani=null;
                }else{ ani.draw(context); }})window.requestAnimationFrame(render)
        }        
        loadImage().then((a)= >{
            console.log('Image load completed')
            render();
            setInterval(tapAdd,100);
        });
     </script>
 </html>
Copy the code

The picture material

zan.png

The last

The above is my own reading H5 live crazy like animation is how to achieve? (attached complete source code) in accordance with their own ideas to achieve a live point like effect, thank the author.