/usr/local/CPAN/htpl/HTML/HTPL/Graph.pm
package HTML::HTPL::Graph;
use HTML::HTPL::Table;
use HTML::HTPL::Lib;
use HTML::HTPL::Sys qw(call);
use strict;
sub new {
my $self = {};
bless $self, shift;
$self->set(@_);
$self;
}
sub set {
my $self = shift;
my %hash = @_;
foreach (keys %hash) {
$self->{lc($_)} = $hash{$_};
}
}
sub astable {
my $self = shift;
my @data;
my @labels = @{$self->{'labels'}};
my $dataref = $self->{'data'};
if (UNIVERSAL::isa($dataref, 'ARRAY')) {
@data = @$dataref;
} elsif (UNIVERSAL::isa($dataref, 'HASH')) {
my $label;
my @vector;
@data = ();
while (keys %$dataref) {
foreach (keys %$dataref) {
push(@vector, shift @{$dataref->{$_}});
delete($dataref->{$_}) if (!@{$dataref->{$_}});
}
push(@data, \@vector);
}
}
my $ref = $self->{'dual'};
if (UNIVERSAL::isa($ref, 'HASH')) {
$ref = [ %$ref ];
}
if (UNIVERSAL::isa($ref, 'ARRAY')) {
my @pairs = @$ref;
@data = ();
@labels = ();
foreach (@pairs) {
push(@data, $_->[1]);
push(@labels, $_->[0]);
}
}
return unless (@data);
my $max = &mymax(@data) || 1;
my $cols = $self->{'cols'};
my $width = $self->{'width'} || 400;
my $unit = $max / $cols if ($cols);
my @colors = @{$self->{'colors'}};
unless (@colors) {
my $item = $data[0];
my $card = scalar(@$item);
my $c;
@colors = map {'#' . sprintf("%02x%02x%02x",
$c = int(0xFF * ($_ - 1) / $card), $c, $c);} (1 .. $card);
}
my $textcol = $self->{'text'};
my $disp = ($textcol ? sub
{return qq! <FONT COLOR="$textcol">$_</FONT>!;}
: sub {return " $_";});
my $gif = $self->{'gif'} || 'pixel.gif';
my $draw = $self->{'draw'} || sub {return qq!<IMG SRC="$gif" WIDTH=$_ HEIGHT=1>!;};
my $fmt = $self->{'fmt'} || "%d";
my $cfmt = (UNIVERSAL::isa($fmt, 'CODE') ? $fmt :
sub {return sprintf($fmt, $_);});
my $i;
my $table = new HTML::HTPL::Table('cols' => 2);
if ($cols) {
my $ct = new HTML::HTPL::Table('cellpadding' => 0, 'border' => 0,
'width' => $width, 'cellspacing' => 0, 'cols' => $cols);
my $w = $width / $cols;
my ($x, @v);
foreach $x (1 .. $cols) {
push(@v, {'data' => &call($cfmt, (($x - 1) / $cols * $max)),
'cattr' => {'width' => $w}});
}
my $el = pop @v;
my $tiny = new HTML::HTPL::Table('cellspacing' => 0, 'border' => 0,
'cellpadding' => 0, 'cols' => 2, 'width' => $w);
my $el2 = {'data' => &call($cfmt, $max),
'cattr' => {'align' => 'right'}};
$tiny->add($el->{'data'}, $el2);
push(@v, {'data' => $tiny->ashtml, 'cattr' => {'width' => $w}});
$ct->add(@v);
$table->add([' ', $ct->ashtml]);
}
foreach $i ((0 .. $#data)) {
my @these;
if (UNIVERSAL::isa($data[$i], 'ARRAY')) {
my @cols = @colors;
my (@dat, $datum);
foreach $datum (@{$data[$i]}) {
my $col = shift @cols;
push(@cols, $col);
push(@dat, [$datum, $col]);
}
@these = sort {$a->[0] <=> $b->[0]} @dat;
} else {
my $col = shift @colors;
push(@colors, $col);
@these = ([$data[$i], $col]);
}
my (@cells, @cells2);
my $tillnow = 0;
my $datum;
foreach (@these) {
my ($datum, $col) = @$_;
my $this = int($datum * $width / $max);
if ($this > $tillnow) {
push(@cells, {'data' => &call($draw, $this - $tillnow,),
'cattr' => {'bgcolor' => $col}});
$tillnow = $this;
}
}
my $row = new HTML::HTPL::Table('cellpadding' => 0,
'cellspacing' => 0, 'border' => 0,
'cols' => $#cells + 2);
$row->add(@cells, &call($disp, &call($cfmt, $datum)));
$table->add([&call($disp, $labels[$i]), $row->ashtml]);
}
my @legend = @{$self->{'legend'}};
if (@legend) {
my @cols = @colors;
my @cells = ();
my @cells2 = ();
my $per = int(100 / scalar(@legend));
foreach (@legend) {
my $col = shift @colors;
push(@cells, {'cattr' => {'bgcolor' => $col,
'width' => "$per%"},
'data' => qq!<FONT COLOR="$textcol">$_</FONT>!});
push(@cells2, {'cattr' => {'width' => "$per%"},
'data' => qq!<FONT COLOR="$col">$_</FONT>!});
}
my $legend = new HTML::HTPL::Table('cols' => scalar(@legend),
'border' => 2, 'width' => $width, 'cellpadding' => 2);
$legend->add(@cells);
$legend->add(@cells2);
$table->add(" ", $legend->ashtml);
}
$table;
}
sub ashtml {
my $self;
my $table = $self->astable || return undef;
$table->ashtml;
}
sub mymax {
if (!$#_) {
return &mymax(@{$_[0]}) if (UNIVERSAL::isa($_[0], 'ARRAY'));
return $_[0];
}
my $start = &mymax(shift);
foreach (@_) {
my $val = &mymax($_);
$start = $val if ($val > $start);
}
$start;
}
1;