Hi,
I modified the plugin for you a little.
Now, you should give all of the sections a class of “window” and remove the class of “noSnap”.
<section class="window" id="one">Section A</section>
<section class="window" id="two">Section B</section>
<section class="window" id="three">Section C</section>
<section class="window" id="four">Section D</section>
<section class="window" id="five">Section E</section>
<section class="window" id="six">Section F</section>
When you initialize the plugin, you can now pass in an option of ignoreLast:
var $win = $('.window');
$win.windows({
snapping: true,
snapSpeed: 500,
snapInterval: 1100,
ignoreLast: true,
onScroll: function(s){},
onSnapComplete: function($el){},
onWindowEnter: function($el){}
});
If this is set to true, the final element in the collection that you call the windows()
method on, will be allowed to scroll as far as it likes past the top of the viewport, without snapping back into position.
I made a new demo to reflect this.
Here’s the code:
<!doctype html>
<html>
<head>
<title>windows</title>
<style>
html, body{
height: 100%;
}
.window{
height:100%;
}
#one{
background-color: red;
}
#two{
background-color: blue;
}
#three{
background-color: yellow;
}
#four{
background-color: green;
}
#five{
background-color: pink;
}
#six{
background-color: #639;
height:3000px;
}
</style>
</head>
<body>
<section class="window" id="one">Section A</section>
<section class="window" id="two">Section B</section>
<section class="window" id="three">Section C</section>
<section class="window" id="four">Section D</section>
<section class="window" id="five">Section E</section>
<section class="window" id="six">Section F</section>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
/*!
* windows: a handy, loosely-coupled jQuery plugin for full-screen scrolling windows.
* Version: 0.0.1
* Original author: @nick-jonas
* Website: http://www.workofjonas.com
* Licensed under the MIT license
*/
;(function ( $, window, document, undefined ) {
var that = this,
pluginName = 'windows',
defaults = {
snapping: true,
snapSpeed: 500,
snapInterval: 1100,
ignoreLast: false,
onScroll: function(){},
onSnapComplete: function(){},
onWindowEnter: function(){}
},
options = {},
$w = $(window),
s = 0, // scroll amount
t = null, // timeout
$windows = [];
/**
* Constructor
* @param {jQuery Object} element main jQuery object
* @param {Object} customOptions options to override defaults
*/
function windows( element, customOptions ) {
this.element = element;
options = options = $.extend( {}, defaults, customOptions) ;
this._defaults = defaults;
this._name = pluginName;
$windows.push(element);
var isOnScreen = $(element).isOnScreen();
$(element).data('onScreen', isOnScreen);
if(isOnScreen) options.onWindowEnter($(element));
}
/**
* Get ratio of element's visibility on screen
* @return {Number} ratio 0-1
*/
$.fn.ratioVisible = function(){
var s = $w.scrollTop();
if(!this.isOnScreen()) return 0;
var curPos = this.offset();
var curTop = curPos.top - s;
var screenHeight = $w.height();
var ratio = (curTop + screenHeight) / screenHeight;
if(ratio > 1) ratio = 1 - (ratio - 1);
return ratio;
};
/**
* Is section currently on screen?
* @return {Boolean}
*/
$.fn.isOnScreen = function(){
var s = $w.scrollTop(),
screenHeight = $w.height(),
curPos = this.offset(),
curTop = curPos.top - s;
return (curTop >= screenHeight || curTop <= -screenHeight) ? false : true;
};
/**
* Get section that is mostly visible on screen
* @return {jQuery el}
*/
var _getCurrentWindow = $.fn.getCurrentWindow = function(){
var maxPerc = 0,
maxElem = $windows[0];
$.each($windows, function(i){
var perc = $(this).ratioVisible();
if(Math.abs(perc) > Math.abs(maxPerc)){
maxElem = $(this);
maxPerc = perc;
}
});
return $(maxElem);
};
// PRIVATE API ----------------------------------------------------------
/**
* Window scroll event handler
* @return null
*/
var _onScroll = function(){
s = $w.scrollTop();
_snapWindow();
options.onScroll(s);
// notify on new window entering
$.each($windows, function(i){
var $this = $(this),
isOnScreen = $this.isOnScreen();
if(isOnScreen){
if(!$this.data('onScreen')) options.onWindowEnter($this);
}
$this.data('onScreen', isOnScreen);
});
};
var _onResize = function(){
_snapWindow();
};
var _snapWindow = function(){
// clear timeout if exists
if(t){clearTimeout(t);}
if(options.ignoreLast){
if ($(document).scrollTop() - $($windows[$windows.length-1]).offset().top > 0){
return false;
}
}
// check for when user has stopped scrolling, & do stuff
if(options.snapping){
t = setTimeout(function(){
var $visibleWindow = _getCurrentWindow(), // visible window
scrollTo = $visibleWindow.offset().top, // top of visible window
completeCalled = false;
// animate to top of visible window
$('html:not(:animated),body:not(:animated)').animate({scrollTop: scrollTo }, options.snapSpeed, function(){
if(!completeCalled){
if(t){clearTimeout(t);}
t = null;
completeCalled = true;
options.onSnapComplete($visibleWindow);
}
});
}, options.snapInterval);
}
};
/**
* A really lightweight plugin wrapper around the constructor,
preventing against multiple instantiations
* @param {Object} options
* @return {jQuery Object}
*/
$.fn[pluginName] = function ( options ) {
$w.scroll(_onScroll);
$w.resize(_onResize);
return this.each(function(i) {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new windows( this, options ));
}
});
};
})( jQuery, window, document );
</script>
<script>
var $win = $('.window');
$win.windows({
snapping: true,
snapSpeed: 500,
snapInterval: 1100,
ignoreLast: true,
onScroll: function(s){},
onSnapComplete: function($el){},
onWindowEnter: function($el){}
});
</script>
</body>
</html>
I removed the .visible()
method entirely (as it was superfluous) and I amended most of the stuff that was querying the DOM.
I did keep $(document).scrollTop()
however, as that could change if the windows gets resized.
I hope this helps.