Animated Progress Bars Using MooTools: dwProgressBar

By  on  

I love progress bars. It's important that I know roughly what percentage of a task is complete. I've created a highly customizable MooTools progress bar class that animates to the desired percentage.

The Moo-Generated XHTML

	<div id="this.options.boxID">
		<div id="this.options.percentageID"></div>
	</div>
	<div id="this.options.displayID">{x}%</div>

This DIV structure is extremely simple and can be controlled completely by CSS.

The CSS

	/* these selector names are based on what you provide to the class */
	
	/* example 1 */
	#box			{ border:1px solid #ccc; width:200px; height:20px; }
	#perc			{ background:#ccc; height:20px; }
	
	/* example 2 */
	#box2			{ background:url(progress-bar-back.gif) right center no-repeat; width:200px; height:20px; float:left; }
	#perc2			{ background:url(progress-bar.gif) right center no-repeat; height:20px; }
	#text			{ font-family:tahoma, arial, sans-serif; font-size:11px; color:#000; float:left; padding:3px 0 0 10px; }
	

You'll declare styles for the three generated XHTML elements. You'll like use background colors and background images. You will also want to define a width value for the outside box.

The MooTools JavaScript: dwProgressBar

//class is in
var dwProgressBar = new Class({
	
	//implements
	Implements: [Options],

	//options
	options: {
		container: $$('body')[0],
		boxID:'',
		percentageID:'',
		displayID:'',
		startPercentage: 0,
		displayText: false,
		speed:10
	},
	
	//initialization
	initialize: function(options) {
		//set options
		this.setOptions(options);
		//create elements
		this.createElements();
	},
	
	//creates the box and percentage elements
	createElements: function() {
		var box = new Element('div', { id:this.options.boxID });
		var perc = new Element('div', { id:this.options.percentageID, 'style':'width:0px;' });
		perc.inject(box);
		box.inject(this.options.container);
		if(this.options.displayText) { 
			var text = new Element('div', { id:this.options.displayID });
			text.inject(this.options.container);
		}
		this.set(this.options.startPercentage);
	},
	
	//calculates width in pixels from percentage
	calculate: function(percentage) {
		return ($(this.options.boxID).getStyle('width').replace('px','') * (percentage / 100)).toInt();
	},
	
	//animates the change in percentage
	animate: function(to) {
		$(this.options.percentageID).set('morph', { duration: this.options.speed, link:'cancel' }).morph({width:this.calculate(to.toInt())});
		if(this.options.displayText) { 
			$(this.options.displayID).set('text', to.toInt() + '%'); 
		}
	},
	
	//sets the percentage from its current state to desired percentage
	set: function(to) {
		this.animate(to);
	}
	
});

The class accepts the following options:

  • container: element that the entire progress bar gets placed in
  • boxID: the IDof the progress bar's containing DIV
  • percentageID: the ID of the progress bar's animated/sliding DIV
  • displayID: the ID of the progress bar's "{x} %" text DIV
  • startPercentage: the percentage at which you'd like the progress bar to start at (defaults to 0)
  • displayText: Boolean. Do you want the progress bar to show the percentage in text format too?
  • speed: speed of the animation to the given percentage

 

MooTools Usage

//once the DOM is ready
window.addEvent('domready', function() {
	
	/* create the progress bar for example 1 */
	pb = new dwProgressBar({
		container: $('put-bar-here'),
		startPercentage: 25,
		speed:1000,
		boxID: 'box',
		percentageID: 'perc'
	});
		
	/* create the progress bar for example 2 */
	pb2 = new dwProgressBar({
		container: $('put-bar-here2'),
		startPercentage: 10,
		speed:1000,
		boxID: 'box2',
		percentageID: 'perc2',
		displayID: 'text',
		displayText: true
	});
	
	/* move the first progress bar to 55% */
	pb.set(55);
	
	/* move the second progress bar to 89% */
	pb2.set(89);
		
});

All you need to do is create an instance of the dwProgressBar and pass your desired options. It's quick and easy. To move the progress bar, all you need to do is call the "set()" method, passing it the desired percentage.

Practical Uses

You could use this progress bar for:

  • An image preloading script
  • Form completion tracking
  • Internal goal tracking applications
  • Anything you want!

 

I've made the progress bar as flexible as possible by allowing the developer to format each generated DIV using CSS.

Also, please feel free to make suggestions for the class. I may implement them in the future!

Recent Features

  • By
    CSS @supports

    Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS.  What we end up doing is repeating the same properties multiple times with each browser prefix.  Yuck.  Another thing we...

  • By
    Create Namespaced Classes with MooTools

    MooTools has always gotten a bit of grief for not inherently using and standardizing namespaced-based JavaScript classes like the Dojo Toolkit does.  Many developers create their classes as globals which is generally frowned up.  I mostly disagree with that stance, but each to their own.  In any event...

Incredible Demos

Discussion

  1. Looks definitely great & I’ll be sharing this with WebResourcesDepot readers in a very short time.

    Thanks.

  2. Good job! I will adapt it quickly for jquery

  3. Cool!
    thats a great job

  4. Great! I’ll use it as soon as possible.

  5. Great Resource! You’ve been showcased on RichardCastera.com

  6. Sunil Shrestha

    Great Codes! I’ll use it as soon as possible.

  7. Pieter

    Added this to my delicious, thank you very much.
    May be using this :)

  8. Christian

    hi, nice script but it doesn’t work with the 1.11 libary! have you a idee to customize the script for the 1.11?

  9. @Christian: The problem is likely due to the fact that Moo 1.1 didn’t use the “set()” functionality. You’ll need to go back and look at the 1.1 docs.

  10. Storeman

    Nice job!

    I would recommend some enhancements, instead of ID’s I would recommend using classnames. So multiple instances can be created. The elements can be stored inside the class. I also used a template for displaying and added message-support. Not such a big difference, but I thought I should share ;).

    /*
        Class:      dwProgress bar
        Author:     David Walsh / Edited by Storeman
        Website:    http://davidwalsh.name
        Version:    1.1b
        Date:       27/01/2009
        Built For:  MooTools 1.2.1
    */
    
    //class is in
    var dwProgressBar = new Class({
    
        box: null,
        perc: null,
        display:null,
        msg: null,
    
        //implements
        Implements: [Options],
    
        //options
        options: {
            container: $$('body')[0],
            boxClass:'',
            percentageClass:'',
            displayClass:'',
            startPercentage: 0,
            displayText: false,
            speed:10,
            template: '{x}% {msg}'
        },
    
        //initialization
        initialize: function(options) {
            //set options
            this.setOptions(options);
            //create elements
            this.createElements();
        },
    
        //creates the box and percentage elements
        createElements: function() {
            this.box = new Element('div', { class:this.options.boxClass });
            this.perc = new Element('div', { class:this.options.percentageClass, 'style':'width:0px;' });
            this.perc.inject( this.box );
            this.box.inject(this.options.container);
    
            if(this.options.displayText) { 
                this.display = new Element('div', { class:this.options.displayClass });
                this.display.inject(this.options.container);
            }
    
            this.set(this.options.startPercentage);
        },
    
        //calculates width in pixels from percentage
        calculate: function(percentage) {
            return (this.box.getStyle('width').toInt() * (percentage / 100)).toInt();
        },
    
        //animates the change in percentage
        animate: function(to) {
            this.perc.set('morph', { duration: this.options.speed, link:'cancel' }).morph({width:this.calculate(to.toInt())});
            if(this.options.displayText) { 
                text = this.options.template.replace('{x}', to.toInt() ).replace('{msg}', this.msg );
                this.display.set('text', text ); 
            }
        },
    
        //sets the percentage from its current state to desired percentage
        set: function(to, msg) {
            if( !msg ) this.msg = '';
            else this.msg = msg;
    
            this.animate(to);
        }
    
    });
    
  11. Storeman

    I’m sorry for posting again, I’m using it with Zend Framework (Zend_Progressbar)

    PHP – The Action:

    public function demoAction(){
    $this->_helper->viewRenderer->setNoRender(true);
    $this->view->layout()->disableLayout( true );
    
    $pb = new Zend_ProgressBar( new Zend_ProgressBar_Adapter_JsPush(array(
    
    ))  );
    
    for( $i=0; $i<10; $i++){
        $pb->next( 10, 'Ronde ' . $i );
        sleep(1);
    }
    
    
    }
    
    PHP - The View:
    
    <?php ob_start(); ?>
    <h2>Progressbar - demo</h2>
    
    <div id="pbContainer">
    </div>
    <iframe src="<?=$this->url( array_merge($this->params, array('action'=>'demo') ) )?>" style="left:-100px; top:-100px; width:1px; height:1px; position:absolute">
    </iframe>
    <?php
    $this->layout()->mainContent = ob_get_clean();
    
    
    $this->layout()->setLayout('default');
    $this->layout()->menu = $this->layout()->render('adminmenu');
    
    $this->headScript()->appendFile( $this->url->js . '/progressbar.js' );
    $this->headScript()->captureStart()?>
    
    var pb;
    window.addEvent('domready', function(){
        pb = new dwProgressBar({
            container: $('pbContainer'),
            boxClass: 'progress_box',
            percentageClass: 'progress_percentage',
            displayClass: 'progress_display',
            startPercentage: 0,
            speed: 1000,
            displayText: true
        });
    });
    
    function Zend_ProgressBar_Update(data){
        pb.set( data.percent, data.text );
    }
    
    <?php $this->headScript()->captureEnd();
    

    Some stuff I just personal, but it’ll get everyone started, note that the view belongs to another action!

  12. In your class, in function createElements, I added :

    if ($("text")) $("text").dispose();
    

    Because when you have a succession of progressBars, the last text is not cleared and you have multiple XHTML elements with the same id brrrr.
    With something like this, the css stay on the road and DOM is respected.

  13. Max

    Hey David,

    what’s the licence of these progress bar? Can I use it for commercial websites?

    Thanks in advance.

  14. MIT. Use it however and wherever you’d like.

  15. Hello,

    Thought you might be interested to see a website where your component is used or maybe give it a review or something. I made a forex prices and trend analysis tool that you can see at http://www.forex-prices.com/

    Have a nice day, Ruslan

  16. Hi,
    Is there any way to create a nice looking percentage bar to preload all images / content on a HTML page, and then show that page once everything is cached?

    You seem to know what you’re talking about, whereas I don’t
    :-)

  17. BobMac

    I’m trying to pass the output of this php variable $progress to your script and not having any luck. Any ideas?

  18. Great sample code and as David said you can use it wherever you want . Cool

  19. Excellent job. Easy to use. I was wracking my brains what to do on my initial load of my webapp. Your progress bar fitted in without any problems. Using Mootools 1.2.1 and jQuery.

    Cheers

    Pete…

  20. I added a text header that I called ‘pretext’ which appears above the progress bar:

    So the options object looks like this:

    options: {
        container: $$('body')[0],
        boxID:'',
        percentageID:'',
        displayID:'',
        textID:'',
        startPercentage: 0,
        displayText: false,
        speed:10,
        pretext:""
    }
    

    CreateElements looks like this:

    //creates the box and percentage elements
    createElements: function() {
        var tbox = new Element('div', { id: this.options.textID, 'style':'display:inline;float:left' });
        tbox.innerHTML = this.options.pretext;
        var box = new Element('div', { id:this.options.boxID });
        var perc = new Element('div', { id:this.options.percentageID, 'style':'width:0px' });
        perc.inject(box);
        tbox.inject(this.options.container);
        box.inject(this.options.container);
        if(this.options.displayText) { 
            var text = new Element('span', { id:this.options.displayID });
            text.inject(this.options.container);
        }
        this.set(this.options.startPercentage);
    },
    

    Note that I added the ‘tbox’ Element

    I like your component but I don’t like MooTools. It is so unintuitive. The ‘inject’ method is from some upside down world – possibly the Mr Men.

    Cheers

    Pete…

  21. How do I get this script to preload images?

  22. I apologize if this was answered before.
    Can anyone help me implement the preloader for a webpage. Thanks in advance.

  23. Very good job :)
    i like it :)

  24. I think i’m going to use into my blog too
    Thanks for sharing

  25. Francois

    I was looking for a progressbar script and I landed on your website. Nice website! Think I am adding it to my bookmarks. But before I do this… ;-)

    Can you please explain how you render these GoogleWebfonts anti aliasing? I have not found a solution to this.

    Thanx in advance!

  26. Great job, it works perfectly.

    Thank you! :-)

  27. and what I need to write in body to get this work??
    I cope paste The MooTools JavaScript: dwProgressBar and copy paste css and MooTools Usage, put all this before head tag, also put the images, link to jquery and its not work for me?? Also can this go to another page when the countdown ends?

  28. Alexei

    Great class, but it misses feature to set look of progress bar elements through CSS classes, rather than IDs. I have several dynamically generated progress bars on my page, so creating CSS for each progress bar is inadequate. Instead, I modified your class to support CSS classes as well. It is useful feature and easy to implement.

  29. no need for js, now with css3 translations and animations, you can have a smooth and good looking progress bars, i tried this one http://www.codicode.com/art/pure_css_progress_bar_animated_by_css3.aspx and i like it.
    the only problem is ie9,8…

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!