Функция по скролу плавному страницы до определенных точек

Есть функция которую писали под первые требования

function automatic_scroll( arrayHights = [{points: 150, delay: 0, animation: 2500}, {points: 2028, delay: 1800, animation: 2800}, {points: 3035, delay: 2200, animation: 3800},{points: 4435, delay: 4000, animation: 800},{points: 4535, delay: 7000, animation: 2000}], delayScript = 2000, debug = false) {
if(debug) {
    $('body').click(function(e){
        var coord = e.pageY;
        console.log("Координата: " + coord);
    });
}
else {
    function scripts_start() {
       
            function delay(time) {
                console.log('fdelay(time) ' + time);
              return new Promise(resolve => setTimeout(resolve, time)); // айминк верный передаем в тайм время плюс задержку
            }

            async function delayedLog(item,time,animation) {             
              await delay(time);
              console.log('item: '+item);
              console.log('time: '+time);
              console.log('____________');
              smoothScrollTo(item,animation,0,timereturn = true);              
            }

            async function processArray(array) {
                 for (var i = 1; i <= array.length; i++) {
                    var c = i - 1;
                    if (c == 0) {
                        await delayedLog(array[c]['points'],delayScript,array[c]['animation']);
                    }
                    else {
                        await delayedLog(array[c]['points'],array[c]['delay'],array[c]['animation']);
                    }
                 }
              console.log('Done!');
            }

            processArray(arrayHights);  
    }

    setTimeout(scripts_start, delayScript);

   window.smoothScrollTo = (function () {
        var timer, start, factor;
        return function (target, duration, startPlus = 0 , timereturn = false) {
            var offset = window.pageYOffset,
                delta  = target - window.pageYOffset; // Y-offset difference
            duration = duration || 1500;              // default 1 sec animation
            start = Date.now() + startPlus;                       // get start time
            factor = 0;
            if( timer ) {
                clearInterval(timer); // stop any running animations
            }

            function step() {
                var y;
                factor = (Date.now() - start) / duration; // get interpolation factor
                if( factor >= 1 ) {
                    clearInterval(timer); // stop animation
                    factor = 1;           // clip to max 1.0
                }
                y = factor * delta + offset;
                     window.scrollBy(0, y - window.pageYOffset,'smooth');
            }

            timer = setInterval(step, 10);
            return timer;
        };
    }());
}}

пример запуска

automatic_scroll([{points: 700, delay: 0, animation: 1500}, {points: 2528, delay: 10000, animation: 4800}, {points: 3835, delay: 9000, animation: 2800},{points: 5035, delay: 10000, animation: 2800}], 4000, false);

функция прокручивает до точек определенных со своей задержкой (задержка работает не точно из за того что не допилил расчет времени прокрутки + остановка на точке) а так же у каждой точки своя скорость прокрутки.

Но нужно теперь переписать или заново написать под задачи :

— Нужно сделать прокрутку плавнее, вроде ease-in-out — чтобы ускорялся и тормозил красиво. Без этой штуки скрипт не несёт пользы, потому что прокрутка некрасивая.

— Код нужно упростить.

  1. Маленький код должен быть такой:

automatic_scroll(points= [0, 659, 1274, 1807, 2330, 2993 ,3856, 4525, 4743], delays = [500, 600, 700, 700, 700, 700, 700, 700, 700], speed = 600); — никаких false или непонятных чисел в конце.

Скорость давай указывать одну и высчитывать её так: берём расстояние до следующей точки, пусть это 600 пикселей, тогда при скорости 600 пк/сек прокрутка произойдёт за 1 секунду. Если бы до следующей точки было 1200 точек, то заняла бы 2 секунды. Если указать скорсть 1200 пк/сек и до точки 1200 пикселей, то снова 1 секунда.

Подскажите как переписать ее по человечески , что использовать лучше (не шарю сильно в промисах и в async но готов разобраться) , каким образом. Достаточно будет базового наброска типо алгоритма программы и в идеале какую технологию применить. Но нужно на js что бы через консоль в браузере работал скрипт.Заранее спасибо за ответ!


Ответы (1 шт):

Автор решения: HTMLProgrammer

https://easings.net/ru#easeInOutCubic на этом сайте есть математические функции для разных типов плавностей. Вот пример реализации:

//Function that calculate animation easing
function delta(x) {
    return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
}

//async delay
async function delay(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

async function automatic_scroll(points, delays, speed) {
    for (let i = 0; i < points.length; i++) {
        await scrollPoint(points[i], delays[i], speed);
    }
}

async function scrollPoint(p, delayms, speed) {
    //Save constants
    const begin = +new Date();
    const start = pageYOffset;
    const time = (p - start) / speed;

    //move
    await animateTo();

    //wait
    await delay(delayms);

    async function animateTo() {
        const t = (+new Date() - begin) / 1000;
        const progress = t / time;
        let delt = delta(progress);

        if (t > time) {
            //time is over
            scrollTo(0, p);
            return;
        } else scrollTo(0, start + delt * (p - start));

        //Promisification of recursion
        return new Promise((resolve, rej) => {
            setTimeout(async () => {
                await animateTo();
                resolve();
            }, 0);
        });
    }
}

window.onload = () => {
    document.body.onclick = () => {
        automatic_scroll([400, 900, 3500], [500, 200, 400], 600);
    };
};
body {
    height: 5000px;
}

body > div {
    position: absolute;
}

#p1 {
    top: 0px;
}

#p2 {
    top: 400px;
}

#p3 {
    top: 900px;
}

#p4 {
    top: 3500px;
}
<div id="p1">Point at 0</div>
<div id="p2">Point at 400</div>
<div id="p3">Point at 900</div>
<div id="p4">Point at 3500</div>

→ Ссылка