diff options
| author | Andreas Brachold <vdr07@deltab.de> | 2007-08-13 18:41:27 +0000 |
|---|---|---|
| committer | Andreas Brachold <vdr07@deltab.de> | 2007-08-13 18:41:27 +0000 |
| commit | bcbf441e09fb502cf64924ff2530fa144bdf52c5 (patch) | |
| tree | f377707a2dac078db8cd0c7d7abfe69ac1006d71 /lib/GD/Graph/bars3d.pm | |
| download | xxv-bcbf441e09fb502cf64924ff2530fa144bdf52c5.tar.gz xxv-bcbf441e09fb502cf64924ff2530fa144bdf52c5.tar.bz2 | |
* Move files to trunk
Diffstat (limited to 'lib/GD/Graph/bars3d.pm')
| -rw-r--r-- | lib/GD/Graph/bars3d.pm | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/lib/GD/Graph/bars3d.pm b/lib/GD/Graph/bars3d.pm new file mode 100644 index 0000000..5344976 --- /dev/null +++ b/lib/GD/Graph/bars3d.pm @@ -0,0 +1,349 @@ +#========================================================================== +# Module: GD::Graph::bars3d +# +# Copyright (C) 1999,2001 Wadsack-Allen. All Rights Reserved. +# +# Based on GD::Graph::bars.pm,v 1.16 2000/03/18 10:58:39 mgjv +# Copyright (c) 1995-1998 Martien Verbruggen +# +#-------------------------------------------------------------------------- +# Date Modification Author +# ------------------------------------------------------------------------- +# 1999SEP18 Created 3D bar chart class (this module) JAW +# 1999SEP19 Rewrote to include a single bar-drawing JAW +# function and process all bars in series +# 1999SEP19 Implemented support for overwrite 2 style JAW +# 1999SEP19 Fixed a bug in color cycler (colors were off by 1) JAW +# 2000JAN19 Converted to GD::Graph class JAW +# 2000MAR10 Fixed bug where bars ran off bottom of chart JAW +# 2000APR18 Modified to be compatible with GD::Graph 1.30 JAW +# 2000APR24 Fixed a lot of rendering bugs and added shading JAW +# 2000AUG21 Added 3d shading JAW +# 2000AUG24 Fixed shading on cycle_clrs option JAW +# 06Dec2002 Fixed on-bar rendering with bars.pm draw_values JW +#========================================================================== +package GD::Graph::bars3d; + +use strict; + +use GD::Graph::axestype3d; +use GD::Graph::bars; +use GD::Graph::utils qw(:all); +use GD::Graph::colour qw(:colours); + +@GD::Graph::bars3d::ISA = qw(GD::Graph::axestype3d); +$GD::Graph::bars3d::VERSION = '0.63'; + +use constant PI => 4 * atan2(1,1); + + +my %Defaults = ( + # Spacing between the bars + bar_spacing => 0, + + # The 3-d extrusion depth of the bars + bar_depth => 10, +); + +sub initialise +{ + my $self = shift; + + my $rc = $self->SUPER::initialise(); + $self->set(correct_width => 1); + + while( my($key, $val) = each %Defaults ) { + $self->{$key} = $val + } # end while + + return $rc; +} # end initialise + +sub set +{ + my $s = shift; + my %args = @_; + + $s->{_set_error} = 0; + + for (keys %args) + { + /^bar_depth$/ and do + { + $s->{bar_depth} = $args{$_}; + delete $args{$_}; + next; + }; + } + + return $s->SUPER::set(%args); +} + + +# CONTRIB Jeremy Wadsack +# This is a complete overhaul of the original GD::Graph::bars +# design, because all versions (overwrite = 0, 1, 2) +# require that the bars be drawn in a loop of point over sets +sub draw_data +{ + my $self = shift; + my $g = $self->{graph}; + + my $bar_s = _round($self->{bar_spacing}/2); + + my $zero = $self->{zeropoint}; + + my $i; + my @iterate = (0 .. $self->{_data}->num_points()); + for $i ($self->{rotate_chart} ? reverse(@iterate) : @iterate) { + my ($xp, $t); + my $overwrite = 0; + $overwrite = $self->{overwrite} if defined $self->{overwrite}; + + my $j; + my @iterate = (1 .. $self->{_data}->num_sets()); + for $j (($self->{rotate_chart} && $self->{cumulate} == 0) ? reverse(@iterate) : @iterate) { + my $value = $self->{_data}->get_y( $j, $i ); + next unless defined $value; + + my $bottom = $self->_get_bottom($j, $i); + $value = $self->{_data}->get_y_cumulative($j, $i) + if ($self->{cumulate}); + + # Pick a data colour, calc shading colors too, if requested + # cycle_clrs option sets the color based on the point, not the dataset. + my @rgb; + if( $self->{cycle_clrs} ) { + @rgb = $self->pick_data_clr( $i + 1 ); + } else { + @rgb = $self->pick_data_clr( $j ); + } # end if + my $dsci = $self->set_clr( @rgb ); + if( $self->{'3d_shading'} ) { + $self->{'3d_highlights'}[$dsci] = $self->set_clr( $self->_brighten( @rgb ) ); + $self->{'3d_shadows'}[$dsci] = $self->set_clr( $self->_darken( @rgb ) ); + } # end if + + # contrib "Bremford, Mike" <mike.bremford@gs.com> + my $brci; + if( $self->{cycle_clrs} > 1 ) { + $brci = $self->set_clr($self->pick_data_clr($i + 1)); + } else { + $brci = $self->set_clr($self->pick_border_clr($j)); + } # end if + + + # get coordinates of top and center of bar + ($xp, $t) = $self->val_to_pixel($i + 1, $value, $j); + + # calculate offsets of this bar + my $x_offset = 0; + my $y_offset = 0; + if( $overwrite == 1 ) { + $x_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j); + $y_offset = $self->{bar_depth} * ($self->{_data}->num_sets() - $j); + } + $t -= $y_offset; + + + # calculate left and right of bar + my ($l, $r); + if ($self->{rotate_chart}) { + $l = $bottom; + ($r) = $self->val_to_pixel($i + 1, $value, $j); + } + + if( (ref $self eq 'GD::Graph::mixed') || ($overwrite >= 1) ) + { + if ($self->{rotate_chart}) { + $bottom = $t + $self->{x_step}/2 - $bar_s + $x_offset; + $t = $t - $self->{x_step}/2 + $bar_s + $x_offset; + } + else + { + $l = $xp - $self->{x_step}/2 + $bar_s + $x_offset; + $r = $xp + $self->{x_step}/2 - $bar_s + $x_offset; + } + } + else + { + if ($self->{rotate_chart}) { + warn "base is $t"; + $bottom = $t - $self->{x_step}/2 + + ($j) * $self->{x_step}/$self->{_data}->num_sets() + + $bar_s + $x_offset; + $t = $t - $self->{x_step}/2 + + ($j-1) * $self->{x_step}/$self->{_data}->num_sets() + - $bar_s + $x_offset; + warn "top bottom is ($t, $bottom)"; + } + else + { + $l = $xp + - $self->{x_step}/2 + + ($j - 1) * $self->{x_step}/$self->{_data}->num_sets() + + $bar_s + $x_offset; + $r = $xp + - $self->{x_step}/2 + + $j * $self->{x_step}/$self->{_data}->num_sets() + - $bar_s + $x_offset; + } + } + + if ($value >= 0) { + # draw the positive bar + $self->draw_bar( $g, $l, $t, $r, $bottom-$y_offset, $dsci, $brci, 0 ) + } else { + # draw the negative bar + $self->draw_bar( $g, $l, $bottom-$y_offset, $r, $t, $dsci, $brci, -1 ) + } # end if + + } # end for + } # end for + + + # redraw the 'zero' axis, front and right + if( $self->{zero_axis} ) { + $g->line( + $self->{left}, $self->{zeropoint}, + $self->{right}, $self->{zeropoint}, + $self->{fgci} ); + $g->line( + $self->{right}, $self->{zeropoint}, + $self->{right}+$self->{depth_3d}, $self->{zeropoint}-$self->{depth_3d}, + $self->{fgci} ); + } # end if + + # redraw the box face + if ( $self->{box_axis} ) { + # Axes box + $g->rectangle($self->{left}, $self->{top}, $self->{right}, $self->{bottom}, $self->{fgci}); + $g->line($self->{right}, $self->{top}, $self->{right} + $self->{depth_3d}, $self->{top} - $self->{depth_3d}, $self->{fgci}); + $g->line($self->{right}, $self->{bottom}, $self->{right} + $self->{depth_3d}, $self->{bottom} - $self->{depth_3d}, $self->{fgci}); + } # end if + + return $self; + +} # end draw_data + +# CONTRIB Jeremy Wadsack +# This function draws a bar at the given +# coordinates. This is called in all three +# overwrite modes. +sub draw_bar { + my $self = shift; + my $g = shift; + my( $l, $t, $r, $b, $dsci, $brci, $neg ) = @_; + + # get depth of the bar + my $depth = $self->{bar_depth}; + + # get the bar shadow depth and color + my $bsd = $self->{shadow_depth}; + my $bsci = $self->set_clr(_rgb($self->{shadowclr})); + + my( $xi ); + + # shadow + if( $bsd > 0 ) { + my $sb = $b - $depth; + my $st = $t - $depth + $bsd; + + if( $neg != 0 ) { + $st -= $bsd; + if( $self->{zero_axis_only} ) { + $sb += $bsd; + } else { + $sb = _min($b-$depth+$bsd, $self->{bottom}-$depth); + } # end if + } # end if + + # ** If this isn't the back bar, then no side shadow should be + # drawn or else the top should be lowered by + # ($bsd * dataset_num), it should be drawn on the back surface, + # and a shadow should be drawn behind the front bar if the + # bar is positive and the back is negative. + + $g->filledRectangle($l+$depth+$bsd, + $st, + $r+$depth+$bsd, + $sb, + $bsci); + + # Only draw bottom shadow if at the bottom and has bottom + # axis. Always draw top shadow + if( ($neg == 0) || ($sb >= $self->{bottom}-$depth) ) { + my $poly = new GD::Polygon; + $poly->addPt( $r, $b ); + $poly->addPt( $r+$bsd, $b ); + $poly->addPt( $r+$depth+$bsd, $b-$depth ); + $poly->addPt( $r+$depth, $b-$depth ); + $g->filledPolygon( $poly, $bsci ); + } # end if + + } # end if + + # side + my $poly = new GD::Polygon; + $poly->addPt( $r, $t ); + $poly->addPt( $r+$depth, $t-$depth ); + $poly->addPt( $r+$depth, $b-$depth ); + $poly->addPt( $r, $b ); + if( $self->{'3d_shading'} ) { + $g->filledPolygon( $poly, $self->{'3d_shadows'}[$dsci] ); + } else { + $g->filledPolygon( $poly, $dsci ); + } # end if + $g->polygon( $poly, $brci ); + + # top + # -- only draw negative tops if the bar starts at zero + if( ($neg == 0) || ($t <= $self->{zeropoint}) ) { + $poly = new GD::Polygon; + $poly->addPt( $l, $t ); + $poly->addPt( $l+$depth, $t-$depth ); + $poly->addPt( $r+$depth, $t-$depth ); + $poly->addPt( $r, $t ); + if( $self->{'3d_shading'} ) { + $g->filledPolygon( $poly, $self->{'3d_highlights'}[$dsci] ); + } else { + $g->filledPolygon( $poly, $dsci ); + } # end if + $g->polygon( $poly, $brci ); + } # end if + + # face + $g->filledRectangle( $l, $t, $r, $b, $dsci ); + $g->rectangle( $l, $t, $r, $b, $brci ); + +} # end draw_bar + +# [JAW] Overrides axestype's set_max_min. +# Go through the parent's process then adjust the baseline to 0 for bar graphs. +sub set_max_min { + my $self = shift; + + $self->SUPER::set_max_min( @_ ); + + # This code is taken from Martien's axestype.pm + for my $i (1..($self->{two_axes} ? 2 : 1)) { + # If at the same side of the zero axis + if( $self->{y_max}[$i] && $self->{y_min}[$i]/$self->{y_max}[$i] > 0 ) { + $self->{y_min}[$i] > 0 ? + $self->{y_min}[$i] = 0 : + $self->{y_max}[$i] = 0 ; + } # end if + } # end for + + return $self; +} # end set_max_min + + +# [JW] Just use the one in GD::Graph::bars +sub draw_values +{ + return &GD::Graph::bars::draw_values( @_ ); +} + + +1; |
