Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
jquery.marquee.js
/**
* author Remy Sharp
* url http://remysharp.com/tag/marquee
*/
(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(),
$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);
}).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));
@ache

This comment has been minimized.

Show comment
Hide comment
@ache

ache Aug 10, 2012

FF 14.0.1 produce following error
Use of getAttributeNode() is deprecated. Use getAttribute() instead. @ jquery-1.7.2.min.js:2
when see $marquee.attr('loop'). FF don't think that 'loop' is attribute, but property, and latest jquery becomes very picky about .attr() vs. .prop(). usage. The fix is to change two $marquee.attr('loop') in the code to $marquee.prop('loop').

ache commented Aug 10, 2012

FF 14.0.1 produce following error
Use of getAttributeNode() is deprecated. Use getAttribute() instead. @ jquery-1.7.2.min.js:2
when see $marquee.attr('loop'). FF don't think that 'loop' is attribute, but property, and latest jquery becomes very picky about .attr() vs. .prop(). usage. The fix is to change two $marquee.attr('loop') in the code to $marquee.prop('loop').

@slovette2

This comment has been minimized.

Show comment
Hide comment
@slovette2

slovette2 Jan 9, 2013

WHere is the reference to the FOSS license for this java script?

WHere is the reference to the FOSS license for this java script?

@aamirafridi

This comment has been minimized.

Show comment
Hide comment
@kirokuan

This comment has been minimized.

Show comment
Hide comment
@kirokuan

kirokuan Aug 7, 2013

I try the plugin with id name and some data-binding value,the plugin generate the new element and cause the original style gone

kirokuan commented Aug 7, 2013

I try the plugin with id name and some data-binding value,the plugin generate the new element and cause the original style gone

@floatplane

This comment has been minimized.

Show comment
Hide comment
@floatplane

floatplane Aug 13, 2013

Thanks for this! I tweaked it slightly to support % width and height on the marquee element: https://gist.github.com/floatplane/6226786

Thanks for this! I tweaked it slightly to support % width and height on the marquee element: https://gist.github.com/floatplane/6226786

@JoeyMobileDev

This comment has been minimized.

Show comment
Hide comment
@JoeyMobileDev

JoeyMobileDev Nov 5, 2013

Isn't it display: inline-block instead of display: block-inline?

Isn't it display: inline-block instead of display: block-inline?

@Deks986

This comment has been minimized.

Show comment
Hide comment
@Deks986

Deks986 Jan 30, 2014

Hi! How can I change gap between elements. Example: I have 2 elements in row and I wanna let the first act like 3rd. So first go automatically after 2nd without waiting till everything finish?

Thanks

Deks986 commented Jan 30, 2014

Hi! How can I change gap between elements. Example: I have 2 elements in row and I wanna let the first act like 3rd. So first go automatically after 2nd without waiting till everything finish?

Thanks

@yoopernc

This comment has been minimized.

Show comment
Hide comment
@yoopernc

yoopernc Aug 1, 2014

I'm using this gistfile to smooth out my marquees, and it's working great!

What's needed to be able to handle the "onfinish" event? Thanks!

yoopernc commented Aug 1, 2014

I'm using this gistfile to smooth out my marquees, and it's working great!

What's needed to be able to handle the "onfinish" event? Thanks!

@HuanxinHu

This comment has been minimized.

Show comment
Hide comment
@HuanxinHu

HuanxinHu Apr 30, 2015

Hi!, the plugin is so cool, but there is a bug, the marquee is not responsive if the window width is changed. Could you solve this bug?

Hi!, the plugin is so cool, but there is a bug, the marquee is not responsive if the window width is changed. Could you solve this bug?

@parallaxinfotech

This comment has been minimized.

Show comment
Hide comment
@parallaxinfotech

parallaxinfotech Sep 22, 2015

@HuanxinHu
I just found myself looking for a solution to the same thing. I have a feeling a custom jquery function will have to be implemented to resize and change the padding.

@HuanxinHu
I just found myself looking for a solution to the same thing. I have a feeling a custom jquery function will have to be implemented to resize and change the padding.

@parallaxinfotech

This comment has been minimized.

Show comment
Hide comment
@parallaxinfotech

parallaxinfotech Sep 22, 2015

I have found a bug in this code. On line 100, you see the style "display: block-inline;". That is actually backwards. It should be "display: inline-block;"

I have found a bug in this code. On line 100, you see the style "display: block-inline;". That is actually backwards. It should be "display: inline-block;"

@koppor

This comment has been minimized.

Show comment
Hide comment

koppor commented Jul 18, 2016

@aamirafridi - the updated URL is https://github.com/aamirafridi/jQuery.Marquee - currently 360 stars.

Even with CSS3, you still need to calculate the speed.

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