GD-Graph-Hooks
view release on metacpan or search on metacpan
use strict;
use Carp;
use GD::Graph::axestype;
use constant {
POST_INIT => 0,
PRE_TEXT => 0,
POST_TEXT => 1,
PRE_AXIS => 1,
POST_AXIS => 2,
PRE_DATA => 2,
POST_DATA => 3,
PRE_VALUES => 3,
POST_VALUES => 4,
PRE_LEGEND => 4,
POST_LEGEND => 5,
PRE_RETURN => 5,
};
sub validate {
my $slot = shift;
$slot >= 0 and $slot <= 5;
}
our $VERSION = "1.0003";
{
no warnings; # hackery below, no warnings in here thanks
*GD::Graph::axestype::add_hook = sub {
my $this = shift;
my $slot = int shift; croak "slot unknown" unless validate($slot);
my $code = shift;
my $hook = ref($code) eq "CODE" ? $code : sub { eval $code };
push @{$this->{_hooks}{$slot}}, $hook;
};
*GD::Graph::axestype::call_hooks = sub {
my $this = shift;
my $slot = shift;
return unless exists $this->{_hooks}{$slot};
for my $f (@{$this->{_hooks}{$slot}}) {
$f->( $this, @$this{qw(graph left right top bottom gdta_x_axis gdta_y_axis)} );
}
};
*GD::Graph::axestype::plot = sub {
my $self = shift;
my $data = shift;
$self->check_data($data) or return;
$self->init_graph() or return;
$self->setup_text() or return;
$self->setup_legend();
$self->setup_coords() or return;
$self->call_hooks(POST_INIT);
$self->draw_text();
$self->call_hooks(POST_TEXT);
unless (defined $self->{no_axes}) {
$self->draw_axes();
$self->draw_ticks() or return;
}
$self->call_hooks(POST_AXIS);
$self->draw_data() or return;
$self->call_hooks(POST_DATA);
$self->draw_values() or return;
$self->call_hooks(POST_VALUES);
$self->draw_legend();
$self->call_hooks(POST_LEGEND);
return $self->{graph}
};
}
1;
__END__
=encoding utf-8
=head1 NAME
GD::Graph::Hooks - Kludgey way to add callback hooks to GD::Graph
=head1 SYNOPSIS
use GD::Graph::Hooks;
use GD::Graph::lines;
my @data;
for( 0 .. 100 ) { push @{$data[0]}, $_; push @{$data[1]}, $_ + 3*(rand 5); }
# compute a naive biased moving average
my (@mv_avg, @last);
for my $i ( 0 .. $#{ $data[1] }) {
push @last, $data[1][$i];
if( @last > 4 ) {
shift @last while @last > 5;
my $sum = 0;
$sum += $_ for @last;
$mv_avg[$i] = ($sum / @last);
}
}
my $graph = GD::Graph::lines->new(1500,500);
$graph->add_hook( 'GD::Graph::Hooks::PRE_DATA' => sub {
my ($gobj, $gd, $left, $right, $top, $bottom, $gdta_x_axis) = @_;
my $clr = $gobj->set_clr(0xaa, 0xaa, 0xaa);
my $x = 10;
while ( $x < $#{ $data[1] }-10 ) {
# compute line endpoints from a datapoint
my @lhs = $gobj->val_to_pixel($x+1, $data[1][$x]);
# to a predicted endpoint, based on the moving average
my @rhs = $gobj->val_to_pixel($x+11, $data[1][$x] + 10*($mv_avg[$x] - $mv_avg[$x-1]));
print "adding line from data point (@lhs) to value predicted by mv_avg (@rhs)\n";
$gd->line(@lhs,@rhs,$clr);
$x += 10;
}
});
my $gd = $graph->plot(\@data);
( run in 2.589 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )