• Scotland team
  • Author: Jason

preface

One day I received a wechat message from the product. X, our business now needs a drop animation similar to adding to the shopping cart. After careful consideration by the organization, this requirement is assigned to you. Hence the article. This article does not describe how much advanced technology, more about some authors in the animation of the animation principle of thinking and how to optimize the animation ideas. The implementation effect is as follows:

Picture quality is limited, please understand

Technical analysis

There are many ways to animate the front end. Whether it is JS animation, CSS animation, Canvas animation or SVG animation, even GIF animation to achieve a simple parabola is enough. However, considering the needs of the business scene and the playability, we finally decided to use JS to implement the animation.

Implementation analysis

In my opinion, most animation effects come down to the application of mathematical formulas. Parabolic animation is nothing more than to make the movement of elements conform to the trajectory of the parabola. The equation for the parabola is Y = A*X*X + B*X + C and maybe you’re not familiar with this formula. But the L(distance) = 1/2*A(acceleration)*T*T(time) of the physics teacher must remember in mind. The author uses this formula to complete parabolic animation.

The specific implementation

Step 1: Get the start and end of the parabola

Due to the particularity of the business itself, it is necessary to obtain the absolute position of the element in the window when the user clicks on the item. The X, Y coordinates of the element relative to the browser’s visible area. Here I recommend using the getBoundingClientRect() function to compute the absolute location in conjunction with the specific business. Of course, in some scenes you can just use the mouse click position or any other method to get the starting point of the animation.

Step 2 Set parabolic parameters

1. The acceleration

The acceleration, A, determines how fast the element changes in its direction. When the starting point and ending point of the animation are fixed, the formula L(vertical distance) = 0.5 * A(acceleration) * T * T(time) can be concluded that the acceleration A is inversely proportional to the square of time T. It should be noted that positive acceleration A will always enlarge the vertical movement distance between frames, so excessive acceleration A may cause the ball flickering at the end of the animation.

2. Initial velocity of time T and X-axis

In parabolic animations, we generally think of elements moving horizontally at a fixed speed. Then, it can be concluded from the formula L(horizontal distance) = T * Xspeed(horizontal speed) that the horizontal speed Xspeed actually determines the animation execution time. Based on the concept of acceleration, we can draw the following conclusions: When the starting and ending points of the animation are fixed, if we set the initial velocity of the X-axis as a fixed value, the animation execution time is fixed, in order to make the ball reach the fixed position. Acceleration A needs to be computed. The specific calculation formula is as follows:

// Determine the start and end points of the animationletXStart = 0, YStart = 0, XEnd = 1000, YEnd = 1000; // Determine key parametersletXspeed = XX; // Calculate animation time and vertical acceleration according to the key parameter Xpeedlet Time = (XEnd - XStart) / Xspeed; 
let A = 2 * (YEnd - YStart ) / (Time * Time); 
Copy the code

What if you want the animation to run for a fixed amount of time?

// Determine key parametersletTime = XX; // Calculate the horizontal velocity and vertical acceleration according to the key parameter Timelet Xpeed = (XEnd - XStart) / Time; 
let A = 2 * (YEnd - YStart ) / (Time * Time); 
Copy the code

What if you want to fix the acceleration? No, you don’t need…..

3. Initial velocity of Y axis

The initial velocity of the Y axis, the vertical velocity when the parabola is thrown. In general, I would set the initial Y velocity to be negative. At this point there will be up and then the natural fall of the animation, slightly vivid… Then the calculation formula of acceleration A becomes:

let A = 2 * (YEnd - YStart - Yspeed * Time) / (Time * Time); 
Copy the code

It should be noted that different ratios of Xspeed and Yspeed can change the shape of the curve. The principle behind this is that Yspeed and acceleration A(possibly controlled by Xspeed) together determine the highest point that the ball can reach during its ascent, while Xspeed determines the X-axis position at this time.

Step three: Get it moving

We usually use setTimeOut or requestAnimationFram to implement regular JS animations. Let’s use requestAnimationFram to implement fixed animation execution times as an example.

1. First generate the ball and determine the start and end of animation, as well as key parameters

// Start and finish are free to setlet XStart = 0, YStart = 0, XEnd = 1000, YEnd = 1000; 
let Time = T;
let Xpeed = (XEnd - XStart) / Time; 
let Ypeed = -YY; 
letA = 2 * (YEnd - YStart - Yspeed * Time) / (Time * Time); // Generate elementslet Node = document.createElement('div'); // Free control body, Fixed node.classname ='myNode';
document.body.appendChild(Node);
Node.style.top = YStart + 'px';
Node.style.left = XStart + 'px';

