CGI and Perl

Listing 14.4. GD_Logfile.pm.

package Logfile::GD_Logfile;
 =head1 NAME
 GD_Logfile - add a graphing feature the Logfile class, a single method to
 allow bar graph generation of log data.  Uses the GD module to produce the
 graph.
 =head1 SYNOPSYS
     Logfile::GD_Logfile::graph($l,Group => File,
                            Sort => Records,
                            ImSize => [640,480],
                            Font => `gdSmallFont'
                           );
 Where $l is a Logfile object, ImSize is the output image size, and Font is
 a font from the GD module. All other parameters to the Logfile::report()
 method may be included, but only one List variable may be passed in.
 =head1 AUTHOR
 Bill Middleton - [email protected]
 =cut
 use GD;
 sub graph{
 my $self  = shift;
 my %par = @_;
 my $group = $self->group($par{Group});
 my $sort  = $par{Sort} || $group;
 my $font = $par{Font};
 my $rever = (($sort =~ /Date|Hour/) xor $par{Reverse});
 my $list  = $par{List};
 my ($keys, $key, $val, %keys);
 my $direction = ($rever)?'increasing':'decreasing';
 my (@list, %absolute);
 my (@sorted, $rec_total, $largest, $list_total);
 my ($width, $ht, $color, $black, $white);
 my ($im, $i, $inc);
 my($top,$bottom,$left,$right);
 my($color_inc,$title);
 my($third,$fourth,$current);
 # Instantiate a new GD image based on args or default
 if(ref($par{ImSize})){
     $im = new GD::Image(@{$par{ImSize}});
     $right = $par{ImSize}->[0] - 30;
     $top = $par{ImSize}->[1] - 30 ;
     $left = $par{ImSize}->[0] / 2;
     $bottom = $par{ImSize}->[1] /10;
 }
 else{ # defaults to 640x480
     $im = new GD::Image(640,480); # default
     $right = 610;
     $top = 450;
     $left = 320;
     $bottom = 48;
 }
 # Set up a few basic colors and sizes
 $width = $right - $left;
 $ht = $top - $bottom ;
 $white = $im->colorAllocate(255, 255, 255);
 $black = $im->colorAllocate(0 , 0, 0);
 $im->transparent($white);
 # Graphs of this sort only make sense with single variable
 if ($list) {
     if (ref($list)) {
         die "Sorry, graphs may have only one List variable\n"
     }
 } else {
     $list = "Records";
 }
 # Sum things up
 while (($key,$val) = each %{$self->{$group}}) {
     $keys{$key} = $val->{$sort};
     $rec_total+=1;
     $list_total += $val->{$list};
 }
 (defined $par{Top}) and $rec_total = $par{Top};
 # Graph outline
 $im->line($left,$top,$right,$top,$black);
 $im->line($left,$top,$left,$bottom,$black);
 # Graph Title
 $title = "Percentages of $list by $group";
 $im->string(gdLargeFont,$left,10,$title,$black);
 $title = "Total $list = $list_total";
 $im->string(gdMediumBoldFont,$left,
     ($top + $bottom/4),$title,$black);
 # $i will be our color increment variable for grayscale
 $i = 200;
 $color_inc = 100 / $rec_total;
 $top = $bottom + ($ht / $rec_total);
 # A couple of text layout variables
 $fourth= (($ht / $rec_total) / 4);
 $third = (($ht / $rec_total) / 3);
 # Main loop iterates over items, draws the text field and
 # rectangle representing the percentage of total for each
 for $key ( sort
     {&Logfile::Base::srt($rever, $keys{$a}, $keys{$b})}
         keys %keys){
     my $val = $self->{$group}->{$key};
     next unless defined($val);
     $color = $im->colorAllocate($i, $i, $i);
     if ($key =~ /$;/) {
         die "Sorry, graphs may have only one key\n";
     }
     $current = $top - $fourth * 3;
     $im->string(&{$font},10,$current,$key,$black);
     $title = sprintf("%s(%4.2f%%)",' ` x 5,
             ($val->{$list}/$list_total * 100));
     $current = $top - $third;
     $im->string(&{$font},10,$current,$title,$black);
     $right = $left + ($width * $val->{$list} / $list_total);
     $im->rectangle($left,$top,$right,$bottom,$black);
     $im->fill(($left+1),($bottom+1),$color);
     $bottom = $top;
     $top += $ht / $rec_total;
     last if defined $par{Top} && --$par{Top} <= 0;
     $i -= $color_inc;
 }
 # Dump the GIF to stdout
 print $im->gif;
 }
 1;

Now you can produce a nice, two-dimensional graph of your log file data with Listing 14.5.