Home > database >  Migrate jQuery animate({scrollLeft: x}) to vanilla JS using window.requestAnimationFrame()
Migrate jQuery animate({scrollLeft: x}) to vanilla JS using window.requestAnimationFrame()

Time:01-25

I'm trying to migrate some jQuery code that performs a smooth scroll (back and forth) in an horizontal image gallery when clicking over its images (putting the clicked image in the center of the browser viewport):

jQuery:

$('.page-template-format-horizontal .exhibit-image').on('click', function (e) {
    var slideWidth = $(this).width();
    var windowWidth = $(window).width();
    var scrollTo = $(this).position().left;
    var offset = scrollTo - (windowWidth / 2)   (slideWidth / 2);
    $('html, body').animate({
        scrollLeft: offset
    }, 500);
    e.preventDefault();
});

This is the vanilla JS code I've come up with. I know that I can use the behaviour: 'smooth' option in the window.scrollBy() function, but I'd like to use the window.requestAnimationFrame() function instead because I need to support some older Safari versions that don't support the smooth behavior option.

JS:

document.querySelector('.page-template-format-horizontal .exhibit-image').addEventListener('click', function (e) {
    var slideWidth = e.currentTarget.getBoundingClientRect().width;
    var windowWidth = window.innerWidth;
    var scrollTo = e.currentTarget.offsetLeft;
    var offset = scrollTo - (windowWidth / 2)   (slideWidth / 2);

    var duration = 50;
    var startLocation = window.pageXOffset;
    var endLocation = offset;
    var distance = endLocation - startLocation;
    var increments = distance / (duration / 16);

    function step() {
        window.scrollBy(increments, 0);
        if ( window.pageXOffset <= endLocation) {
            window.requestAnimationFrame(step);
        }
    }
    window.requestAnimationFrame(step);
    e.preventDefault();
});

It quite works, but just when scrolling to the right, not to the left. Any help would be appreciated.

CodePudding user response:

I managed to solve this myself. This is the code I came up with:

document.querySelectorAll('.page-template-format-horizontal .exhibit-image').forEach(function(item) {
    item.addEventListener('click', function (e) {
        var slideWidth = e.currentTarget.getBoundingClientRect().width;
        var windowWidth = window.innerWidth;
        var scrollTo = e.currentTarget.offsetLeft;
        var startLocation = window.pageXOffset;
        var endLocation = scrollTo - (windowWidth / 2)   (slideWidth / 2);
        var distance = endLocation - startLocation;
        var duration = 400;
        var easing = function (t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2) 1 }
        var start;

        if (!distance) {
            return;
        }

        function step(timestamp) {
            start = start || timestamp;
            var time = timestamp - start;
            var percent = Math.min(time / duration, 1);
            percent = easing(percent);
            window.scrollTo(parseInt(startLocation   distance * percent), window.scrollY);
            if (time < duration) {
                window.requestAnimationFrame(step);
            }
        }
        window.requestAnimationFrame(step);
        e.preventDefault();
    });
});
  • Related