Copy the code

2. Change the element position in the requestAnimationFram callback

// Record the real-time position of the elementlet nowX = XStart;
letnowY = YEnd; // Unit timelet loop = 0;
// 
let move = () => {
    ifNode.remove(); (nowY >= targetTop) {node.remove ();return; } // The current position is equal to the original position + the displacement in unit time nowX += Xspeed; // nowY += (A * loop + Yspeed); requestAnimationFram(() => { Node.style.top = nowY +'px';
        Node.style.left = nowX + 'px';
        loop++;
        move();
    });
};
Copy the code

3. The ball may overshoot its target point

Depending on the logic of the code that stops the animation, the ball may have passed the target point on its last move. We will stop the animation and destroy the instance at the next setTimeOut judgment. The solution is as follows.

requestAnimationFram(() => {
    Node.style.top = Math.min(nowY, XEnd) + 'px';
    Node.style.left = Math.min(nowX, YEnd) + 'px';
    loop++;
    move();
});
Copy the code

By the way: there are lots of interesting animations you can do with Math.min() or math.max (), so go discover new worlds for yourself.

How to achieve dynamic blur effect

Dynamic blur effect, picture quality is limited, please understand

Ordinary implementation effect, picture quality is limited, please understand

What is dynamic ambiguity?

Motion blur refers to a static scene or a series of pictures, such as movies or animations, in which fast-moving objects cause obvious blurred drag marks. The author understands it as residual visual information, that is, residual visual information of the previous moment in the visual sources of the current moment (such as pictures, videos and imagination). What’s the good of that? The right amount of motion blur will make the continuous screen changes more fluid and natural.

How to implement dynamic blur?

First of all, let’s do a method of elimination. Let’s take a look at the dynamic blur achieved by creating an obvious blur drag trace. That is to say, if you implement blur drag traces can imitate the dynamic blur effect. So what does a fuzzy drag look like?

In the author’s opinion, the effect of dynamic blur can be simulated by adding several opacity gradients around the same element

Code implementation

Before the code can be implemented, we first need to determine what we need to achieve. Take the ball in parabolic animation as the target, that is, generate several balls with gradient transparency around the moving ball. Exactly where to add the ball? The author’s idea is to insert the residual shadow ball between the two frame positions of the ball.

Step 1 Packing

Wrap the original implementation in a function

letAnimat = (initial position, end position) => {... // Position change nowX += Xspeed; nowY += (A * loop + Yspeed); requestAnimationFrame(() => { Node.style.top = nowY +'px';
        Node.style.left = nowX + 'px';
        loop++;
        move();
    });
}
Copy the code

The purpose is simple: the ball of the generated shadow also needs to synchronize with the position information of the original ball.

The second step is to generate residual shadows

Think: Each time the position of the shadow ball should be related to the real ball. So we can’t change the actual position of the ball, so Translate seems like a good choice.

letAnimat = (initial position, end position, whether residual) => {... // Position change nowX += Xspeed; nowY += (A * loop + Yspeed); requestAnimationFrame(() => { Node.style.top = nowY +'px';
        Node.style.left = nowX + 'px';
        if (isShadow) {
            item.style.transform = `translate(The ${(0.5 * Xspeed)}px ,${-(0.5 * (A * loop + Yspeed))}px)`; Item. Style. Opacity = 0.5; } } loop++; move(); }); }Copy the code

One caveat to this step is that changes in transparency are critical. The author recommends a value between 0.1 and 0.5 for transparency.

The third step generates multiple residual shadows

If only one spawns a ball, the effect of dynamic blur will not be noticeable. So we need to create a function that controls the number of balls.

CreateShadow (initial position, end position, num) {for (leti = 0; i < num; I++) {animat(initial position, end position,true, i / (num + 1)); }},Copy the code

The animat function changes to

letAnimat = (initial position, end position, whether residual, num) => {..... requestAnimationFrame(() => { ....if (isShadow) {
            item.style.transform = `translate(${-(num * Xspeed)}px ,${-(num * (A * loop + Yspeed))}px)`; Item.style. Opacity = (1-num) * 0.5; }}... }); }Copy the code

And you’re done.

conclusion

If you don’t understand, disagree with this article, or have a better idea, please leave a comment in the comments section. Communicate together and make progress together.