The development of front-end animation has always been my passion to explore and study. This article will describe what simulacrum animation effects are, the popular React animation library, and some demos based on Framer-Motion animation library.

Real experience of animation effects

timing-functionThe shortage of the

When it comes to realistic animation experience, the essence is the sense of body brought by transition animation in animation. In general, a front-end animation is developed using CSS Transition. The relationship between the values of the variables in the animation (such as the displacement or Angle of div) and time is cubic- Bezier. Ease, ease-in, ease-out, ease-in-out etc. are commonly used in timing function, or pass four parameters to the cubic Bessel curve to control the shape of the curve. The following

In the real world, however, nothing moves in a cubic Bezier curve. Because the motion of an object is related to its own mass, resistance, elasticity and so on, this is why the physical engine was born. I’m going to talk step by step about the motion in a spring-damped system.

Motion in a spring-damping system

In many native animations, especially in iOS system animations, it can be seen that “the smaller the pull, the smaller the rebound; The greater the pull, the greater the rebound “feeling, this is the effect of spring animation

First of all, let’s look at the force on the spring. According to Hooke’s Law, the formula is as follows:


F s = k X F_s=-kX

KKK is spring stiffness coefficient

Taking drag into account, CCC is the coefficient of friction and VVV is the velocity


F d = c v F_d=-cv

The net force on the spring is:


F = F s + F d = k X c v F=F_s+F_d=-kX-cv

Newton’s second law


F = m a F=ma

Two equations at the same time


