Mobile phone scrolling-how to achieve inertial scrolling

how to calculate the speed when the mobile phone is inertial scrolling, and how to decrease the speed after that

because I want to be a scrolling plug-in on the mobile phone, I want to simulate the original inertia scrolling of the phone, that is, after the fingers swipe, the mobile phone page will still scroll for some distance after the fingers are lifted.

now I have tried two methods
1. When the time between finger start and end is less than 300ms, the length that needs to continue scrolling is calculated according to the finger movement distance. After end, the animation effect is achieved through transition and top
2. After finger end, the draw speed is calculated by finger movement distance and usage time. If the use time is less than 300ms, a function that decreases speed each time is called through requestAnimationFrame loop. Jump out of the function loop when the speed is very small. Set the top value every time in the function, because the requestAnimationFrame interval is very short, about 16ms after that, to achieve the effect

the first method code

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no"/>
    <meta charset="utf-8"/>
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .container {
            position: relative;
            margin: 50px;
            width: calc(100% - 100px);
            height: 400px;
            border: 1px solid green;
            box-sizing: border-box;
            overflow: hidden;
        }
        .container .scroll {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            transition: all 160ms ease-out;
        }
        .container p {
            margin: 0 auto 10px;
            width: 80%;
            height: 80px;
            border: 1px solid yellow;
        }
        .container .scroll:after {
            content: "";
            display: block;
            clear: both;
        }

        .container .barBox {
            position: absolute;
            right: 2px;
            top: 2px;
            width: 3px;
            height: calc(100% - 4px);
            background: rgba(100, 200, 100, 0.3);
        }
        .container .barBox .bar {
            position: absolute;
            top: 0;
            right: 0;
            height: 0;
            width: 100%;
            background: -sharpccc;
            transition: all 160ms ease-out;
        }
    </style>
</head>
<body>
    <div class="container" id="container">
        <div class="scroll">
            <p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

</div> <div class="barBox" id="barBox"> <div class="bar"></div> </div> </div> <script> var oContainer = document.getElementById("container"); var oScroll = oContainer.children[0]; var oBarBox = document.getElementById("barBox"); var oBar = oBarBox.children[0]; // var iWrapperH = numberPx(getStyle(oContainer, "height")); var iScrollH = numberPx(getStyle(oScroll, "height")); var iBarBoxH = numberPx(getStyle(oBarBox, "height")); var iBarH = iWrapperH / iScrollH * iBarBoxH; // setStyle(oBar, { height: iBarH + "px" }) // var startTime = 0; var endTime = 0; var isMove = false; var iScrollTop = 0; var iBarTop = 0; var endTimeout = null; oContainer.addEventListener("touchstart", function (e) { startTime = new Date().getTime(); var startY = e.targetTouches[0].clientY; var startTop = numberPx(getStyle(oScroll, "top")); var endY = startY; var endTop = startTop; setStyle(oScroll, { top: startTop + "px" }) setStyle(oBar, { top: -startTop / iScrollH * iBarBoxH + "px" }) var moveFn = function (e) { isMove = true; var nowY = e.targetTouches[0].clientY; var nowTop = startTop; endY = nowY; var moveY = nowY - startY; nowTop += moveY; endTop = nowTop; iScrollTop = nowTop > 0 ? 0 : (nowTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : nowTop); iBarTop = -iScrollTop / iScrollH * iBarBoxH; setStyle(oScroll, { top: iScrollTop + "px" }) setStyle(oBar, { top: iBarTop + "px" }) } var endFn = function (e) { endTime = new Date().getTime(); if ( endTime - startTime <= 200 && isMove ) { var moveY = endY - startY; var iScale = 1; var iTime = 300; if ( Math.abs(moveY) <= 100 ) { iScale = 1; iTime = 300; } else if ( Math.abs(moveY) <= 200 ) { iScale = 2; iTime = 500; } else { iScale = 3; iTime = 700; } moveY = moveY * iScale; endTop += moveY; iScrollTop = endTop > 0 ? 0 : (endTop < iWrapperH - iScrollH ? iWrapperH - iScrollH : endTop); iBarTop = -iScrollTop / iScrollH * iBarBoxH; setStyle(oScroll, { transition: "all " + iTime + "ms ease-out", top: iScrollTop + "px" }) setStyle(oBar, { transition: "all " + iTime + "ms ease-out", top: iBarTop + "px" }) clearTimeout(endTimeout); endTimeout = setTimeout(function () { setStyle(oScroll, { transition: "all 160ms ease-out" }) setStyle(oBar, { transition: "all 160ms ease-out", }) }, 500); } isMove = false; document.documentElement.removeEventListener("touchmove", moveFn); oContainer.removeEventListener("touchend", endFn); } document.documentElement.addEventListener("touchmove", moveFn); oContainer.addEventListener("touchend", endFn); }) function getStyle (obj, name) { if(window.getComputedStyle) { return getComputedStyle(obj, null)[name]; } else { return obj.currentStyle[name]; } } function setStyle (obj, oStyle) { for(var i in oStyle) { obj.style[i] = oStyle[i]; } } function numberPx (num) { return Number(num.split("px")[0]); } </script> </body> </html>

