'Smooth scroll using translateY in js

I created class based functions in my project. Scroll class is to create smooth scroll behaviour using translateY property. The second one called SideNavigation generate bullet list navigation based on projects elements length. I want to achive smooth scroll effect also on click on those bullets, but can't find solution for this. Code snippet included. Hope anyone can help with this.

const config = {
  ease: 0.1,
  current: 0,
  previous: 0,
  rounded: 0
}

class Scroll {
  constructor(velocity) {
    this.velocity = velocity
  }

  setBodyHeight() {
    document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
  }

  isMobile() {
    return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
  }

  onScroll() {
    config.current = window.scrollY
    config.previous += (config.current - config.previous) * config.ease
    config.rounded = Math.round(config.previous * 100) / 100

    const difference = config.current - config.rounded
    const acceleration = difference / document.body.clientWidth
    const velocity = +acceleration
    const skew = velocity * this.velocity

    const element = document.getElementById('projects')

    this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`

    requestAnimationFrame(() => this.onScroll())
  }
}

class SideNavigation {
  constructor() {
    createBullets()
  }
}

function createBullets() {
  const bulletWrapper = document.createElement('div')
  const bulletList = document.createElement('ul')

  bulletWrapper.classList.add('side-nav')

  for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
    const bullet = document.createElement('li')

    bullet.setAttribute('id', '' + i)

    bullet.addEventListener('click', event => {
      console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
      // scroll to current section
    })

    bulletList.append(bullet)
    bulletWrapper.append(bulletList)
    document.body.append(bulletWrapper)
  }
}

window.addEventListener('load', () => {
  const scrollInstance = new Scroll(8, true)
  const sideNav = new SideNavigation()

  scrollInstance.setBodyHeight()

  requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
  height: 100%;
}

main {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

#projects {
  width: 80%;
}

.project {
  height: 500px;
  width: 100%;
  background: #333;
  color: #fff;
}

.side-nav {
  position: fixed;
  right: 20px;
  top: 20%;
  z-index: 10;
}

.side-nav li {
  width: 30px;
  height: 30px;
  display: block;
  background: #333;
  margin-bottom: 20px;
  border-radius: 50%;
  cursor: pointer;
}
<body>
  <main>
    <div id="projects">
      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>
    </div>
  </main>
</body>


Solution 1:[1]

I hope I understood your question correctly. Is this what you're looking for?

const config = {
  ease: 0.1,
  current: 0,
  previous: 0,
  rounded: 0
}

class Scroll {
  constructor(velocity) {
    this.velocity = velocity
  }

  setBodyHeight() {
    document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
  }

  isMobile() {
    return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
  }

  onScroll() {
    config.current = window.scrollY
    config.previous += (config.current - config.previous) * config.ease
    config.rounded = Math.round(config.previous * 100) / 100

    const difference = config.current - config.rounded
    const acceleration = difference / document.body.clientWidth
    const velocity = +acceleration
    const skew = velocity * this.velocity

    const element = document.getElementById('projects')

    this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`

    requestAnimationFrame(() => this.onScroll())
  }
}

class SideNavigation {
  constructor() {
    createBullets()
  }
}

function createBullets() {
  const bulletWrapper = document.createElement('div')
  const bulletList = document.createElement('ul')

  bulletWrapper.classList.add('side-nav')

  for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
    const bullet = document.createElement('li')

    bullet.setAttribute('id', '' + i)

    bullet.addEventListener('click', event => {
      console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
      // scroll to current section
      window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset);
    })

    bulletList.append(bullet)
    bulletWrapper.append(bulletList)
    document.body.append(bulletWrapper)
  }
}

window.addEventListener('load', () => {
  const scrollInstance = new Scroll(8, true)
  const sideNav = new SideNavigation()

  scrollInstance.setBodyHeight()

  requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
  height: 100%;
}

main {
  position: fixed;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

#projects {
  width: 80%;
}

.project {
  height: 500px;
  width: 100%;
  background: #333;
  color: #fff;
}

.side-nav {
  position: fixed;
  right: 20px;
  top: 20%;
  z-index: 10;
}

.side-nav li {
  width: 30px;
  height: 30px;
  display: block;
  background: #333;
  margin-bottom: 20px;
  border-radius: 50%;
  cursor: pointer;
}
<body>
  <main>
    <div id="projects">
      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>

      <div class="project">
        <p>Some text example</p>
      </div>
    </div>
  </main>
</body>

The scrollBy function's second parameter allows to modify the window's Y axis. But as we want each bullet to jump to the start of it's project, we decrease the current Y axis of the page from the Y axis of the project window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rani Giterman