Search code examples
javascriptscrolloverflowgsap

Reaching the edge of overflow: hidden 'curtain' in TweenMax


I have a div with overflow: hidden;

Underneath this div, there is another div which needs to be scrollable.

Scrolling bit works fine with TweenMax, but I need to determine whether I have reached the edge of the parent div or not after every scroll, to change the direction of the scroll. And I cannot figure out how to do this part.

Here is a quick pen: http://codepen.io/anon/pen/wGJVOm


Solution

  • If I understand it correctly, I think you can do something like below:

    var scrollButton = document.getElementById('scroll');
    var container = document.getElementsByClassName('container')[0];
    var inner = document.getElementsByClassName('inner')[0];
    var containerWidth = 0;
    var containerMaxWidth = 0;
    var totalDuration = 1;
    var duration = 0.8;
    var ease = Power2.easeInOut;
    var direction = '';
    var DIRECTION_LEFT = 'DIRECTION_LEFT';
    var DIRECTION_RIGHT = 'DIRECTION_RIGHT';
    var currProgress = 0;
    var progressFactor = 0.2;
    var tl = new TimelineMax({
      paused: true
    });
    
    function initVariables() {
      containerWidth = container.offsetWidth;
      TweenMax.set(container, {
        position: 'absolute',
        width: 'auto'
      });
      containerMaxWidth = container.offsetWidth;
      TweenMax.set(container, {
        clearProps: 'all'
      });
    }
    
    function initTimeline() {
      tl.to(inner, totalDuration, {
        x: -containerMaxWidth + containerWidth,
        ease: Power0.easeNone
      });
    }
    
    function initListeners() {
      scrollButton.addEventListener('click', doScroll, false);
    }
    
    function doScroll() {
      if (direction === DIRECTION_RIGHT) {
        currProgress = currProgress - progressFactor;
      } else {
        currProgress = currProgress + progressFactor;
      }
    
      if (currProgress >= 1) {
        currProgress = 1;
        direction = DIRECTION_RIGHT;
      } else if (currProgress <= 0) {
        currProgress = 0;
        direction = DIRECTION_LEFT;
      }
    
      TweenMax.to(tl, duration, {
        progress: currProgress,
        ease: ease
      });
    }
    
    //
    initVariables();
    initTimeline();
    initListeners();
    .container {
      width: 400px;
      border: 1px solid green;
      overflow: hidden;
    }
    .inner {
      white-space: nowrap;
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
    <div class="container">
      <div class="inner">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sed, magnam. Ut sunt nihil quo reprehenderit in voluptas voluptatum at tempore accusamus suscipit ipsam ea atque, unde, itaque quas pariatur architecto.
      </div>
    </div>
    <p>
      <span id="scroll">Scroll</span>
    </p>

    Basically, here is what is happening here:

    • Your container element's width is stored in a variable called containerWidth.
    • It then is temporarily set to a position: absolute along with its width: auto.
    • The new width of this container element is stored as containerMaxWidth.
    • The temporarily styles are immediately removed right after using TweenMax's clearProps: 'all' setting.
    • A TimelineMax named tl is created which has a defined motion from x: 0 to the maximum position it can scroll to which in this case is -containerMaxWidth + containerWidth and this timeline is initially set to paused.
    • A direction variable is indirectly used to update progress of our TimelineMax instance.
    • currProgress is directly used to update progress of our TimelineMax instance.
    • This currProgress gets calculated based on the direction determined above.
    • Finally, a tween updates our tl instance's progress property.

    Here is a codepen result of the above.