Simulate transition-timing-function: ease-out with JS

Keywords: Javascript less iOS Mobile IE

Background: The scrollTop of div needs to be changed in the process of doing the project a few days ago, requiring the movement process to be similar to IOS Webview visual area ceiling animation, first fast and then slow.

Analysis:

  1. css can't set offsetTop. JS needs to change offsetTop dynamically.
  2. Faster and slower animation means that scrollTop changes are slower and slower
  3. The total distance of the mobile is scrollTop.
  4. Events are controlled in two seconds, less than 1 s on a screen and more than 2 s on a screen.
  5. Speed? Distance?? The integral of velocity in time equals distance???? Definite integral!!!!

Conjecture function:

What function is decreasing?

What functions do definite integrals do well? In other words, the original function is easy to find.

What function scope contains 0 (because it needs to start at 0)

What function is the integral of scrollTop in 0-2S?

Blind guess y = 1/x;

Drawing address

Scope does not contain 0???? Shift one unit to the right??? Left plus right minus, up plus down minus!!! Dundun Teaching of Haha Haha High Mathematics Teacher==

y = 1 / (x + 1);

Y = 1 / x + 1; must the integral in 0-2s be scrollTop???

Need a coefficient?????

y = K / (x + 1) ;

How can we get this coefficient?

y = K / (x + 1);

The integral of y on 0 - 2 = scrollTop;

The original function f(x) = Math.log(x) + c of y = 1/x is constant.

By analogy, the original function f (x) = Math. log (x + 1) + C of y = K / x + 1 is obtained, and C is a constant.

The final implementation code is as follows:

optimize performance
setInterval achieves this effect only by using 20ms as the time point for offset changes
Higher optimization???? Request AnimFrame!!! MDN requestAnimationFrame

Core idea: Get the interval between two recursive events??? new Date().getTime() - startTime

The final realization is as follows:

Complete code 
    <!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>test scroll</title>

    <style>

        * {
            padding: 0;
            margin: 0;
        }

        .scroll {
            height: 400px;
            overflow: scroll;
            width: 100px;
            background-color: red;
        }

        .scroll div:nth-child(even) {
            height: 60px;
            background-color: red;
        }

        .scroll div:nth-child(odd) {
            height: 60px;
            background-color: green;
        }

        .button {
            position: fixed;
            right: 0;
            top: 0;
            height: 30px;
            width: 100px;
            background-color: red;
            font-size: 12px;
            line-height: 30px;
            text-align: center;
        }
    </style>

    <script>
        window.addEventListener('load', () => {
            const scrollDOM = document.querySelector('.scroll');
            const btnDOM = document.querySelector('.button');

            window.requestAnimFrame = window.requestAnimationFrame
                || window.webkitRequestAnimationFrame
                || window.mozRequestAnimationFrame;

            btnDOM.addEventListener('click', () => {
                console.log(scrollDOM.scrollTop);
                let scrollTop = scrollDOM.scrollTop;

                window.requestAnimFrame
                    ? window.requestAnimFrame(() => requestFrameUpdateScrollTop(new Date().getTime(), scrollTop))
                    : setTimeUpdateScrollTop(scrollTop);
            });

            const requestFrameUpdateScrollTop = (startTime, scrollTop) => {
                const timeStep = 20;
                // Total time 2000 ms
                const allX = 2000 / timeStep;
                let startX = 0;

                // coefficient
                const ratio = scrollTop / Math.log(allX + 1);
                // Definite integrals are available
                const speed = ratio * (1 / (startX + 1));
                const time = new Date().getTime();
                const timeDiff = time - startTime;
                startX += Math.floor(timeDiff / timeStep) + 1;
                scrollTop = scrollTop - speed * startX;
                scrollTop = scrollTop <= 1 ? 0 : scrollTop;
                scrollDOM.scrollTop = scrollTop;
                if (scrollTop > 0) {
                    window.requestAnimFrame(() => requestFrameUpdateScrollTop(Date.now(), scrollTop));
                }
            };

            const setTimeUpdateScrollTop = scrollTop => {
                if (this.timer) {
                    return;
                }

                const timeStep = 20;
                // Total time 2000 ms
                const allX = 2000 / timeStep;
                let startX = 0;
                // coefficient
                const ratio = scrollTop / Math.log(allX + 1);
                // Definite integrals are available

                this.timer = setInterval(() => {
                    const speed = ratio * (1 / (startX + 1));
                    console.log(speed);
                    startX++;
                    scrollTop = scrollTop - speed;
                    scrollDOM.scrollTop = scrollTop < 0 ? 0 : scrollTop;
                    if (scrollTop <= 0) {
                        clearInterval(this.timer);
                        this.timer = null;
                    }
                }, timeStep);
            };
        });
    </script>
</head>
<body>
<div class="scroll">
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
</div>

<div class="button">
    //Begin 123 123 123 campaign
</div>
</body>
</html>

This is fast and slow animation, and other animation solutions are the same.
Core:

 Find function, do integral!!!
 Find function, do integral!!!
 Find function, do integral!!!

Finally, if you can use css to achieve, less JS

Posted by dessolator on Mon, 23 Sep 2019 03:19:00 -0700