-
-
Save floatplane/6226786 to your computer and use it in GitHub Desktop.
jquery marquee plugin - forked to support percentage widths on marquee element, AMD wrapped
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* author Remy Sharp | |
* url http://remysharp.com/tag/marquee | |
*/ | |
require(['jquery'], function ($) { | |
$.fn.marquee = function (klass) { | |
var newMarquee = [], | |
last = this.length; | |
// works out the left or right hand reset position, based on scroll | |
// behavior, current direction and new direction | |
function getReset(newDir, marqueeRedux, marqueeState) { | |
var behavior = marqueeState.behavior, width = marqueeState.width, dir = marqueeState.dir; | |
var r = 0; | |
if (behavior == 'alternate') { | |
r = newDir == 1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : width; | |
} else if (behavior == 'slide') { | |
if (newDir == -1) { | |
r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] : width; | |
} else { | |
r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : 0; | |
} | |
} else { | |
r = newDir == -1 ? marqueeRedux[marqueeState.widthAxis] : 0; | |
} | |
return r; | |
} | |
// single "thread" animation | |
function animateMarquee() { | |
var i = newMarquee.length, | |
marqueeRedux = null, | |
$marqueeRedux = null, | |
marqueeState = {}, | |
newMarqueeList = [], | |
hitedge = false; | |
while (i--) { | |
marqueeRedux = newMarquee[i]; | |
$marqueeRedux = $(marqueeRedux); | |
marqueeState = $marqueeRedux.data('marqueeState'); | |
if ($marqueeRedux.data('paused') !== true) { | |
// TODO read scrollamount, dir, behavior, loops and last from data | |
marqueeRedux[marqueeState.axis] += (marqueeState.scrollamount * marqueeState.dir); | |
// only true if it's hit the end | |
hitedge = marqueeState.dir == -1 ? marqueeRedux[marqueeState.axis] <= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState) : marqueeRedux[marqueeState.axis] >= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState); | |
if ((marqueeState.behavior == 'scroll' && marqueeState.last == marqueeRedux[marqueeState.axis]) || (marqueeState.behavior == 'alternate' && hitedge && marqueeState.last != -1) || (marqueeState.behavior == 'slide' && hitedge && marqueeState.last != -1)) { | |
if (marqueeState.behavior == 'alternate') { | |
marqueeState.dir *= -1; // flip | |
} | |
marqueeState.last = -1; | |
$marqueeRedux.trigger('stop'); | |
marqueeState.loops--; | |
if (marqueeState.loops === 0) { | |
if (marqueeState.behavior != 'slide') { | |
marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); | |
} else { | |
// corrects the position | |
marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir * -1, marqueeRedux, marqueeState); | |
} | |
$marqueeRedux.trigger('end'); | |
} else { | |
// keep this marquee going | |
newMarqueeList.push(marqueeRedux); | |
$marqueeRedux.trigger('start'); | |
marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); | |
} | |
} else { | |
newMarqueeList.push(marqueeRedux); | |
} | |
marqueeState.last = marqueeRedux[marqueeState.axis]; | |
// store updated state only if we ran an animation | |
$marqueeRedux.data('marqueeState', marqueeState); | |
} else { | |
// even though it's paused, keep it in the list | |
newMarqueeList.push(marqueeRedux); | |
} | |
} | |
newMarquee = newMarqueeList; | |
if (newMarquee.length) { | |
setTimeout(animateMarquee, 25); | |
} | |
} | |
// TODO consider whether using .html() in the wrapping process could lead to loosing predefined events... | |
this.each(function (i) { | |
var $marquee = $(this), | |
width = $marquee.attr('width') || $marquee.width(), | |
height = $marquee.attr('height') || $marquee.height(), | |
widthWithUnits = (typeof(width) == 'string' ? width : width + 'px'), | |
heightWithUnits = (typeof(height) == 'string' ? height : height + 'px'), | |
$marqueeRedux = $marquee.after('<div ' + (klass ? 'class="' + klass + '" ' : '') + 'style="display: block-inline; width: ' + widthWithUnits + '; height: ' + heightWithUnits + '; overflow: hidden;"><div style="float: left; white-space: nowrap;">' + $marquee.html() + '</div></div>').next(), | |
marqueeRedux = $marqueeRedux.get(0), | |
hitedge = 0, | |
direction = ($marquee.attr('direction') || 'left').toLowerCase(), | |
marqueeState = { | |
dir : /down|right/.test(direction) ? -1 : 1, | |
axis : /left|right/.test(direction) ? 'scrollLeft' : 'scrollTop', | |
widthAxis : /left|right/.test(direction) ? 'scrollWidth' : 'scrollHeight', | |
last : -1, | |
loops : $marquee.attr('loop') || -1, | |
scrollamount : $marquee.attr('scrollamount') || this.scrollAmount || 2, | |
behavior : ($marquee.attr('behavior') || 'scroll').toLowerCase(), | |
width : /left|right/.test(direction) ? width : height | |
}; | |
// corrects a bug in Firefox - the default loops for slide is -1 | |
if ($marquee.attr('loop') == -1 && marqueeState.behavior == 'slide') { | |
marqueeState.loops = 1; | |
} | |
$marquee.remove(); | |
// add padding | |
if (/left|right/.test(direction)) { | |
$marqueeRedux.find('> div').css('padding', '0 ' + widthWithUnits); | |
} else { | |
$marqueeRedux.find('> div').css('padding', heightWithUnits + ' 0'); | |
} | |
// events | |
$marqueeRedux.bind('stop', function () { | |
$marqueeRedux.data('paused', true); | |
}).bind('pause', function () { | |
$marqueeRedux.data('paused', true); | |
}).bind('start', function () { | |
$marqueeRedux.data('paused', false); | |
}).bind('unpause', function () { | |
$marqueeRedux.data('paused', false); | |
}).data('marqueeState', marqueeState); // finally: store the state | |
// todo - rerender event allowing us to do an ajax hit and redraw the marquee | |
newMarquee.push(marqueeRedux); | |
marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); | |
$marqueeRedux.trigger('start'); | |
// on the very last marquee, trigger the animation | |
if (i+1 == last) { | |
animateMarquee(); | |
} | |
}); | |
return $(newMarquee); | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Any thoughts on what would be needed to handle the "onfinish" event? Thanks!