Skip to content
Advertisement

Binding touch and scroll to wheel event

I have this code for vehicle to horizontal and back to vertical scrolling, however it only works on mouse wheel scroll. I also need it to respond accordingly to mobile touch, scrollbars, page up/down, and the keyboard arrow keys. Below is my code:

(function(){
    init();

    var g_containerInViewport;
    function init(){
        setStickyContainersSize();
        bindEvents();
    }

    function bindEvents(){
        window.addEventListener("wheel", wheelHandler);  

        //do not work
        window.addEventListener("touchstart", wheelHandler);
        window.addEventListener("touchmove", wheelHandler);
        window.addEventListener("touchend", wheelHandler);
        window.addEventListener("touchcancel", wheelHandler);

    
    }

    function setStickyContainersSize(){
        document.querySelectorAll('.sticky-container').forEach(function(container){
            const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight);
            container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
        });
    }

    function isElementInViewport (el) {
        const rect = el.getBoundingClientRect();
        return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
    }

    function wheelHandler(evt){

        
        const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container){
            return isElementInViewport(container);
        })[0];

        if(!containerInViewPort){
            return;
        }

        var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
        var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
        let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;

        if(g_canScrollHorizontally){
            containerInViewPort.querySelector('main').scrollLeft += evt.deltaY;
        }
    }
})();
html,
body {
  margin: 0;
  font-family: sans-serif;
}

.vertical-section{
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

main {
  overflow-x: hidden;
  display: flex;
  position: sticky;
  top:0;
}

h1 {
  margin: 0;
  padding: 0;
}

section {
  min-width: 50vw;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 4ch;
}

section:nth-child(even) {
  background-color: teal;
  color: white;
}
<div class="vertical-section">
  scrolling is vertical
</div>
<div class="sticky-container">
  <main>
    <section>
      <h1>scrolling</h1>
    </section>
    <section>
      <h1>is</h1>
    </section>
    <section>
      <h1>now</h1>
    </section>
    <section>
      <h1>horizontal</h1>
    </section>
  </main>
</div>
<div class="vertical-section">
  scrolling is vertical again
</div>
<div class="sticky-container">
  <main>
    <section>
      <h1>scrolling</h1>
    </section>
    <section>
      <h1>is</h1>
    </section>
    <section>
      <h1>now</h1>
    </section>
    <section>
      <h1>horizontal</h1>
    </section>
  </main>
</div>

How can I make this work for mobile touch, scroll bar, arrow keys, and page up/down?

Thanks

Advertisement

Answer

My solution was to use the scroll event, it works on all devices:

let lastKnownScrollPosition = 0;
let deltaY = 0;

window.addEventListener("scroll", wheelHandler);

document.querySelectorAll('.sticky-container').forEach(function(container) {
    const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight);
    container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
});


function isElementInViewport(el) {
    const rect = el.getBoundingClientRect();
    return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}

function wheelHandler(event) {

    deltaY = window.scrollY - lastKnownScrollPosition;
    lastKnownScrollPosition = window.scrollY;


    console.log('deltaY', deltaY);


    const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) {
        return isElementInViewport(container);
    })[0];

    if (!containerInViewPort) {
        return;
    }

    var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
    var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
    let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;


    if (g_canScrollHorizontally) {

        containerInViewPort.querySelector('main').scrollLeft += deltaY;

    }
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement