213 lines
6.9 KiB
JavaScript
213 lines
6.9 KiB
JavaScript
/**
|
|
* 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);
|
|
} |