2

I'm looking to implement scrolling functionality like the Google Inbox landing page has:

Notably, no matter how fast or how many times you scroll the wheel, it will count as "one" and go to the next step. This seems easier said than done since there's no way to cancel "scroll" event. There is a way to cancel DOMMouseScroll & mousewheel events however doing so is tricky:

The problem is the way cancelling these events works is like below using return preventFn(ev):

   var preventFn = function (ev) {
      ev.returnValue = false;
      return false;
   };

Try it here

However doing so causes scrollTop() action to break. But without it, the scroll event passes through and messes it up also.

I can do better with a rather buggy implementation using a timeout (see fiddle). It works alright but has major bug being everything permanently breaks if the user scrolls WHILE the scrollTop() animation is happening.

How can I correct this so it's as awesome as Google did? (and preferably without a timeout. In the Google page, going from 3rd to 4th step ... I cannot even perceive any timeout, it seems to scroll immediately as my mousewheel starts moving. so it seems possible)

parliament
  • 21,544
  • 38
  • 148
  • 238

3 Answers3

3

Seems the solution implies to use anchors and timeout. Inspired by this post
I've updated your plunkr. Here is a link: http://plnkr.co/edit/GDdm7Z4OEzfh7ZwnQce7?p=preview

    app.directive('autoScroll', function($document, $timeout) {
    return {
        restrict: 'AE',
        link: function(scope, elem, attrs) {
            var delay = false;
            $document.on('mousewheel DOMMouseScroll', function(e) {
                e.preventDefault();
                if (delay) return;

                delay = true;
                $timeout(function() {
                    delay = false
                }, 100)

                var wd = e.originalEvent.wheelDelta || -e.originalEvent.detail;

                var a = angular.element('a');
                if (wd < 0) {
                    for (var i = 0; i < a.length; i++) {
                        var t = a[i].getClientRects()[0].top;
                        if (t >= 40) break;
                    }
                } else {
                    for (var i = a.length - 1; i >= 0; i--) {
                        var t = a[i].getClientRects()[0].top;
                        if (t < -20) break;
                    }
                }
                angular.element('html,body').animate({
                    scrollTop: a[i].offsetTop
                }, 500);
            });
        }
    }
});
Community
  • 1
  • 1
thisninja
  • 56
  • 1
  • 1
  • 5
  • hey how would I go about getting touch support in there also? I would definitely reward a bounty in 2 days if you added that – parliament Dec 15 '14 at 06:50
  • 1
    I have been playing around a little bit with code (it works, but not as expected; i've been testing it with dev tools using mobile emulation mode). Here is the [fiddle](http://jsfiddle.net/jym69crw/) example (Unfortunately, at the moment plunkr is not working). You could try to improve it. Also i will be able to return to example today after 6 pm (GMT +2) – thisninja Dec 16 '14 at 04:22
0

If you want to create a similar site, I would recommend you to use fullPage.js if you haven't tried it yet.

About the timeout problem, it is not so simple to deal with it. Mac OS X devices and Apple trackpads or the Magic Mouse has quite a big inertia and the scroll event is being recorded even 1 second after you have stopped scrolling.

I will try the Google site in a Mac to see how it reacts but meanwhile I would suggest you to read the closer I found to solve the problem: stopping mousewheel event from happening twice in OSX

Community
  • 1
  • 1
Alvaro
  • 40,778
  • 30
  • 164
  • 336
0

using plain jquery: Html:

   <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js">      </script>
<body>
 <main> 
    <div class="contslide">Liza1</div>
    <div class="contslide">Liza2</div>
    <div class="contslide">Liza3</div>
    <div class="contslide">Liza4</div>
    <div class="contslide">Liza5</div>
 </main>
 </body>

css :

  body{width:100%;height:100%;  overflow:hidden; margin:0px;}
  main{ position:absolute; width:100%;  height:100%;  font:20pt verdana;} 
  main div{width:100%;  height:100%; }
  main div:nth-child(odd) {background: #ff0000;}

jquery:

  $(document).ready(function () {
  var delay = false;
  $(document).on('mousewheel DOMMouseScroll', function(event) {
    event.preventDefault();
    if(delay) return;

    delay = true;
    setTimeout(function(){delay = false},200)

    var wd = event.originalEvent.wheelDelta || -event.originalEvent.detail;

    var a= document.getElementsByClassName('contslide');
    if(wd < 0) {
      for(var i = 0 ; i < a.length ; i++) {
        var t = a[i].getClientRects()[0].top;
        if(t >= 40) break;
      }
    }
    else {
      for(var i = a.length-1 ; i >= 0 ; i--) {
        var t = a[i].getClientRects()[0].top;
        if(t < -20) break;
      }
    }
   $('html, body').animate({
    scrollTop: a[i].offsetTop
   });
   });
  });

Here is the fiddle example

liza
  • 3,687
  • 3
  • 16
  • 18