0

I would like to smoothly animate horizontal scrolling of page sections by full width of the viewport, by clicking on Previous Page and Next Page buttons, using Animate Plus.

Here is the relevant piece of code:

import animate from "https://cdn.jsdelivr.net/npm/animateplus@2/animateplus.js"

const previousPage = document.querySelector("button:nth-of-type(1)")
const nextPage = document.querySelector("button:nth-of-type(2)")

previousPage.addEventListener("click", () => {
  window.scrollBy(-window.innerWidth, 0)
  animate({
    easing: "out-quintic"
  })
})

nextPage.addEventListener("click", () => {
  window.scrollBy(window.innerWidth, 0)
  animate({
    easing: "out-quintic"
  })
})

My full code can be found here:

https://codepen.io/anon/pen/bzVGMz


The animation effect I would like to achieve can be found here:

http://animateplus.com/examples/anchor-scroll/

What am I missing?

Community
  • 1
  • 1
Tzar
  • 5,132
  • 4
  • 23
  • 57

1 Answers1

1

The idea is to use the change callback and calculate an increment to scroll the window by. This increment is equal to the progress multiplied by the distance we want to scroll.

However, I assume you want to be able to navigate through multiple sections using only a prev and a next buttons. Since the user can also manually scroll to the different sections, you need a way to detect which section is currently in view and go to the previous/next one programatically.

The following code does this by maintaining a list of sections ordered by their left coordinates. For this example, I consider the current section as being the section spanning the centerline of the screen.

import animate from "https://cdn.jsdelivr.net/npm/animateplus@2/animateplus.js"

const previousPage = document.querySelector("button:nth-of-type(1)")
const nextPage = document.querySelector("button:nth-of-type(2)")

const root = document.scrollingElement;

const sections = Array.from(document.querySelectorAll("section")).sort((s1, s2) => {
  return s1.getBoundingClientRect().left - s2.getBoundingClientRect().left;
});

// get the section that spans the centerline
const getSectionInView = () => {
  const halfWdidth = window.innerWidth / 2;
  const index = sections.findIndex(s =>
    s.getBoundingClientRect().left <= halfWdidth &&
    s.getBoundingClientRect().right > halfWdidth
  );
  return index;
};

// find the next or previous section in the list
const getNextSection = (dir) => {
  const sectionInViewIndex = getSectionInView();
  const nextIndex = sectionInViewIndex + dir;
  const numSections = sections.length;
  const nextSectionIndex = nextIndex < 0 || nextIndex >= numSections ? sectionInViewIndex : nextIndex;
  return sections[nextSectionIndex];
};

// animation function
const animateScroll = (dir) => {
  const from = root.scrollLeft;
  const { left } = getNextSection(dir).getBoundingClientRect();
  return progress => root.scrollLeft = from + progress * left
};

previousPage.addEventListener("click", () => {
  animate({
    easing: "out-quintic",
    change: animateScroll(-1)
  });
});

nextPage.addEventListener("click", () => {
  animate({
    easing: "out-quintic",
    change: animateScroll(1)
  });
});

Here is a CodePen

For it tor work, you have to remove scroll-snap-align: center; from the section style or set it to none as it conflicts with the animation.

jo_va
  • 13,504
  • 3
  • 23
  • 47
  • It animates smoothly, but for some reason it doesn't scroll by full width now – it's at ninety-something percent. – Tzar Jan 24 '19 at 14:37
  • 1
    I will modify it to use const document.scrollingElement.scrollLeft, it should work – jo_va Jan 24 '19 at 14:42
  • Thank you so much! Just one more thing… If I quickly tap on the buttons, the sections do not snap to the edges of the window. – Tzar Jan 24 '19 at 15:16
  • 1
    @Tzar I have modified the answer and the CodePen. It should work with manual scrolling too. – jo_va Jan 24 '19 at 16:06