{ F = k X c v F = m a \begin{cases} F=-kX-cv \\ F=ma \end{cases}

For simplicity, we assume that the mass value is 1 (that is, m=1m=1m=1), so that we can get:


a = k X c v a=-kX-cv

XXX represents an object moving from its equilibrium position. This means that if we want to go from x=xx=xx=x to x=1x=1x=1, we have to move x−1x-1x−1 every time to get to that specified position (the idea of differentiation).


X = x 1 X=x-1

Get the equation of motion


a = k ( x 1 ) c v a=-k(x-1)-cv

The differential formula is then used to work out the relationship between the position and time of the object’s motion


x = f ( t ) x=f(t)

Calculate velocity based on position


v = d x d t = f ( t ) v=\frac{dx}{dt}=f'(t)

Calculated acceleration


a = d v d t = f ( t ) a=\frac{dv}{dt}=f”(t)

Combine that with the equation of motion that we got before


{ a = k ( x 1 ) c v a = d v d t = f ( t ) v = d x d t = f ( t ) x = f ( t ) \begin{cases} a=-k(x-1)-cv \\ \\ a=\dfrac{dv}{dt}=f”(t) \\ \\ v=\dfrac{dx}{dt}=f'(t) \\ \\ x=f(t) \end{cases}

conclusion


f ( t ) = k ( f ( t ) 1 ) c f ( t ) f”(t)=-k(f(t)-1)-cf'(t)

So now we have to solve this differential equation.

So let’s think about the boundary conditions, before we move the block, the position of the block let’s say at x=0x=0x=0, so the initial position of the block is x=0x=0x=0, and the initial time is t=0t=0t=0


f ( 0 ) = 0 f(0)=0

f ( 0 ) = 0 f'(0)=0

Suppose the stiffness coefficient k= 180K = 180K =180, and the friction coefficient C = 12C = 12C =12


{ f ( 0 ) = 0 f ( 0 ) = 0 f ( t ) = 180 ( f ( t ) 1 ) 12 f ( t ) \begin{cases} f(0) = 0 \\ f'(0) = 0 \\ f”(t) = -180(f(t) – 1) – 12f'(t) \end{cases}

I won’t go into details here, but there’s a powerful search engine called WolframAlpha that can be used to solve all kinds of calculus equations

f(0) = 0; f'(0) = 0; f''(t) = -180(f(t) - 1) - 12f'(t)
Copy the code

The following figure

As you can see in the screenshot above, the equation is given by the Fourier transform


f ( t ) = 1 2 e 6 t ( 2 e 6 t + s i n ( 12 t ) + 2 c o s ( 12 t ) ) f(t)=-\frac{1}{2}e^{-6t}(-2e^{6t}+sin(12t)+2cos(12t))

The graph of this function is plotted in a two-dimensional coordinate system as follows:

Is it very much like the third Bezier curve in timing-fuction? Yes, the cubic Bezier curve is a simulation of this calculation, and our calculation just restores the actual motion of a spring with a mass of 1, a stiffness coefficient of 180, and a friction coefficient of 12.

Simple harmonic motion

When it comes to this trajectory, its essence is a simple harmonic motion. Here’s a review of what harmonic motion is:

Simple Harmonic Motion, or Simple Harmonic vibration, resonance, SHM (Simple Harmonic Motion), is the most basic and the simplest kind of mechanical vibration. When an object is in harmonic motion, the force on the object is proportional to the displacement, and the force always points to the equilibrium position.

As shown in the figure below, the damping of simple harmonic motion can be divided into four cases

  • Zero damping: Dashed lines in the figure show zero damping, which means that objects move through cycles without stopping
  • Light damping: In the blue line, the object oscillates at the equilibrium position, but the amplitude decreases and eventually returns to the equilibrium position
  • Critical damping: The red line in the figure is critical damping and the object returns to the equilibrium position at the fastest speed. In real life, the doors of many rooms or bathrooms in buildings are equipped with automatic closing torsion springs at the same time, are equipped with damping hinges accordingly, so that the damping of the door is close to critical damping, so that people close the door or the door is blown by the wind will not cause too much noise, and at the same time can be closed at the fastest speed. In addition, the shock absorber spring of the car is also the principle of critical damping
  • Over damping: The green line is over damping, in which objects return to equilibrium in a very gentle manner

Click or scan the experience

It can be seen that the equation solved above is an underdamped harmonic motion. These are all elastic motions in the real world. Obviously, the cubic Bezier curves in timing-function cannot be simulated. You need a library of animations that can simulate spring damping systems.

React based elastic animation library

React elastic animation library There are three types of react elastic animation library in the industry.

  • react-motion
    • The author of Spring animation, does not support hooks API, not updated in 3 years
  • react-spring
    • React-motion inspired, hooks supported, powerful
  • framer-motion
    • Support hooks, powerful function, while adding a lot of declarative attributes, simple and friendly API

Comparing the NPM downloads of the three libraries, they are almost the same

name download values
react-motion
react-spring
framer-motion

Framer-motion is one of the big ones, and it’s growing really fast

Weekly downloads in October 2020 were almost 10 times higher than in the same period in 2019, thanks in large part to the friendliness of its API. Let’s explore how Framer-Motion can be used.

framer-motion

What is Framer-motion? Take a look at www.framer.com/motion/

A production-ready motion library for React. Utilize the power behind Framer, the best prototyping tool for teams. Proudly open source.

Framer Motion is a production-grade React animation library that supports its own prototype tool framer and is proudly open sourced. In fact, Framer Motion, as an animation library, provides some extremely concise apis to help us create complex animations. These apis help us abstract away the complexity behind animations, making it easy to create animations.

The website highlights several features that are part of its minimalist API

  • Declarative apis
  • Components share layout animations
  • Gesture support

Let’s take a look at some of the demos I developed, where the spring damping properties mentioned above are developed using Framer-Motion

Spring damping demo

import React from 'react'
import { motion } from 'framer-motion'

import './index.css'

function index() {
  return (
    <>
      <div className="wrap">
        <div className="title">Zero damping</div>
        <motion.div
          className="ball"
          animate={{
            x: 150.transition: {
              type: 'spring',
              damping: 0,}}} / >
      </div>
      <div className="wrap">
        <div className="title">under-damped</div>
        <motion.div
          className="ball"
          animate={{
            x: 150.transition: {
              type: 'spring',
              damping: 2,}}} / >
      </div>
      <div className="wrap">
        <div className="title">A damping</div>
        <motion.div
          className="ball"
          animate={{
            x: 150.transition: {
              type: 'spring',
              damping: 100,}}} / >
      </div>
      <div className="wrap">
        <div className="title">Critical damping</div>
        <motion.div
          className="ball"
          animate={{
            x: 150.transition: {
              type: 'spring',
              damping: 17,}}} / >
      </div>

      <br />
      <br />
      <br />
      <button
        type="button"
        onClick={()= > {
          window.location.reload()
        }}
      >
        reload this page
      </button>
    </>)}export default index
Copy the code

The demo page links gaohaoyang. Making. IO/framer – moti…

You can see that the code is really neat. The code is essentially divided into two parts:

  • Basic component created by combining HTML or SVG tags prefixed with Motion
  • API for interfacing with components through Prop

Modify the displacement and damping in the code as follows. In the code, only set the displacement X that div needs to move, and the damping value (use the default value of mass and stiffness coefficient), and then complete the triggering of the animation. This is completely different from the traditional transition animation concept of setting duration equivalents.

animate={{
  x: 150.transition: {
    type: 'spring'.// Spring animation
    damping: 0./ / damping values}}},Copy the code

Take a look at the attribute changes on the tag as the page is rendered

You can see that the value of translateX changes from frame to frame, and framer-Motion adds the attribute of translateZ(0px) for performance.

fadeInOut demo

Now let’s look at an animation demo of elements being shown and hidden. Normally, we would listen for the transitionEnd event when the element disappears and then remove the DOM node, but framer-Motion does this for us as well. Just use the AnimatePresence tag and the code looks like this:

import React, { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'

function index() {
  const [toggleShow, setToggleShow] = useState(true)
  return (
    <>
      <br />
      <br />
      <button
        onClick={()= >{ setToggleShow((pre) => ! pre) }} type="button" > toggleShow</button>
      <br />
      <br />

      <AnimatePresence>
        {toggleShow && (
          <motion.div
            style={{
              backgroundColor: '#ddd',
              width: '50vw',
              height: '80vw'}}key="modal"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1.x: 100 }}
            exit={{ opacity: 0.x: 0 }}
          >
            fadeInOut animation
          </motion.div>
        )}
      </AnimatePresence>
    </>)}export default index
Copy the code
Click or scan the experience

In the code, we can see that the div is set to show or hide state using useState. In an action that requires a remove action, wrap it with the AnimatePresence tag and set the exit property

exit={{ opacity: 0.x: 0 }}
Copy the code

Take a look at how the tabs change during page rendering

When you click the Toggle button, the animation is performed first and then the DOM is removed.

drag demo

import React from 'react'
import { motion } from 'framer-motion'
import './index.css'

function index() {
  return (
    <div className="container">
      <div
        className="box"
        style={{
          width: '300px',
          height: '500px'}} >
        <motion.div
          style={{ width: '44px', height: '44px'}}className="ball"
          drag
          dragConstraints={{
            top: - 228..bottom: 228.left: - 128..right: 128,}}dragElastic=0.2} {
        />
      </div>
    </div>)}export default index
Copy the code

The effect is as follows:

Click or scan the experience

As you can see, the code is very simple. You can set the drag attribute, dragElastic elasticity, and drag boundary conditions to get this effect, and when you let go of the drag, the div will continue to move with inertia.

Also when rendering in the browser, Framer-Motion uses Translate3D () to turn on GPU acceleration for performance optimization.

transform: translate3d(128px, 228px, 0px);
Copy the code

Other more demo please visit gaohaoyang. Making. IO/framer – moti…

Or scan code:

The git address of demo is github.com/Gaohaoyang/…

Main apis framer – motion

Framer-motion doesn’t just have Spring animations, it also has Tween tween frames, Keyframes, choreography, lots of gestures, hooks, Details you can refer to www.framer.com/api/motion/ website document

conclusion

Animations of different complexity can use different animation libraries. Consider framer-Motion for realistic large-area/DOM/SVG React/RAx animations. Framer-motion has an extremely compact API and supports Spring elastic animation, gesture drag, hooks apis, and more.

These are the charms of physics and mathematics, thanks to the great pioneers of science: