Part 1 shows how to move, hide, and display Web page content. But what about creating new HTML on the fly? How do you graph data and use similar fun techniques? Figure 1 shows a graph of world illiteracy rates (data from Unesco; see Resources).
Figure 1. Illiteracy rates worldwide by year
This isn't the most entertaining data set, but it's encouraging. What if you want to see only the illiteracy rate in Europe? Easy: Click the drop-down and select Europe.
Figure 2. Illiteracy rates in Europe by year
The graph shows that illiteracy rates are far lower in Europe than they are worldwide. The code in Listing 1 produces this dynamic graph.
Listing 1. The bar graph code
<html>
<head>
<title>Bar Graph Example</title>
<script>
var years = [ 1970, 1980, 1990, 1995, 2000, 2005, 2010, 2015 ];
var rates = [];
rates[ 'World' ] = [ 36.6, 30.3, 24.7, 22.4,
20.3, 18.3, 16.5, 15.0 ];
rates[ 'Africa' ] = [ 72.4, 62.4, 51.2, 45.6,
40.2, 35.2, 30.8, 26.8 ];
rates[ 'America' ] = [ 14.8, 11.6, 9.0, 7.9,
6.9, 6.0, 5.3, 4.6 ];
rates[ 'Asia' ] = [ 48.5, 38.7, 30.2, 27.2,
24.4, 21.8, 19.6, 17.7 ];
rates[ 'Europe' ] = [ 6.4, 4.3, 2.8, 2.2, 1.8,
1.4, 1.1, 0.8 ];
rates[ 'Oceania' ] = [ 11.1, 8.7, 7.1, 6.6,
6.1, 5.6, 5.3, 5.0 ];
function plot( region )
{
var html = "";
html += "<table width='100%' cellspacing='0' cellpadding='1'>";
for( var year in years )
{
var val = Math.round( rates[region][year] );
html += "<tr>";
html += "<td width='8%'>"+years[year]+"</td>";
html += "<td width='1%' class='bar-start'></td>";
html += "<td width='92%'>";
html += "<table width='100%' cellspacing='0' ";
html += "cellpadding='0'><tr>";
html += "<td width='"+val+"%' class='bar-on'>";
html += " </td>";
html += "<td width='"+(100-val);
html += "%' class='bar-off'> </td>";
html += "</tr></table></td>";
html += "<td width='1%' class='bar-start'></td>";
html += "</tr>";
}
html += "</table>";
document.getElementById( "graph" ).innerHTML = html;
}
</script>
<style>
body { font-family: arial, verdana, sans serif; }
.bar-on { background: blue; }
.bar-off { background: white; }
.bar-start { width:1px; background: black; }
#graph { width: 600px; }
</style>
</head>
<body onload="plot('World')">
Region:
<select onchange="plot(this.options[this.selectedIndex].value)">
<option value="World">World</option>
<option value="Africa">Africa</option>
<option value="America">America</option>
<option value="Asia">Asia</option>
<option value="Europe">Europe</option>
<option value="Oceania">Oceania</option>
</select><br/><br/>
Rates of illiteracy (larger is worse):<br/><br/>
<div id="graph">
</div>
</body>
</html>
|
Begin with an empty <div> with the ID "graph". The onload attribute of the <body> tag tells the browser to call the plot function when the page is loaded. The plot function is where the fun happens.
The function begins by creating an empty string. Next, it builds up the graph by adding <table>, <tr>, and <td> tags into the string. The function then sets the innerHTML attribute of the graph <div> tag to be the newly generated HTML.
The graph itself is a table with four columns: the year, a little spacer, the bar, and another spacer. Within each row of the bar column is another table. These nested tables have two cells: The first is colored blue, and the second is white. The width of the blue cell is the percentage of illiteracy, and the width of the white cell is 100 minus the original percentage. The result is a simple HTML bar graph with no images.
The Region drop-down has an onchange handler that's called whenever a new item is selected. When that happens, the plot method is called with the currently selected value, and the graph is updated.
This code is very compatible. The use of innerHTML, which is being replaced by DOM methods like createElement and appendChild, is compatible with every modern browser.
In implementing the PHP for bar graphs, this article looks at how to take data from the PHP code in the server and put it into dynamic HTML (DHTML) JavaScript. The PHP code for the bar graph is shown in Listing 2.
Listing 2. The bar graph code in PHP
<?php
$years = array( 1970, 1980, 1990, 1995, 2000, 2005, 2010, 2015 );
$countries = array();
$countries[ "World" ] = array( 36.6, 30.3, 24.7, 22.4,
20.3, 18.3, 16.5, 15.0 );
$countries[ "Africa" ] = array( 72.4, 62.4, 51.2, 45.6,
40.2, 35.2, 30.8, 26.8 );
$countries[ "America" ] = array( 14.8, 11.6, 9.0, 7.9,
6.9, 6.0, 5.3, 4.6 );
$countries[ "Asia" ] = array( 48.5, 38.7, 30.2, 27.2,
24.4, 21.8, 19.6, 17.7 );
$countries[ "Europe" ] = array( 6.4, 4.3, 2.8, 2.2,
1.8, 1.4, 1.1, 0.8 );
$countries[ "Oceania" ] = array( 11.1, 8.7, 7.1, 6.6,
6.1, 5.6, 5.3, 5.0 );
?>
<html>
<head>
<title>Bar Graph Example</title>
<script>
var years = [ <?php echo( join( ",", $years ) ); ?> ];
var rates = [];
<?php
foreach( $countries as $name => $values ) {
?>
rates[ '<?php echo($name) ?>' ] = [
<?php echo( join( ",", $values ) ); ?> ];
<?php } ?>
function plot( region )
{
var html = "";
html += "<table width='100%' cellspacing='0' cellpadding='1'>";
for( var year in years )
{
var val = Math.round( rates[region][year] );
html += "<tr>";
html += "<td width='8%'>"+years[year]+"</td>";
html += "<td width='1%' class='bar-start'></td>";
html += "<td width='92%'>";
html += "<table width='100%' cellspacing='0' cellpadding='0'><tr>";
html += "<td width='"+val+"%' class='bar-on'> </td>";
html += "<td width='"+(100-val)+"%' class='bar-off'> </td>";
html += "</tr></table></td>";
html += "<td width='1%' class='bar-start'></td>";
html += "</tr>";
}
html += "</table>";
document.getElementById( "graph" ).innerHTML = html;
}
</script>
<style>
body { font-family: arial, verdana, sans serif; }
.bar-on { background: blue; }
.bar-off { background: white; }
.bar-start { width:1px; background: black; }
#graph { width: 600px; }
</style>
</head>
<body onload="plot('World')">
Region: <select onchange="plot(this.options[this.selectedIndex].value)">
<?php
foreach( $countries as $name => $values ) {
?>
<option value="<?php echo($name) ?>"><?php echo($name) ?></option>
<?php } ?>
</select><br/><br/>
Rates of illiteracy (larger is worse):<br/><br/>
<div id="graph">
</div>
</body>
</html>
|
At the top of the file, preload the years and countries arrays with the years, and the list of countries and their literacy values. Then, PHP needs to generate three areas of the DHTML code. The first populates the years array in the JavaScript, the second populates the rates, and the third sets the contents of the <select> tag with the names of the countries.
Creating new HTML on the fly is at the heart of DHTML. One option is to build a string and set the inner HTML of elements on the page. This example shows a second method, using a scatter plot as an example. Figure 3 shows a plot of a simple equation.
Figure 3. A graph of a multiperiod sine wave
You can change the equation and click the Try It! button to update the graph, as shown in Figure 4.
Figure 4. A graph of a slightly different equation
All that without going back to the PHP server. This example doesn't even use a server -- you can just create a new HTML file and begin writing the HTML code. The code for the graph is shown in Listing 3.
Listing 3. The scatter plot code
<html>
<head>
<title>Dynamic Graphing Example</title>
<style type="text/css">
body { font-family: arial, verdana, sans serif; }
#graphdiv {
height:500px; width:500px;
border:1px solid black;
position:relative;
}
</style>
<script>
function drawgraph()
{
var g = document.getElementById( "graphdiv" );
var eq = document.getElementById( "eq" ).value;
var dx = [];
var dy = [];
var sx = 10000;
var ex = -10000;
var sy = 10000;
var ey = -10000;
for( var i = 0; i < 100; i++ )
{
var x = i / 100;
var y = eval( eq );
if ( y > ey ) ey = y;
if ( y < sy ) sy = y;
if ( x > ex ) ex = x;
if ( x < sx ) sx = x;
dx.push( x );
dy.push( y );
}
var gwidth = 500;
var gheight = 500;
var imgwidth = 100;
var imgheight = 100;
var fx = (gwidth-(imgwidth/2))/(ex-sx);
var fy = ((gheight-(imgheight/2))/2)/(ey-sy);
g.innerHTML = "";
for( i = 0; i < dx.length; i++ )
{
var x = ( dx[i] * fx );
var y = ((gheight-(imgheight/2))/2)+(dy[i]*fy);
var img = document.createElement( "img" );
img.src = "ball.gif";
img.style.position = "absolute";
img.style.top = y+"px";
img.style.left = x+"px";
g.appendChild( img );
}
}
</script>
</head>
<body onload="drawgraph()">
Equation:
<input type="text" id="eq" value="Math.sin(x*32)" />
<button onclick="drawgraph()">Try It!</button>
<br/><br/>
<div id="graphdiv">
</div>
</body>
</html>
|
Most of the code in this example is in the drawgraph JavaScript function. That function creates two arrays of numbers -- one for the x value and another for the y value. The numbers on the x axis run from 0 to 1; the numbers in the y axis are generated by evaluating the equation for each x value.
As the data are generated from the equation, the code keeps the minimum and maximum for each axis, then autoscales the data to fit.
Putting the images into the graph employs a new technique: You use the document.createElement to build an <img> tag, then you use appendChild to add the newly created img object to the graph object. This technique is preferable to setting innerHTML using a string because the code is easier to read and maintain -- and you don't have to worry about string-encoding issues.
The technique of using createElement is compliant with the World Wide Web Consortium (W3C) Document Object Model (DOM) specification and is the preferred way of creating HTML elements dynamically.
The scatter plot example is self-contained. The PHP code wraps the scatter plot as a component. The code for the component is shown in Listing 4.
Listing 4. The scatter plot code in PHP
<?php
function graph_header()
{
?>
<style type="text/css">
body { font-family: arial, verdana, sans serif; }
#graphdiv {
height:500px; width:500px;
border:1px solid black;
position:relative;
}
</style>
<script>
function drawgraph()
{
var g = document.getElementById( "graphdiv" );
var eq = document.getElementById( "eq" ).value;
var dx = [];
var dy = [];
var sx = 10000;
var ex = -10000;
var sy = 10000;
var ey = -10000;
for( var i = 0; i < 100; i++ )
{
var x = i / 100;
var y = eval( eq );
if ( y > ey ) ey = y;
if ( y < sy ) sy = y;
if ( x > ex ) ex = x;
if ( x < sx ) sx = x;
dx.push( x );
dy.push( y );
}
var gwidth = 500;
var gheight = 500;
var imgwidth = 100;
var imgheight = 100;
var fx = (gwidth-(imgwidth/2))/(ex-sx);
var fy = ((gheight- (imgheight/2))/2)/(ey-sy);
g.innerHTML = "";
for( i = 0; i < dx.length; i++ )
{
var x = ( dx[i] * fx );
var y = ((gheight-(imgheight/2))/2)+(dy[i]*fy);
var img = document.createElement( "img" );
img.src = "ball.gif";
img.style.position = "absolute";
img.style.top = y+"px";
img.style.left = x+"px";
g.appendChild( img );
}
}
</script>
<?php
}
function graph_place()
{
?>
</head>
<div id="graphdiv">
</div>
<?php
}
?>
|
This code defines two functions: graph_header and graph_place. The graph_header function should be called in the head section of the document, and the graph_place should be called wherever you want the graph to go. Listing 5 shows the code for the updated graph page.
Listing 5. The updated scatter plot code in PHP
<?php require_once( "graph_component.php" ); ?> <html> <head> <title>Dynamic Graphing Example</title> <?php graph_header(); ?> </head> <body onload="drawgraph()"> Equation: <input type="text" id="eq" value="Math.sin(x*32)" /> <button onclick="drawgraph()">Try It!</button> <br/><br/> <?php graph_place(); ?> </body> </html> |
It's much simpler than the original page. You include the code for the component. Then you call the graph_header to add the JavaScript and CSS. Finally, you call the graph_place function where you want to place the graph on the page.
It's easy to get drawn into the power and simplicity of JavaScript code. The question quickly becomes not how little to put in but how far to push the envelope. Google Maps (see Resources) is an excellent example of a DHTML application that not only is useful on a site but also can be integrated into any Web page with only a little JavaScript. But Google didn't stop there: It also created Gmail (see Resources), which makes extensive use of DHTML to create an easy-to-use mail client right in the browser. (You may not take your JavaScript that far, but it's nice to see what you could do if you took the time.)
One technology every DHTML programmer should look into is Asynchronous JavaScript and XML (Ajax). Ajax adds the ability for the browser to make Web requests in the background. That means your DHTML application can call back to your PHP application without requiring a page refresh. The page can then use that data to refresh the information presented -- all without the user leaving the comfort of the page he's on. (See Resources for Ajax articles and tutorials.)
The previous article this "Devise Web 2.0 applications with PHP and DHTML" series began by talking about the new buzzword de jour, Web 2.0. Another big industry buzzword is rich client applications. They both mean cool Web applications, so you can think of them the same way. Lots of technologies are available for creating rich Internet applications. Laszlo and MXML make building Flash a lot easier, and Microsoft® has some new ideas coming in Vista. But DHTML is tempting for building rich Internet applications because you can do it with the technologies you already have, like PHP.
This article has demonstrated several methods for enriching the customer experience with simple CSS and JavaScript. You can do the same in the Web applications you're working in now -- just open a <script> tag and have some fun.
Learn
-
PHP.net is the starting point for all things PHP.
-
The Ajaxian blog is a great place to go looking for client-side coding tips.
-
Ajax Freaks is another good client-side site.
-
The Web Reference has good articles and reference materials on browser compatibility issues.
-
O'Reilly's Dynamic HTML: The Definitive Reference is the best book on Dynamic HTML.
-
The Unesco Institute for Statistics provides data on worldwide illiteracy as of 2000.
-
A good demonstration of DHTML in action is Google Maps, which can help you find your way around the world.
-
Try dynamic Web mail at Gmail and Laszlo Mail.
-
Read "A cross-browser DHTML table" to learn how to create a cross-browser table with DHTML and JavaScript, which does most of the things that a table component written in Java might do.
-
IBM developerWorks offers many articles and tutorials on Ajax, including "Mastering Ajax, Part 1: Introduction to Ajax" and "Using Ajax with PHP and Sajax."
-
Visit IBM developerWorks PHP project resources to learn more about PHP.
-
Stay current with developerWorks technical events and webcasts.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
Get products and technologies
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
-
Get involved in the developerWorks community by participating in developerWorks blogs.