the second code

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no"/>
    <meta charset="utf-8"/>
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .container {
            position: relative;
            margin: 50px;
            width: calc(100% - 100px);
            height: 400px;
            border: 1px solid green;
            box-sizing: border-box;
            overflow: hidden;
        }
        .container .scroll {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
        }
        .container p {
            margin: 0 auto 10px;
            width: 80%;
            height: 80px;
            border: 1px solid yellow;
        }
        .container .scroll:after {
            content: "";
            display: block;
            clear: both;
        }

        .container .barBox {
            position: absolute;
            right: 2px;
            top: 2px;
            width: 3px;
            height: calc(100% - 4px);
            background: rgba(100, 200, 100, 0.3);
        }
        .container .barBox .bar {
            position: absolute;
            top: 0;
            right: 0;
            height: 0;
            width: 100%;
            background: -sharpccc;
        }
    </style>
</head>
<body>
    <div class="container" id="container">
        <div class="scroll">
            <p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

</div> <div class="barBox" id="barBox"> <div class="bar"></div> </div> </div> <script> var oContainer = document.getElementById("container"); var oScroll = oContainer.children[0]; var oBarBox = document.getElementById("barBox"); var oBar = oBarBox.children[0]; // var iWrapperH = numberPx(getStyle(oContainer, "height")); var iScrollH = numberPx(getStyle(oScroll, "height")); var iBarBoxH = numberPx(getStyle(oBarBox, "height")); var iBarH = iWrapperH / iScrollH * iBarBoxH; // setStyle(oBar, { height: iBarH + "px" }) // var startTime = 0; var endTime = 0; var pastTime = 0; // var nowTime = 0; // var isMove = false; var iBarTop = 0; var timer = true; oContainer.addEventListener("touchstart", function (e) { startTime = new Date().getTime(); pastTime = startTime; var startY = e.targetTouches[0].clientY; var startTop = numberPx(getStyle(oScroll, "top")); var endY = startY; var endTop = startTop; timer = false; var moveFn = function (e) { isMove = true; var nowY = e.targetTouches[0].clientY; var nowTop = startTop; endY = nowY; var moveY = nowY - startY; nowTop += moveY; endTop = nowTop = getPos(nowTop); setStyle(oScroll, { top: nowTop + "px" }) setStyle(oBar, { top: getBarTop(nowTop) + "px" }) } var endFn = function (e) { endTime = new Date().getTime(); var speed = (endY - startY) / (endTime - startTime); if ( endTime - startTime <= 300 && isMove ) { speed *= 16; var f = 0, top = endTop; timer = true; show(); function show () { timer && requestAnimationFrame(show); f = Math.min(Math.abs(speed) / 10, 0.5); // if( speed > 0.2 ) { speed -= f } else if(speed < -0.2){ speed += f } else { timer = false speed = 0 return } top += speed; if ( top > 0 || top < iWrapperH -iScrollH ) { timer = false speed = 0 setStyle(oScroll, { top: getPos(top) + "px" }) setStyle(oBar, { top: getBarTop(getPos(top)) + "px" }) return } setStyle(oScroll, { top: top + "px" }) setStyle(oBar, { top: getBarTop(top) + "px" }) } } isMove = false; document.documentElement.removeEventListener("touchmove", moveFn); document.documentElement.removeEventListener("touchend", endFn); } document.documentElement.addEventListener("touchmove", moveFn); document.documentElement.addEventListener("touchend", endFn); }) function getPos (num) { return num >= 0 ? 0 : (num <= iWrapperH - iScrollH ? iWrapperH - iScrollH : num); } function getBarTop (num) { return -num / iScrollH * iBarBoxH; } function getStyle (obj, name) { if(window.getComputedStyle) { return getComputedStyle(obj, null)[name]; } else { return obj.currentStyle[name]; } } function setStyle (obj, oStyle) { for(var i in oStyle) { obj.style[i] = oStyle[i]; } } function numberPx (num) { return Number(num.split("px")[0]); } </script> </body> </html>

you can see the original effect

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalabel=no">
    <title></title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .container {
            position: relative;
            margin: 50px;
            width: calc(100% - 100px);
            height: 400px;
            border: 1px solid green;
            box-sizing: border-box;
            overflow: auto;
        }
        .container p {
            margin: 0 auto 10px;
            width: 80%;
            height: 80px;
            border: 1px solid yellow;
        }
    </style>
</head>
<body>
    <div class="container" id="container">
        <div class="scroll">
            <p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

<p style="border-color: green;">

<p style="border-color: yellow;">

<p style="border-color: -sharp932132;">

<p style="border-color: -sharp00007f;">

<p style="border-color: red;">

<p style="border-color: -sharp432892;">

<p style="border-color: -sharp007f00;">

<p style="border-color: blue;">

<p style="border-color: green;">

<p style="border-color: -sharp7f0000;">

<p style="border-color: -sharp003947;">

<p style="border-color: -sharpcccc33;">

</div> </div> </body> </html>

although it looks like scrolling now, it feels a long way from the original inertia scrolling and the effects of iScroll, better-scroll, etc. Look at their source code, I really can"t find anything from anywhere. I hope the bosses who understand it can give me some advice!

Dec.08,2021

is mainly a problem of algorithm (motion curve). With tranform to move
a good curve, you can move more naturally


it should be that the motion curve is too dry. Recommend a motion curve algorithm.
I have done a piece of animation with this curve algorithm before, and it feels very simple, and the effect is good.
how to use
the first half is about requestAnimationFrame, and the second half is about how to use it.
2013-09-30_170002.png

github address

Menu