File Coverage

blib/lib/GD/Graph/smootharea.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package GD::Graph::smootharea;
2            
3 1     1   22714 use strict;
  1         2  
  1         35  
4 1     1   5 use warnings;
  1         2  
  1         25  
5              
6 1     1   452 use GD;
  0            
  0            
7             use GD::Graph::smoothlines;
8              
9             use GD::Graph::colour qw(:colours);
10             use GD::Graph::utils qw(:all);
11              
12             @GD::Graph::smootharea::ISA = qw( GD::Graph::smoothlines );
13              
14             use vars qw($VERSION);
15             $VERSION = '1.6';
16              
17             sub enableGradient {
18             $_[0]->{_enableGradient} = $_[1] if ( defined $_[1] );
19             return exists $_[0]->{_enableGradient} ? $_[0]->{_enableGradient} : 0;
20             }
21             sub gradientStartColor {
22             $_[0]->{_gradientStartColor} = $_[1] if ( defined $_[1] );
23             return exists $_[0]->{_gradientStartColor} ? $_[0]->{_gradientStartColor} : 'white';
24             }
25             sub gradientEndColor {
26             $_[0]->{_gradientEndColor} = $_[1] if ( defined $_[1] );
27             return exists $_[0]->{_gradientEndColor} ? $_[0]->{_gradientEndColor} : 'green';
28             }
29              
30             sub draw_data_set
31             {
32             my $self = shift;
33             my $ds = shift;
34            
35             my @values = $self->{_data}->y_values( $ds ) or
36             return $self->_set_error( "Impossible illegal data set: $ds", $self->{_data}->error )
37             ;
38            
39             # Select a data colour
40             my $dsci = $self->set_clr( $self->pick_data_clr( $ds ) );
41             my $brci = $self->set_clr( $self->pick_border_clr( $ds ));
42            
43             # Create a new polygon
44             my $poly = GD::Polygon->new();
45            
46             my ( @top, @bottom );
47            
48             # Add the data points
49             for ( my $i = 0; $i < @values; $i++ )
50             {
51             my $value = $values[$i];
52             next unless defined $value;
53            
54             my $bottom = $self->_get_bottom( $ds, $i );
55             $value = $self->{_data}->get_y_cumulative( $ds, $ i)
56             if $self->{cumulate}
57             ;
58            
59             my ( $x, $y ) = $self->val_to_pixel( $i + 1, $value, $ds );
60             push @top, [$x, $y];
61             # Need to keep track of this stuff for hotspots, and because
62             # it's the only reliable way of closing the polygon, without
63             # making odd assumptions.
64             push @bottom, [$x, $bottom];
65            
66             # Hotspot stuff
67             # XXX needs fixing. Not used at the moment.
68             next unless defined $self->{_hotspots}->[$ds]->[$i];
69             if ( $i == 0 )
70             {
71             $self->{_hotspots}->[$ds]->[$i] = ["poly",
72             $x, $y,
73             $x , $bottom,
74             $x - 1, $bottom,
75             $x - 1, $y,
76             $x, $y
77             ];
78             }
79             else
80             {
81             $self->{_hotspots}->[$ds]->[$i] = ["poly",
82             $poly->getPt($i),
83             @{$bottom[$i]},
84             @{$bottom[$i-1]},
85             $poly->getPt($i-1),
86             $poly->getPt($i)
87             ];
88             }
89             }
90            
91             my @_points = @top;
92            
93             # little stupid, but this is the interface
94             @_points = map { { x => $_->[0], y => $_->[1] } } @_points;
95             @_points = @{ $self->_getPoints( $ds, \@_points, 1 ) };
96             @_points = map { [ $_->{x}, $_->{y} ] } @_points;
97            
98             foreach my $pair ( @_points, reverse @bottom ) {
99             $poly->addPt( @$pair );
100             }
101            
102             if ( $self->enableGradient )
103             {
104             my $min_bottom = $bottom[0]->[1];
105             my $max_bottom = $_points[0]->[1];
106             for ( @_points ) {
107             $max_bottom = $_->[1] if ( $_->[1] < $max_bottom );
108             }
109             my $image = $self->FillGradient(
110             $self->IMAGE_GRAPH_GRAD_VERTICAL,
111             $self->color_to_int( $self->gradientStartColor ),
112             $self->color_to_int( $self->gradientEndColor ),
113             int ( $min_bottom - $max_bottom )
114             );
115            
116             my $last_w;
117             for ( @_points ) {
118             $self->{graph}->copy(
119             $image,
120             $_->[0] , $_->[1],
121             0 , $_->[1] - $max_bottom ,
122             defined $last_w ? int($_->[0] - $last_w + 1): $image->width,$min_bottom - $_->[1],
123             );
124             # $last_w = $_->[0];
125             }
126             $self->{graph}->polygon($poly, $brci)
127             if defined $brci;
128             # undef $dsci;
129             # undef $brci;
130             } else {
131             # Draw a filled and a line polygon
132             $self->{graph}->filledPolygon( $poly, $dsci )
133             if defined $dsci;
134             $self->{graph}->polygon( $poly, $brci )
135             if defined $brci;
136             }
137            
138             # Draw the accent lines
139             if ( defined $brci &&
140             ( $self->{right} - $self->{left} ) / @values > $self->{accent_treshold}
141             ) {
142             for my $i ( 0 .. $#top ) {
143             my ($x, $y) = @{$top[$i]};
144             my $bottom = $bottom[$i]->[1];
145             $self->{graph}->dashedLine( $x, $y, $x, $bottom, $brci );
146             }
147             }
148            
149             return $ds
150             }
151              
152             # used only for gradient option
153             sub color_to_int
154             {
155             my $self = shift;
156             my ( $r, $g, $b ) = _rgb( shift );
157             return $r * ( 256 ** 2 ) + $g * ( 256 ) + $b;
158             }
159              
160             use GD::Image;
161             use GD::Polygon;
162              
163             sub IMAGE_GRAPH_GRAD_HORIZONTAL { 'IMAGE_GRAPH_GRAD_HORIZONTAL' }
164             sub IMAGE_GRAPH_GRAD_VERTICAL { 'IMAGE_GRAPH_GRAD_VERTICAL' }
165             sub IMAGE_GRAPH_GRAD_HORIZONTAL_MIRRORED { 'IMAGE_GRAPH_GRAD_HORIZONTAL_MIRRORED' }
166             sub IMAGE_GRAPH_GRAD_VERTICAL_MIRRORED { 'IMAGE_GRAPH_GRAD_VERTICAL_MIRRORED' }
167             sub IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR { 'IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR' }
168             sub IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR { 'IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR' }
169             sub IMAGE_GRAPH_GRAD_RADIAL { 'IMAGE_GRAPH_GRAD_RADIAL' }
170              
171             sub FillGradient
172             {
173             my $self = shift;
174             my ( $direction, $startColor, $endColor, $count, $alpha ) = @_;
175             $count = 100 unless ( defined $count );
176             $alpha = 0 unless ( defined $alpha );
177            
178             my $this = $self->{FillGradient} = {};
179            
180             $this->{_direction} = $direction;
181              
182             $this->{_startColor}->{RED} = ($startColor >> 16) & 0xff;
183             $this->{_startColor}->{GREEN} = ($startColor >> 8 ) & 0xff;
184             $this->{_startColor}->{BLUE} = ($startColor ) & 0xff;
185            
186             $this->{_endColor}->{RED} = ($endColor >> 16) & 0xff;
187             $this->{_endColor}->{GREEN} = ($endColor >> 8 ) & 0xff;
188             $this->{_endColor}->{BLUE} = ($endColor ) & 0xff;
189            
190             $this->{_count} = $count;
191            
192             my ( $width, $height );
193             if ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_HORIZONTAL ) {
194             $width = $this->{_count};
195             $height = 1;
196             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_VERTICAL ) {
197             $width = 1;
198             $height = $this->{_count};
199             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_HORIZONTAL_MIRRORED ) {
200             $width = 2 * $this->{_count};
201             $height = 1;
202             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_VERTICAL_MIRRORED ) {
203             $width = 1;
204             $height = 2 * $this->{_count};
205             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR || $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR ) {
206             $width = $height = $this->{_count} / 2;
207             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_RADIAL ) {
208             $width = $height = sqrt($this->{_count} * $this->{_count} / 2);
209             }
210            
211             $this->{_image} = GD::Image->newTrueColor( $width, $height );
212            
213             my $redIncrement = ($this->{_endColor}->{RED} - $this->{_startColor}->{RED} ) / $this->{_count};
214             my $greenIncrement = ($this->{_endColor}->{GREEN} - $this->{_startColor}->{GREEN}) / $this->{_count};
215             my $blueIncrement = ($this->{_endColor}->{BLUE} - $this->{_startColor}->{BLUE} ) / $this->{_count};
216            
217             for ( my $i = 0; $i <= $this->{_count}; $i++ ) {
218             my ( $red, $green, $blue );
219             if ($i == 0) {
220             $red = $this->{_startColor}->{RED};
221             $green = $this->{_startColor}->{GREEN};
222             $blue = $this->{_startColor}->{BLUE};
223             } else {
224             $red = int(($redIncrement * $i) + $redIncrement + $this->{_startColor}->{RED});
225             $green = int(($greenIncrement * $i) + $greenIncrement + $this->{_startColor}->{GREEN});
226             $blue = int(($blueIncrement * $i) + $blueIncrement + $this->{_startColor}->{BLUE});
227             }
228             my $color = $this->{_image}->colorAllocateAlpha( $red, $green, $blue, $alpha );
229             #warn "$red, $green, $blue => $color";
230            
231             if ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_HORIZONTAL ) {
232             $this->{_image}->setPixel( $i, 0, $color );
233             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_VERTICAL ) {
234             $this->{_image}->setPixel( 0, $height - $i, $color );
235             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_HORIZONTAL_MIRRORED ) {
236             $this->{_image}->setPixel( $i, 0, $color );
237             $this->{_image}->setPixel( $width - $i, 0, $color );
238             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_VERTICAL_MIRRORED ) {
239             $this->{_image}->setPixel( 0, $i, $color );
240             $this->{_image}->setPixel( 0, $height - $i, $color );
241             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR || $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR ) {
242             my $polygon = new GD::Polygon;
243             if ($i > $width) {
244             $polygon->addPt( $width, $i - $width );
245             $polygon->addPt( $width, $height );
246             $polygon->addPt( $i - $width, $height );
247             } else {
248             $polygon->addPt( 0, $i );
249             $polygon->addPt( 0, $height );
250             $polygon->addPt( $width, $height );
251             $polygon->addPt( $width, 0 );
252             $polygon->addPt( $i, 0 );
253             }
254             $this->{_image}->filledPolygon( $polygon, $color );
255             } elsif ( $this->{_direction} eq $self->IMAGE_GRAPH_GRAD_RADIAL ) {
256             if ( $i < $this->{_count} ) {
257             $this->{_image}->filledEllipse( $width / 2, $height / 2, $this->{_count} - $i, $this->{_count} - $i, $color );
258             }
259             }
260             }
261            
262             return $this->{_image};
263             }
264              
265             1;
266              
267             __END__