Skip to content

Instantly share code, notes, and snippets.

@leefish
Forked from eric1234/marquee.coffee
Created November 10, 2012 18:37
Show Gist options
  • Save leefish/4052043 to your computer and use it in GitHub Desktop.
Save leefish/4052043 to your computer and use it in GitHub Desktop.
<marquee> element lives! - Emulating the behavior of the old marquee element with CoffeeScript/JavaScript
class @Marquee
constructor: (@element, @options={}) ->
# Set defaults
@options['duration'] or= 30
@options['wrapAround'] = true unless 'wrapAround' of @options
@options['direction'] or= 'forward'
# If everything fits don't bother with all this mess
return if this.element.scrollWidth == this.element.clientWidth
# Create wrapping container to scroll the marquee in.
# Adapted from Prototype's wrap method.
@container = document.createElement 'div'
@container.className = 'marquee-wrapper'
@element.parentNode.replaceChild @container, @element if @element.parentNode
@container.appendChild @element
# Move some of the relevant marquee styles to this wrapper.
@container.style.width = @element.clientWidth+'px'
@container.style.height = @element.clientHeight+'px'
@container.style.overflow = 'hidden'
# Keep in mind how big it was so we know when to reset
@originalWidth = @element.scrollWidth
# Make it look like it is wrapping around by duping content
if @options.wrapAround
trimmed = element.innerHTML.trim()
@element.innerHTML = trimmed + trimmed + trimmed
# Size restrictions/clipping moved to wrapper, remove from element
@element.style.width = @element.scrollWidth+'px'
@element.style.height = @element.scrollHeight+'px'
@element.style.overflow = 'auto'
@container.scrollLeft = @originalWidth if @options.wrapAround
# Will start the marquee moving.
#
# If no argument is given it will move until it gets to the end of the
# content. If wrapAround is enabled it will reset and do another move to the
# end of the content creating a never-ending scrolling of the content.
#
# If a distance is given then it will only move that far then stop.
move: (distance=null, onFinish=->) ->
ending_position = if distance
if @options.direction is 'forward'
@container.scrollLeft + distance
else
@container.scrollLeft - distance
else
if @options.direction is 'forward'
@container.scrollLeft + @originalWidth
else
@container.scrollLeft - @originalWidth
callback = if @options.wrapAround && !distance
=>
@container.scrollLeft = @originalWidth
onFinish()
Marquee.tween @container, @options.duration, ending_position, callback
else
onFinish
Marquee.tween @container, @options.duration, ending_position, callback
# To actually do the moving we farm this out to a callback. This way the actual
# movement can be handled by a library like morpheus which is designed as a
# single high-performance loop using constant speed animation and the
# requestAnimationFrame standard.
#
# This should be replaced by a function that actually does the work.
Marquee = @Marquee
Marquee.tween = (element, duration, target_scroll, oncomplete) ->
# By default implement a stupid "animation" that just move it without
# any in-between stages.
element.scrollLeft = target_scroll
oncomplete()
# Adapted from
# http://stackoverflow.com/questions/498970/#answer-8522376
unless String::trim
String::trim = -> @replace /^\s+|\s+$/g,''
<!DOCTYPE html>
<html>
<head>
<style>
#test {
font-size: 3em;
width: 10em;
height: 1.5em;
overflow: hidden;
white-space: nowrap;
}
</style>
</head>
<div id="test">
The quick brown fox jumps over the lazy dog
</div>
<script src="marquee.js"></script>
<script src="morpheus.js"></script>
<script>
Marquee.tween = function(element, duration, end, onComplete) {
morpheus.tween(duration*1000, function(position) {
element.scrollLeft = position
}, onComplete, function(p) {return p}, element.scrollLeft, end)
}
marquee = new Marquee(document.getElementById('test'));
marquee.move();
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment