Animated Progress Bars Using MooTools: dwProgressBar

Written by David Walsh on Monday, July 7, 2008


This article may feature code that is no longer best practice in MooTools.
Click here to learn what has changed to make your code framework-compatible.

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!


Epic Discussion

Commenter Avatar July 07 / #
Umut says:

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

Thanks.

Commenter Avatar July 07 / #
Tom says:

Good job! I will adapt it quickly for jquery

Commenter Avatar July 08 / #

Cool!
thats a great job

Commenter Avatar July 08 / #
Gio says:

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

Commenter Avatar July 11 / #
Richard says:

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

Commenter Avatar July 28 / #
Sunil Shrestha says:

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

Commenter Avatar October 28 / #
Samuel says:

I really like this but have little clue how to put this into my page, what would be good (you might roll your eyes at this suggestion), would be to provide a simple field where you enter your webpage and it scans the code and just spits out a new version with everything added in.

I’m completely naff at coding so even though our layout is clean I don’t know where to c&p stuff, the XHTML? where does that go, in the header??

Commenter Avatar November 25 / #
Pieter says:

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

Commenter Avatar January 05 / #
Christian says:

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?

David Walsh January 05 / #
david says:

@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.

Commenter Avatar January 27 / #
Storeman says:

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);
}

});

Commenter Avatar January 27 / #
Storeman says:

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!

Commenter Avatar January 27 / #
Kaoul says:

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.

Commenter Avatar February 06 / #
Max says:

Hey David,

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

Thanks in advance.

David Walsh February 06 / #
david says:

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

Commenter Avatar February 08 / #

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

Commenter Avatar April 01 / #
owen says:

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
:-)

Commenter Avatar April 06 / #
BobMac says:

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

Commenter Avatar July 09 / #
Csaba says:

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

Commenter Avatar August 02 / #

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…

Commenter Avatar August 03 / #

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…

Commenter Avatar September 17 / #
Ty says:

How do I get this script to preload images?

Commenter Avatar October 26 / #
Greg says:

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

Commenter Avatar January 13 / #

Very good job :)
i like it :)

Commenter Avatar January 13 / #

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

Be Heard!

I want to hear what you have to say! Share your comments and questions below.

Name*:
Email*:
Website:  


© David Walsh 2007-2010. Contact David Walsh. Powered by the remarkable MooTools JavaScript framework.