2
\$\begingroup\$

I have tried using jQuery to create an alternative of marquee, and got no success. It flickers and does not stop on hover. I edited and edited again and it finally came out with a jQuery + JavaScript mess.

JavaScript:

$(document).ready(function(){  
        marquee();
        var timeout=1;
        function marquee(){
            var margin= -($('#mydiv > div:eq(0)').outerHeight()+ 20);
            $('#mydiv > div:eq(0)').animate({'margin-top': margin+'px'},4000,function(){
                $('#mydiv > div:eq(2)').html($(this).html());
                $(this).html('').css({'margin-top':'0px'}).appendTo($('#mydiv'));
                loop();
            });
        }
        function loop(){     
            if(timeout)
            setTimeout(marquee,0); 
        }
        $('#mydiv').hover(function(){
                timeout = 0;
                $('#mydiv > div:eq(0)').stop(true);
        },function(){
                timeout = 1;
                marquee();
        });
    });

Markup:

    <div id='mydiv' style='width:300px;height:300px;overflow:hidden'> 
    <div id='div1'>
        <h4> Advantages:</h4><br>
        <ul>
         <li>blah 1</li>
                 <li>blah 2</li>
                 <li>blah 3</li>
        </ul> 
    </div>
    <div id='div2'>
        <h4>Applications:</h4><br>
        <ul>
         <li>blah 1</li>
                 <li>blah 2</li>
                 <li>blah 3</li>
        </ul>
    </div>  
    <div id='div3'></div>

</div>
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I wouldn't recommend to put a marquee on a page unless you want to make harder for the user to notice your whole page and not just the marquee, also some users find marquees annoying. \$\endgroup\$
    – jclozano
    Commented Dec 27, 2011 at 17:57
  • \$\begingroup\$ I just created a jQuery plugin. Try this. github.com/aamirafridi/jQuery.Marquee \$\endgroup\$ Commented Jan 11, 2013 at 15:07

2 Answers 2

3
\$\begingroup\$

A few points:

  • $(this).html('') will throw away the contents of #div1 (on the first iteration) and #div2 (on the second iteration). If you want the marquee to loop, that's not going to work.
  • This is a perfect use case for a simple jQuery plugin (see the documentation).
  • You should probably use next() instead of the eq selector, to make your code work with any number of children (or at least any number above 1).
  • To stop the animations on hover, you'll have to call stop() on any elements that may be half-way into an animation. Pausing and continuing the marquee would be good use cases for plugin methods.
  • You could consider using the position and top attributes to position the children; this is exactly what position: absolute is for.

Given below is an example of a simple plugin that does roughly what you want. To keep in theme with this site, I've stuck with your approach -- animation is done on margin-top and, as you can see, only the first child is animated.

Because of this, the marquee won't loop until all children are outside the parent div. To make it wrap sooner, I would advise rewriting the plugin to use position: absolute and the top attribute on each child. That way, each child can be idependently animated and the marquee can be looped earlier.

Finally, keep in mind that this example is far from perfect. For example, the total height of the children is re-calculated on each run. The plugin could be made more efficient simply by maintaining state.

Plugin:

(function($) {

    var methods = {
        init: function(options) {
            this.children(':first').stop();
            this.marquee('play');
        },
        play: function() {
            var marquee = this,
                pixelsPerSecond = 100,
                firstChild = this.children(':first'),
                totalHeight = 0,
                difference,
                duration;

            // Find the total height of the children by adding each child's height:
            this.children().each(function(index, element) {
                totalHeight += $(element).innerHeight();
            });

            // The distance the divs have to travel to reach -1 * totalHeight:
            difference = totalHeight + parseInt(firstChild.css('margin-top'), 10);

            // The duration of the animation needed to get the correct speed:
            duration = (difference/pixelsPerSecond) * 1000;

            // Animate the first child's margin-top to -1 * totalHeight:
            firstChild.animate(
                { 'margin-top': -1 * totalHeight },
                duration,
                'linear',
                function() {
                    // Move the first child back down (below the container):
                    firstChild.css('margin-top', marquee.innerHeight());
                    // Restart whole process... :)
                    marquee.marquee('play');
                }
            );
        },
        pause: function() {
            this.children(':first').stop();
        }
    };

    $.fn.marquee = function(method) {

        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.marquee');
        }

    };

})(jQuery);

Usage:

var marquee = $('#mydiv');

marquee.marquee();

marquee.hover(function() {
    marquee.marquee('pause');
}, function() {
    marquee.marquee('play');    
});

This example can also be found on jsfiddle: http://jsfiddle.net/PPvG/LgsrU/

\$\endgroup\$
1
  • \$\begingroup\$ superb work. No flickering at all. Thanks for giving time. But this plugin is working exactly like marquee. When all divs finished sliding up. It shows blank for some time and then shows the first div again. I wanted a continuous loop. \$\endgroup\$
    – Jashwant
    Commented Jan 2, 2012 at 9:44
1
\$\begingroup\$

I've been researching the best possible implementations for marquee myself. I indeed was looking for element marquee, rather than text marquee. I finally implemented the code using CSS3 transitions with graceful degradation to scroll animation for the older browsers. The CSS3 transitions, and indeed scroll implementation, is by far more efficient that offsetting elements using margin or any similar implementation.

Even with 4 simultaneous marquee elements on the page, the implementation has virtually no performance impact.

enter image description here

The demo can be seen at https://dev.anuary.com/60244f3a-b8b2-5678-bce5-f7e8742f0c69/. The code is available at https://github.com/gajus/marquee.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.