<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Perplexed Labs &#187; progress bar</title>
	<atom:link href="http://blog.perplexedlabs.com/tag/progress-bar/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.perplexedlabs.com</link>
	<description>web development war stories from the frontlines to the backend</description>
	<lastBuildDate>Sat, 24 Jul 2010 16:27:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Real-time &#8220;AJAX&#8221; JavaScript Progress Bar</title>
		<link>http://blog.perplexedlabs.com/2008/11/07/real-time-ajax-javascript-progress-bar/</link>
		<comments>http://blog.perplexedlabs.com/2008/11/07/real-time-ajax-javascript-progress-bar/#comments</comments>
		<pubDate>Fri, 07 Nov 2008 18:05:19 +0000</pubDate>
		<dc:creator>Matt</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[long polling]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[progress bar]]></category>

		<guid isPermaLink="false">http://www.perplexedlabs.com/?p=43</guid>
		<description><![CDATA[I've been developing a stock market screener with some advanced functionality.  Some of the parameters a user might enter, because of their complexity or sheer volume of data required to calculate, would cause the screener to run for considerable amounts of time before returning results.  The opportunity to create a progress bar presented itself.  EVERY [...]


Related posts:<ol><li><a href='http://blog.perplexedlabs.com/2009/05/04/php-jquery-ajax-javascript-long-polling/' rel='bookmark' title='Permanent Link: PHP jQuery AJAX Javascript Long Polling'>PHP jQuery AJAX Javascript Long Polling</a></li>
<li><a href='http://blog.perplexedlabs.com/2009/02/05/dynamic-javascript-script-insertion-for-embedding/' rel='bookmark' title='Permanent Link: PHP Dynamic JavaScript SCRIPT Insertion for Embedding'>PHP Dynamic JavaScript SCRIPT Insertion for Embedding</a></li>
<li><a href='http://blog.perplexedlabs.com/2008/11/12/javascript-event-handler/' rel='bookmark' title='Permanent Link: JavaScript Event Handler'>JavaScript Event Handler</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I've been developing a stock market screener with some advanced functionality.  Some of the parameters a user might enter, because of their complexity or sheer volume of data required to calculate, would cause the screener to run for considerable amounts of time before returning results.  The opportunity to create a progress bar presented itself.  <strong>EVERY DEVELOPER LOVES CREATING PROGRESS BARS</strong>.</p>
<p>The technique is fairly straightforward.  Here's an overview:</p>
<ol>
<li>Dynamically create a hidden IFRAME</li>
<li>Post to the IFRAME</li>
<li>Backend script outputs (in real-time) individual &lt;SCRIPT&gt; tags to the IFRAME.</li>
<li>Each &lt;SCRIPT&gt; tag contains a single function call to the parent of the IFRAME ( parent.myFuncName(); )</li>
<li>Parent JavaScript function updates the status bar with newly passed parameters</li>
</ol>
<p>A bit of background information.  The "processing" thead is initiated when a user hits the 'Screen' button.  It's an AJAX request to a PHP backend.  While executing, for each iteration, it sets status variables in memcache.  These are the variables that our "status" thread will be able to fetch.</p>
<p><span style="color: #c0c0c0;"><em><strong>Note: </strong>There are a variety of ways I can think of to use this same technique to achieve a real-time progress bar satisfying different situations.  For example, your "processing" thread can be your "status" thread if, for each iteration, it outputs the necessary calls we'll discuss below.  That would allow you to avoid the situation of delivering status data to a seperate thread via memcache (or some other technology).</em></span></p>
<p>I previously had been using an AJAX long-polling technique to achieve this.  If you're not familiar with AJAX long-polling it's essentially when you make a subsequent AJAX request on completion of the prior request to achieve a simulated, continual, "stream" from a server.  The problem in using this technique for a progress bar is two-fold:</p>
<ol>
<li>Multiple, continual, repeated requests to a web server.</li>
<li>The data "stream" is pseudo real-time and is affected by variations in each request's latency.  Not very pretty.</li>
</ol>
<p>All examples below utilize the Prototype JavaScript library.</p>
<p><strong>Create the hidden IFRAME</strong></p>
<pre class="brush: jscript;">
// create status iframe
var statusFrame = new Element('iframe', { id: 'statusFrame', name: 'statusFrame' }).hide();
$$('body')[0].appendChild(statusFrame);
</pre>
<p><strong>Post to the IFRAME</strong></p>
<pre class="brush: jscript;">
// create status form
var statusForm = new Element('form', { action: '/stocks/screenstatus', method: 'post', target: 'statusFrame' });
$$('body')[0].appendChild(statusForm);

// post to iframe
statusForm.submit();
</pre>
<p><strong>Backend script snippet to output &lt;SCRIPT&gt; tags</strong></p>
<pre class="brush: php;">
public function screenstatus()
{
	while(1) {
		//status string
		$status = Mcache::get('status');

		// how many have been processed
		$c = Mcache::get('c');

		// how many results
		$rc = Mcache::get('rc');

		// total
		$t = Mcache::get('t');

		echo '&lt;script type=&quot;text/javascript&quot;&gt;parent.updateStatus(&quot;'.$status.'&quot;, '.(int)$c.', '.(int)$rc.', '.(int)$t.');&lt;/script&gt;'.&quot;\n&quot;;
		flush();

		if(($status === false) || ($status === 'canceled') || ($status === 'complete')) {
			break;
		}

		usleep(25000);
	}
}
</pre>
<p><strong>Parent JavaScript function to update progress bar</strong></p>
<p>I chose to use a div with a background color and a dynamically adjusted width as the visual element for my progress bar.  Initially the width is set to 0.  In each updateStatus() call the width is adjusted to the current % of the whole (which in my case is 675px, the final desired width of the progress bar).</p>
<p>To overlay text I have a 2nd div styled 'position: relative;' with negative 'top' and 'bottom-margin'.  This positions the textual div on top of the progress bar div.</p>
<pre class="brush: css;">
#statusProgressBar {
width: 0px;
height: 29px;
background: #f4f4f4;
}
#statusProgress {
position: relative;
top: -29px;
left: 0;
text-align: center;
width: 675px;
padding-top: 3px;
height: 26px;
margin-bottom: -29px;
color: #00a;
font-size: 10px;
}
</pre>
<pre class="brush: xml;">
&lt;div id=&quot;statusProgressBar&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;statusProgress&quot;&gt;&lt;/div&gt;
</pre>
<pre class="brush: jscript;">
function updateStatus(status, c, rc, t)
{
	var statusHTML;
	var progressBarWidth;

	if(status == 'initializing') {
		$('statusProgressBar').setStyle({ width: '0px' });
		statusHTML = '&lt;span id=&quot;top&quot;&gt;Initializing...&lt;/span&gt;';
	} else if(status == 'canceled') {
		$('statusProgressBar').setStyle({ width: '0px' });
		statusHTML = '&lt;span id=&quot;top&quot;&gt;Canceled... '+number_format(c / t * 100, 2)+'% Complete&lt;/span&gt;';
	} else {
		if(t) {
			statusHTML = '&lt;span id=&quot;top&quot;&gt;'+rc+' result(s) ('+number_format((c ? (rc / c) : 0) * 100, 2)+'%)&lt;/span&gt;&lt;br/&gt;&lt;span id=&quot;bot&quot;&gt;'+c+' of '+t+' processed ('+number_format(c / t * 100, 2)+'%)&lt;/span&gt;';
		} else {
			statusHTML = '&lt;span id=&quot;top&quot;&gt;0 result(s)&lt;/span&gt;';
		}
		progressBarWidth = Math.floor(675 * (c / t));
		$('statusProgressBar').setStyle({ width: progressBarWidth+'px' });
	}

	$('statusProgress').update(statusHTML);
}
</pre>
<p>You'll notice that the updateStatus() function calls number_format().  It's functionally equivalent to PHP's number_format().  Here is the JavaScript code below:</p>
<pre class="brush: jscript;">
function number_format( number, decimals, dec_point, thousands_sep ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     bugfix by: Michael White (http://getsprink.com)
    // +     bugfix by: Benjamin Lupton
    // +     bugfix by: Allan Jensen (http://www.winternet.no)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +     bugfix by: Howard Yeend
    // *     example 1: number_format(1234.5678, 2, '.', '');
    // *     returns 1: 1234.57     

    var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
    var d = dec_point == undefined ? &quot;.&quot; : dec_point;
    var t = thousands_sep == undefined ? &quot;,&quot; : thousands_sep, s = n &lt; 0 ? &quot;-&quot; : &quot;&quot;;
    var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + &quot;&quot;, j = (j = i.length) &gt; 3 ? j % 3 : 0;

    return s + (j ? i.substr(0, j) + t : &quot;&quot;) + i.substr(j).replace(/(\d{3})(?=\d)/g, &quot;$1&quot; + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : &quot;&quot;);
}
</pre>
<p>I hope you found some of this code useful.  I welcome comments and criticism!</p>


<p>Related posts:<ol><li><a href='http://blog.perplexedlabs.com/2009/05/04/php-jquery-ajax-javascript-long-polling/' rel='bookmark' title='Permanent Link: PHP jQuery AJAX Javascript Long Polling'>PHP jQuery AJAX Javascript Long Polling</a></li>
<li><a href='http://blog.perplexedlabs.com/2009/02/05/dynamic-javascript-script-insertion-for-embedding/' rel='bookmark' title='Permanent Link: PHP Dynamic JavaScript SCRIPT Insertion for Embedding'>PHP Dynamic JavaScript SCRIPT Insertion for Embedding</a></li>
<li><a href='http://blog.perplexedlabs.com/2008/11/12/javascript-event-handler/' rel='bookmark' title='Permanent Link: JavaScript Event Handler'>JavaScript Event Handler</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://blog.perplexedlabs.com/2008/11/07/real-time-ajax-javascript-progress-bar/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>
