js realizes a gradually increasing digital animation

js realizes a gradually increasing digital animation

background

The most commonly used component in visualization large-screen projects is the digital component. To show a change in data, in order to improve the visual effect, it is necessary to add a scrolling effect to the number to achieve a scrolling animation that gradually increases from one number to another.

First, a mind map:

Achieve a similar effect to a scroll wheel, with the container fixed and the numbers scrolling upwards

First, list all possible values ​​to form a vertical list, then fix a container and change the offset value of the number at a constant speed.

The following is an introduction to the implementation of this solution. There are ten element values ​​from 0 to 9, and each number occupies 10% of the vertical list, so the vertical offset values ​​are 0% —> -90%

accomplish:

<ul>
  <li>
    <span>0123456789</span>
  </li>
</ul>
ul{
  margin-top: 200px;
}
ul li{
  margin:0 auto;
  width: 20px;
  height: 30px;
  text-align: center;
  border:2px solid rgba(221,221,221,1);
  border-radius:4px;
}
ul li span{
  position: absolute;
  color: #fff;
  top: 30%;
  left: 50%;
  transform: translate(-50%,0);
  transition: transform 500ms ease-in-out;
  writing-mode: vertical-rl;
  text-orientation: upright;
  letter-spacing: 17px;
}
let spanDom = document.querySelector('span')
let start = 0
setInterval(() => {
  start++
  if(start>9){
    start = 0
  }
  spanDom.style.transform = `translate(-50%,-${start*10}%)`
}, 1000)

There is a problem with the above code. When we go from 9 to 0, the container offset goes directly from -90% to 0%. However, due to the fixed transition animation time, there will be a situation of scrolling in the opposite direction. To solve this problem, you can refer to the idea of ​​seamless scrolling.

  • Copy a 0 after 9.
  • When the vertical list scrolls to 9, continue to scroll to the copied 0
  • When scrolling to the copied 0, change the offset position of the list to 0 and control the animation time to 0
<ul>
  <li>
    <span>01234567890</span>
  </li>
</ul>
let spanDom = document.querySelector('span')
let start = 0
var timer = setInterval(fn, 1000);
function fn() {
  start++
  clearInterval(timer)
  timer = setInterval(fn,start >10 ? 0 : 1000);
  if(start>10){
    spanDom.style.transition = `none`
    start = 0
  }else{
    spanDom.style.transition = `transform 500ms ease-in-out`
  }
  spanDom.style.transform = `translate(-50%,-${start/11*100}%)`
} 

Using two elements to achieve scrolling

Look carefully at the effect of the animation. In fact, there are only two elements in the viewport, one is the previous value, and the other is the current value. The scroll offset value only needs to be set to translateY(-100%).

Specific ideas:

  • Declare two variables to store the previous value prev and the changed value cur respectively; declare a variable play as the switch of the scrolling animation of these two values
  • Use useEffect to listen to the incoming value: if it is a valid number, assign the value before the change to prev, assign the current incoming value to cur, and set play to true to start the scrolling animation

The following is the adjusted code structure:

 <div className={styles.slider}>
   {[prev, cur].map((item, index) => (
      <span key={index} className={`${styles['slider-text']} ${playing && styles['slider-ani']} ${(prev === 0 && cur === 0 && index ===0) && styles['slider-hide']}`}>
        {item}
      </span>
    ))}
  </div>
const { value} = props
const [prev, setPrev] = useState(0)
const [cur, setCur] = useState(0)
const [playing, setPlaying] = useState(false)

  const play = (pre, current) => {
    setPrev(pre)
    setCur(current)
    setPlaying(false)
    setTimeout(() => {
      setPlaying(true)
    }, 20)
  }

  useEffect(() => {
    if (!Number.isNaN(value)) {
      play(cur, value)
    } else {
      setPrev(value)
      setCur(value)
    }
  }, [value])

.slider {
  display: flex;
  flex-direction: column;
  height: 36px;
  margin-top: 24%;
  overflow: hidden;
  text-align: left;
}

.slider-text {
  display: block;
  height: 100%;
  transform: translateY(0%);
}

.slider-ani {
  transform: translateY(-100%);
  transition: transform 1s ease;
}
.slider-hide {
  opacity: 0;
}

A digital component that implements the upward scrolling of multiple scroll wheels

Use H5's requestAnimationFrame() API to achieve a gradually increasing animation effect

Implement a scrolling animation of a number that gradually increases and must be completed within a specified time. To see smooth animation effects, it is necessary to update the element status at a certain frequency. JS animation is achieved by continuously rendering/drawing elements in a very short period of time, so the timer has always been the core technology of Javascript animation. The key is the refresh interval. The refresh time needs to be as short as possible so that the animation effect can appear smoother and not stuck; at the same time, the refresh interval cannot be too short to ensure that the browser is capable of rendering the animation.
Most computer monitors have a refresh rate of 60Hz, which means they redraw the image 60 times per second. Therefore, the optimal loop interval for smooth animation is usually 1000ms/60, which is approximately 16.6ms

Timer comparison

  • Unlike setTimeout and setInterval, requestAnimationFrame does not require programmers to set the time interval themselves. The problem with setTimeout and setInterval is the low precision. Their internal operating mechanism determines that the interval parameter actually only specifies the time to add the animation code to the browser UI thread queue to wait for execution. If other tasks have been added to the queue, the animation code will have to wait until the previous tasks are completed before executing.
  • requestAnimationFrame uses the system time interval, which requires the browser to redraw at its own frequency to maintain the best drawing efficiency. It will not cause over-drawing and increase overhead due to a short interval; nor will it cause animation to be stuck and not smooth due to a long interval. It allows various web page animation effects to have a unified refresh mechanism, thereby saving system resources, improving system performance, and improving visual effects.
  • requestAnimationFrame will bring together all DOM operations in each frame and complete them in one redraw or reflow, and the time interval for redrawing or reflowing closely follows the refresh rate of the browser.
  • For hidden or invisible elements, no repainting or reflow will be performed, which means less CPU, GPU and memory usage.
  • requestAnimationFrame is an API provided by the browser specifically for animation. The browser will automatically optimize the method call at runtime, and if the page is not active, the animation will be automatically paused, effectively saving CPU overhead.

RequestAnimationFrame implements scrolling animation

The animation starts, recording the time when the animation starts, startTimeRef.current

const startTimeRef = useRef(Date.now());
const [t, setT] = useState(Date.now());

For each subsequent frame of animation, record how long it has been since the start of the animation and calculate the number that should be reached in the current frame, i.e., currentValue

useEffect(() => {
    const rafFunc = () => {
      const now = Date.now();
      const t = now - startTimeRef.current;
      if (t >= period) {
        setT(period);
      } else {
        setT(t);
        requestAnimationFrame(rafFunc);
      }
    };
    let raf;
    if (autoScroll) {
      raf = requestAnimationFrame(rafFunc);
      startTimeRef.current = Date.now();
    } else {
      raf && cancelAnimationFrame(raf);
    }
    return () => raf && cancelAnimationFrame(raf);
}, [period, autoScroll]);

const currentValue = useMemo(() => ((to - from) / period) * t + from, [t, period, from, to]);

Compare the numbers on each digit at the current position. If there is a change, change the offset. The offset is the difference between the number on the current digit and the next digit. This change is strung together in each frame to form a scrolling animation.

Achievements

This is the end of the article about how to use js to implement a gradually increasing digital animation. For more relevant js gradually increasing digital animation content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of using jquery lightweight digital animation plugin countUp.js
  • Using native JS and jQuery to realize digital linear animation
  • js randomly generates a string of letters and numbers with random animation numbers

<<:  Example of how nginx implements dynamic and static separation

>>:  MySQL learning database search statement DQL Xiaobai chapter

Recommend

Detailed explanation of the order of JS object traversal

Some of you may have heard that the order of trav...

Example test MySQL enum type

When developing a project, you will often encount...

Solution to the problem that docker nginx cannot be accessed after running

## 1 I'm learning docker deployment recently,...

Implementing timed page refresh or redirect based on meta

Use meta to implement timed refresh or jump of th...

Detailed tutorial on using the Prettier Code plugin in vscode

Why use prettier? In large companies, front-end d...

HTML (css style specification) must read

CSS style specifications 1. Class Selector 2. Tag...

Example of converting timestamp to Date in MySQL

Preface I encountered a situation at work: In the...

MySQL 8.0.20 Installation Tutorial with Pictures and Text (Windows 64-bit)

1: Download from mysql official website https://d...

Vue state management: using Pinia instead of Vuex

Table of contents 1. What is Pinia? 2. Pinia is e...

MySQL 8.0.21 installation steps and problem solutions

Download the official website First go to the off...

Summary of methods for querying MySQL user permissions

Introduce two methods to view MySQL user permissi...

Can MySQL's repeatable read level solve phantom reads?

introduction When I was learning more about datab...

Four ways to combine CSS and HTML

(1) Each HTML tag has an attribute style, which c...