PHPBuilder - Bar Charts With GD Page 6

RSS Twitter

Bar Charts With GD - Page 6

by: Stefan Wiesendanger
December 17, 2000

Performance Issues
Now that you can generate graphics on the fly, you might worry (and rightly so) that this could bring your server to its knees. If your site is low-traffic, the problem is marginal. Generating an image like the one above takes well under a second on my Pentium 166 MHz and maybe a second if you include all the overhead for compiling the script. The PHP cache announced by Zend should bring down this latency dramatically.
While we're all waiting for the Zend cache to hit the shelves - or rather ftp servers around the world - there are other solutions to lower the response time. We'll just cache the image on disk. This can be done in the following way:


/* cached_chart.php */ 

$path "path/to/image/file"
$cachefor 3600// time to cache image in seconds 

if (filemtime($path) + $cachefor time()) { 

// draw the image 

imagegif($image$path); // write image to disk 

header("Content-type: image/gif"); 
readfile($path); // send cached copy 

To reduce server load even further, you can put everything between the if brackets in an include file and use include() for conditional inclusion. This means that the image-generating code will only be parsed when needed.
A last idea is to use the CGI version of PHP in the way suggested by Darrell Brogdon in "Using PHP As A Shell Scripting Language" here on PHPBuilder. The image generating script would then be called by cron on a schedule that will depend on how timely your chart has to be. This is probably the most modular way to generate charts. It will also do away with the inconsistent naming of GIF and PNG files with the .php extension.
Source Code
All the source of chart.php in one nice piece for your own tweaking and twiddling:


/* chart.php */ 
$data = array( 
"Jan" => 55
"Feb" => 54
"Mar" => 53
"Apr" => 33
"May" => 13
"Jun" => 15
"Jul" => 23
"Aug" => 28
"Sep" => 32
"Oct" => 45
"Nov" => 73
"Dec" => 71); 

// create image 
$width 480
$height 250
$image imagecreate($width$height); 

// colors 
$white imagecolorallocate($image0xFF0xFF0xFF); 
$navy imagecolorallocate($image0x000x000x80); 
$black imagecolorallocate($image0x000x000x00); 
$gray imagecolorallocate($image0xC00xC00xC0); 

// layout 
$maxval max($data); 
$nval sizeof($data); 

$vmargin 20// top (bottom) vertical margin for title (x-labels) 
$hmargin 38// left horizontal margin for y-labels 

$base floor(($width $hmargin) / $nval); // distance between columns 

$ysize $height $vmargin// y-size of plot 
$xsize $nval $base// x-size of plot 

// title 
$titlefont 3
$title "Presidential Approval Ratings 2000 (in %)"

$txtsz imagefontwidth($titlefont) * strlen($title); // pixel-width of title 

$xpos = (int)($hmargin + ($xsize $txtsz)/2); // center the title 
$xpos max(1$xpos); // force positive coordinates 
$ypos 3// distance from top 

imagestring($image$titlefont$xpos$ypos$title $black); 

// y labels and grid lines 
$labelfont 2
$ngrid 4// number of grid lines 

$dydat $maxval $ngrid// data units between grid lines 
$dypix $ysize / ($ngrid 1); // pixels between grid lines 

for ($i 0$i <= ($ngrid 1); $i++) { 
// iterate over y ticks 

    // height of grid line in units of data 
$ydat = (int)($i $dydat); 

// height of grid line in pixels
$ypos $vmargin $ysize - (int)($i*$dypix); 

$txtsz imagefontwidth($labelfont) * strlen($ydat); // pixel-width of label 
$txtht imagefontheight($labelfont); // pixel-height of label 

$xpos = (int)(($hmargin $txtsz) / 2); 
$xpos max(1$xpos); 

$ypos - (int)($txtht/2), $ydat$black); 

    if (!(
$i == 0) && !($i $ngrid)) {
imageline($image$hmargin 3
$ypos$hmargin $xsize$ypos$gray); 
// don't draw at Y=0 and top 

// columns and x labels 
$padding 3// half of spacing between columns 
$yscale $ysize / (($ngrid+1) * $dydat); // pixels per data unit 

for ($i 0; list($xval$yval) = each($data); $i++) { 

// vertical columns 
$ymax $vmargin $ysize
$ymin $ymax - (int)($yval*$yscale); 
$xmax $hmargin + ($i+1)*$base $padding
$xmin $hmargin $i*$base $padding


// x labels 
$txtsz imagefontwidth($labelfont) * strlen($xval); 

$xpos $xmin + (int)(($base $txtsz) / 2); 
$xpos max($xmin$xpos); 
$ypos $ymax 3// distance from x axis 


// plot frame 
$hmargin $xsize$vmargin $ysize$black); 

// flush image 
header("Content-type: image/gif"); // or "Content-type: image/png" 
imagegif($image); // or imagepng($image) 

You'll note that unlike before, the frame around the chart is drawn in the very end. This is for aesthetic reasons: it now appears in front of the grid lines rather than behind.
Finally, here's the calling approval.html:
<H1>Everybody Loves your_country's_president</H1>
<IMG SRC="chart.php" HEIGHT="250" WIDTH="480">

« Previous Page
Next Page »

Comment and Contribute

Your comment has been submitted and is pending approval.

Stefan Wiesendanger



(Maximum characters: 1200). You have characters left.