Skip to content

Instantly share code, notes, and snippets.

@rage-shadowman
Forked from remy/gist:2484402
Last active December 15, 2015 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rage-shadowman/5323437 to your computer and use it in GitHub Desktop.
Save rage-shadowman/5323437 to your computer and use it in GitHub Desktop.
Updated jQuery marquee plugin by Remy Sharp to handle window resize events. This has been tested only on horizontal right-to-left scrolling text. Theoretically it should work for vertical scrolling and left-to-right, but I have no use for that so I have not tested that behavior.
/**
* author Remy Sharp
* url http://remysharp.com/tag/marquee
*
* Ralph Jennings. 4/5/2013.
* Added support for "resize" event. If triggered, marquee is resized according to
* its parent's width and scroll position is updated accordingly.
*/
(function ($) {
$.fn.marquee = function (klass) {
var newMarquee = [],
last = this.length;
function resizeMarqueeRedux ( marqueeRedux ) {
var $marqueeRedux = $( marqueeRedux ),
state = $marqueeRedux.data('marqueeState' ),
$parent = $( marqueeRedux.parentElement ),
horizontal = /scrollWidth/.test(state.widthAxis ),
origStateWidth = state.width,
newStateWidth = horizontal ? $parent.width() : $parent.height();
// resize the widget
if (horizontal) {
$marqueeRedux.width(newStateWidth);
$marqueeRedux.find('> div').css('padding', '0 ' + newStateWidth + 'px');
state.width = newStateWidth;
} else {
$marqueeRedux.height(newStateWidth);
$marqueeRedux.find('> div').css('padding', newStateWidth + 'px 0');
state.width = newStateWidth;
}
// update the scroll amount so the text doesn't jump all over the place (stays in the same relative position top-left)
state.last += (newStateWidth - origStateWidth);
marqueeRedux[state.axis] = state.last;
}
// 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(),
$marqueeRedux = $marquee.after('<div ' + (klass ? 'class="' + klass + '" ' : '') + 'style="display: block-inline; width: ' + width + 'px; height: ' + height + 'px; 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 ' + width + 'px');
} else {
$marqueeRedux.find('> div').css('padding', height + 'px 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);
}).bind('resize', function () {
resizeMarqueeRedux(marqueeRedux);
}).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);
};
}(jQuery));
Copy link

ghost commented Apr 2, 2015

I'm sorry, but I'm trying to get your resize addition to work. Affortunately I'm not that gifted with jQuery, so I can't get it to work. Could you be so kind to help me out?

I currently have the following, to start the marquee:

$(document).ready(function()
{
$('.twitter-marquee marquee').marquee()
.mouseover(function () {
$(this).trigger('stop');
})
.mouseout(function () {
$(this).trigger('start');
});
});

And for the Resize part:
$(window).resize(function()
{
$('.twitter-marquee marquee').marquee().resize(function () { $(this).trigger('stop'); });
});

@HuanxinHu
Copy link

Hi, I used your updated marquee plugin, but it seems do not work if I resize the window, the text will start to scroll from it's original position, not from the right most.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment