#native_company# #native_desc#
#native_cta#

Bar Charts With GD Page 6

By Stefan Wiesendanger
on 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:

<?php

/* 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 

    
imagedestroy($image); 

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:

<?php

/* 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); 

    imagestring($image$labelfont$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

    imagefilledrectangle($image$xmin$ymin$xmax$ymax$navy); 

    // x labels 

    
$txtsz imagefontwidth($labelfont) * strlen($xval); 

    $xpos $xmin + (int)(($base $txtsz) / 2); 

    
$xpos max($xmin$xpos); 

    
$ypos $ymax 3// distance from x axis 

    imagestring($image$labelfont$xpos$ypos$xval$black); 

// plot frame 

imagerectangle($image$hmargin$vmargin

    
$hmargin $xsize$vmargin $ysize$black); 

// flush image 

header("Content-type: image/gif"); // or "Content-type: image/png" 

imagegif($image); // or imagepng($image) 

imagedestroy($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:
<HTML>
<BODY>
<H1>Everybody Loves your_country's_president</H1>
<IMG SRC="chart.php" HEIGHT="250" WIDTH="480">
</BODY>
<HTML>

1
|
2
|
3
|
4
|
5
|
6
|
7