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.
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:
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
brackets in an include file and use
This means that the image-generating code will only be parsed when needed.
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
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.
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 howtimely 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
twiddling:
chart.php
in one nice piece for your own tweaking andtwiddling:
<?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($image, 0xFF, 0xFF, 0xFF);
$navy = imagecolorallocate($image, 0x00, 0x00, 0x80);
$black = imagecolorallocate($image, 0x00, 0x00, 0x00);
$gray = imagecolorallocate($image, 0xC0, 0xC0, 0xC0);
// 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 - 2 * $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.
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>