Sticky Scroll

A scrolling container with panels that snap to view when scrolled. This is meant to work alongside native inertial scrolling as seen in mobile devices.

by Kyle Falconer

HTML

<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
<div id="wrapper">
    <div id="container">
      <div><p>0</p></div>
      <div><p>1</p></div>
      <div><p>2</p></div>
      <div><p>3</p></div>
      <div><p>4</p></div>
      <div><p>5</p></div>
      <div><p>6</p></div>
      <div><p>7</p></div>
      <div><p>8</p></div>
      <div><p>9</p></div>
    </div>
</div>
<div id="status_scroll"></div>
<div id="status_touch"></div>
    
<script>
    function main() {
    //window.console.clear();    
        window.console.log('main');
        var p = new PanelView();
        p.init(document.getElementById('container'));
   
        // p.scrollToPanel(4);
    }
    main();
</script>

CSS

body {
    background: #ddd; 
    }

#wrapper{
    position:absolute;
    top:0;
    left:0;
    width: 100%;
    height: 100%;
    overflow-x:scroll;
    overflow-y:hidden;
}

#container {
    height:100%;
    width: 100%;
}

#container > div {
    /*width: 397px;
    height: 390px;*/
    background-color:#dddddd;
    height: 100%;
    border: .5px solid #ff0000;
    float: left;
}

#container > div p{
    font-size:150px;  
    color:#383838;
    margin-left:auto;
    margin-right:auto;
    height:150px;
    width:120px;
    margin-top:40%;
    margin-bottom:40%
}


    

#status_scroll, #status_touch {
    position: fixed;
    display:block;
    height:100px;
    width:200px;
    font-size:20px;
    color:#3859AC;
}

    #status_scroll{top:20px;
left:100px;}
    
    #status_touch{top:20px;
left:400px;}

JavaScript

goog.require('goog.dom');
goog.require('goog.fx');
goog.require('goog.fx.dom');
goog.require('goog.fx.easing');
goog.require('goog.style');
goog.require('goog.events');

var PanelView = function() {};

PanelView.prototype.init = function(container) {
    this.container = container;
    this.wrapper = container.parentElement;
    this.notTouching = true;
    this.stopTheWorld = false;

    this.status_scroll = document.getElementById('status_scroll');
    this.status_touch = document.getElementById('status_touch');



    this.panels = goog.dom.getChildren(container);
    this.numPanels = this.panels.length;
    this.wrapper.style.width = ((this.numPanels) * 100) + '%';
    this.panelWidth_pct = 1 / (this.panels.length);

    for (var i = 0; i < this.numPanels; i++) {
        this.panels[i].style.width = this.panelWidth_pct * 100 + '%';
    };

    this.TotalWidth = goog.style.getSize(this.container).width;
    this.panelWidth_px = Math.floor(this.panelWidth_pct * this.TotalWidth);

    var self = this;
    this.scrollingTimeout = null;
    this.scrollingCallback = null;

    this.OldScrollX = 0;

    goog.events.listen(window, ['mousedown', 'touchstart'], function(evt) {
        self.status_touch.innerHTML = 'TOUCHSTART';
        self.status_scroll.innerHTML = '';
        self.notTouching = false;
    }, true);

    goog.events.listen(window, ['mouseup', 'touchend', 'touchcancel'], function(evt) {
        self.status_touch.innerHTML = '';
        self.notTouching = true;
        self.scrollingTimeout = setTimeout(function() {
            self.snapToNearest();
        }, 75);
    }, true);

    goog.events.listen(window, 'scroll', function(evt) {
        if (self.stopTheWorld || !self.notTouching) {
            if (self.scrollingTimeout) {
                clearTimeout(self.scrollingTimeout);
            }
            return;
        }

        var dScroll = Math.abs(window.scrollX - self.OldScrollX);
        self.status_scroll.innerHTML += '<br/>SCROLLING :' +...