Files
PetitTeton/public/js/scroller.js

213 lines
6.9 KiB
JavaScript
Raw Normal View History

/**
* Creates and starts the item scroller which must receive the ID of the node containing the elements to be scrolled,
* an optional increment size for the scroll (may be zero if auto), and an optional autoscroll time interval (millseconds).
* Transition is the number of milliseconds for the animation of shifting one increment.
* @param viewport The jquery wrapper around the viewport container.
* @param increment The number of pixels to shift. If not defined then it will be pulled from the first child of the page.
* @param autoTimer The number of milliseconds to wait between automatic shifts. If undefined or <= 0 then there won't be any auto shifts.
* @param initialDelay The number of milliseconds to wait before starting automatic shifts, or zero if undefined or less than zero.
* @param transition The number of milliseconds to animate the shifting of the page. Will default to 1000.
* @param resetPosition Whether the scroll position is reset upon releasing the item scroller. This defaults to true.
*/
function ItemScroller(viewport, increment, autoTimer, initialDelay, transition, resetPosition) {
this.viewport = viewport;
this.increment = increment != undefined && increment != 0 ? this.stripMetric(increment) : undefined;
if(resetPosition != undefined) {
this.resetPosition = resetPosition;
}
this.init();
if(autoTimer != undefined) {
this.autoscroll(autoTimer, initialDelay);
}
if(transition != undefined && transition > 0) {
this.transition = transition;
}
}
ItemScroller.prototype.constructor = ItemScroller;
ItemScroller.prototype.viewport = null;
ItemScroller.prototype.page = null;
ItemScroller.prototype.increment = null;
ItemScroller.prototype.pageWidth = null;
ItemScroller.prototype.isShifting = false;
ItemScroller.prototype.autoscrollPause = false;
ItemScroller.prototype.isReleased = false;
ItemScroller.prototype.transition = 1000;
ItemScroller.prototype.copyCount = 0;
ItemScroller.prototype.resetPosition = true;
ItemScroller.prototype.currentIndex = 0;
ItemScroller.prototype.length = 0;
ItemScroller.prototype.init = function() {
this.page = this.viewport.children(':first');
var children = this.page.children();
this.length = children.length;
//Calculate the increment size for each left/right scroll.//
if(this.increment == undefined) {
this.increment = this.stripMetric(children.first().outerWidth());
}
//Calculate the width of the original set of displayed elements.//
var viewportWidth = this.viewport.outerWidth();
var pageWidth = 0;
this.page.children().each(function() {
pageWidth += $(this).outerWidth();
});
this.pageWidth = pageWidth;
//Calculate the wrap size that will be needed on the tail of the original set of elements to simulate a wrap around effect.//
var remainder = this.pageWidth / this.increment != 0 ? this.pageWidth % this.increment : this.increment;
var tailLength = remainder;
//Clone children until we have enough to properly simulate a wrap around scrolling action.//
for(var index = 0; index < children.length && tailLength < viewportWidth; index++) {
var next = $(children[index]);
tailLength += next.outerWidth();
next.clone(true, true).appendTo(this.page);
this.copyCount++;
}
//Now: Fix the spacing the browser adds between inline elements that have any kind of spacing or line feeds between them (bad browsers!).//
children = this.page.children();
this.page.css({position: 'relative'});
var offset = 0;
children.each(function() {
var next = $(this);
next.css({position: 'absolute', left: offset, top: 0, display: 'block'});
offset += next.outerWidth();
});
if(this.resetPosition) {
//Start at the beginning.//
this.viewport.scrollLeft(0);
}
else {
var lastIndex = this.viewport.data('lastIndex');
if(lastIndex) {
this.currentIndex = lastIndex;
this.viewport.parents().css('display', 'block');
this.viewport.scrollLeft(lastIndex * this.increment);
//this.viewport.one('scroll', function() {
// this.viewport.scrollLeft(this.currentIndex * this.increment);
//});
}
else {
this.viewport.scrollLeft(0);
}
}
}
ItemScroller.prototype.release = function() {
//this.page.stop(true, false);
//this.page.css({left: 0});
if(!this.released) {
//Stop the animation.//
this.viewport.stop(true, false);
//Remove the children that were added upon initialization.//
var children = this.page.children();
children.slice(children.length - this.copyCount).detach();
//Flag ourselves as released.//
this.isReleased = true;
if(this.resetPosition) {
//Start at the beginning.//
//this.viewport.scrollLeft(0);
}
this.viewport.data('lastIndex', this.currentIndex);
}
}
ItemScroller.prototype.next = function(fn) {
if(!this.isShifting) {
var pageLeft = this.viewport.scrollLeft();
var newPageLeft = pageLeft + this.increment;
var wrapPosition = this.pageWidth;
var shift = this.pageWidth;
var _this = this;
this.isShifting = true;
//this.viewport.data('nextScrollLeft', newPageLeft);
this.currentIndex = (this.currentIndex + 1) % this.length;
this.viewport.animate({scrollLeft: newPageLeft}, {duration: this.transition, queue: true, step: function(now, fx) {
if(fx.now >= wrapPosition) {
fx.start -= shift;
fx.end -= shift;
fx.now -= shift;
}
}, complete: function() {
_this.isShifting = false;
if(fn) fn();
}});
}
return this;
}
ItemScroller.prototype.prev = function(fn) {
if(!this.isShifting) {
var pageLeft = this.viewport.scrollLeft();
var newPageLeft = pageLeft - this.increment;
var wrapPosition = 0;
var shift = this.pageWidth;
var _this = this;
this.isShifting = true;
this.currentIndex = this.currentIndex - 1 < 0 ? this.length : this.currentIndex - 1;
this.viewport.animate({scrollLeft: newPageLeft}, {duration: this.transition, queue: true, step: function(now, fx) {
if(fx.now <= wrapPosition) {
fx.start += shift;
fx.end += shift;
fx.now += shift;
}
}, complete: function() {_this.isShifting = false; if(fn) fn();}});
}
return this;
}
ItemScroller.prototype.pause = function() {
this.autoscrollPause = true;
return this;
}
ItemScroller.prototype.resume = function() {
this.autoscrollPause = false;
return this;
}
ItemScroller.prototype.autoscroll = function(delay, initialDelay) {
var _this = this;
/* Pause scrolling on mouse over.
this.page.mouseover(function(eventObject) {
_this.autoscrollPause = true;
});
this.page.mouseout(function(eventObject) {
_this.autoscrollPause = false;
});
*/
if(initialDelay == undefined || initialDelay <= 0) {
this.autoscrollIncrement(delay);
}
else {
window.setTimeout(function() {_this.autoscrollIncrement(delay);}, initialDelay);
}
}
ItemScroller.prototype.autoscrollIncrement = function(delay) {
var _this = this;
if(!this.isReleased) {
var fn = function() {
window.setTimeout(function() {_this.autoscrollIncrement(delay);}, delay);
};
if(!this.autoscrollPause) {
this.next(fn);
}
else {
fn();
}
}
}
ItemScroller.prototype.stripMetric = function(value) {
return parseInt(value);
}