File Coverage

blib/lib/GD/Graph/bars.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             #==========================================================================
2             # Copyright (c) 1995-1998 Martien Verbruggen
3             #--------------------------------------------------------------------------
4             #
5             # Name:
6             # GD::Graph::bars.pm
7             #
8             # $Id: bars.pm,v 1.26 2007/04/26 03:16:09 ben Exp $
9             #
10             #==========================================================================
11            
12             package GD::Graph::bars;
13              
14             ($GD::Graph::bars::VERSION) = '$Revision: 1.26 $' =~ /\s([\d.]+)/;
15              
16 1     1   6 use strict;
  1         1  
  1         46  
17              
18 1     1   710 use GD::Graph::axestype;
  0            
  0            
19             use GD::Graph::utils qw(:all);
20             use GD::Graph::colour qw(:colours);
21              
22             @GD::Graph::bars::ISA = qw(GD::Graph::axestype);
23              
24             use constant PI => 4 * atan2(1,1);
25              
26             sub initialise
27             {
28             my $self = shift;
29             $self->SUPER::initialise();
30             $self->set(correct_width => 1);
31             }
32              
33             sub draw_data
34             {
35             my $self = shift;
36              
37             $self->SUPER::draw_data() or return;
38              
39             unless ($self->{no_axes})
40             {
41             # redraw the 'zero' axis
42             if ($self->{rotate_chart})
43             {
44             $self->{graph}->line(
45             $self->{zeropoint}, $self->{top},
46             $self->{zeropoint}, $self->{bottom},
47             $self->{fgci} );
48             }
49             else
50             {
51             $self->{graph}->line(
52             $self->{left}, $self->{zeropoint},
53             $self->{right}, $self->{zeropoint},
54             $self->{fgci} );
55             }
56             }
57            
58             return $self;
59             }
60              
61             sub _top_values
62             {
63             my $self = shift;
64             my @topvalues;
65              
66             if ($self->{cumulate})
67             {
68             my $data = $self->{_data};
69             for my $i (0 .. $data->num_points - 1)
70             {
71             push @topvalues, $data->get_y_cumulative($data->num_sets, $i);
72             }
73             }
74              
75             return \@topvalues;
76             }
77              
78             #
79             # Draw the shadow
80             #
81             sub _draw_shadow
82             {
83             my $self = shift;
84             my ($ds, $i, $value, $topvalues, $l, $t, $r, $b) = @_;
85             my $bsd = $self->{shadow_depth} or return;
86             my $bsci = $self->set_clr(_rgb($self->{shadowclr}));
87              
88             if ($self->{cumulate})
89             {
90             return if $ds > 1;
91             $value = $topvalues->[$i];
92             if ($self->{rotate_chart})
93             {
94             $r = ($self->val_to_pixel($i + 1, $value, $ds))[0];
95             }
96             else
97             {
98             $t = ($self->val_to_pixel($i + 1, $value, $ds))[1];
99             }
100             }
101              
102             # XXX Clean this up
103             if ($value >= 0)
104             {
105             if ($self->{rotate_chart})
106             {
107             $self->{graph}->filledRectangle(
108             $l, $t + $bsd, $r - $bsd, $b + $bsd, $bsci);
109             }
110             else
111             {
112             $self->{graph}->filledRectangle(
113             $l + $bsd, $t + $bsd, $r + $bsd, $b, $bsci);
114             }
115             }
116             else
117             {
118             if ($self->{rotate_chart})
119             {
120             $self->{graph}->filledRectangle(
121             $l + $bsd, $t, $r + $bsd, $b, $bsci);
122             }
123             else
124             {
125             $self->{graph}->filledRectangle(
126             $l + $bsd, $b, $r + $bsd, $t + $bsd, $bsci);
127             }
128             }
129             }
130              
131             sub draw_data_set_h
132             {
133             my $self = shift;
134             my $ds = shift;
135              
136             my $bar_s = $self->{bar_spacing}/2;
137              
138             # Pick a data colour
139             my $dsci = $self->set_clr($self->pick_data_clr($ds));
140             # contrib "Bremford, Mike"
141             my $brci = $self->set_clr($self->pick_border_clr($ds));
142              
143             my @values = $self->{_data}->y_values($ds) or
144             return $self->_set_error("Impossible illegal data set: $ds",
145             $self->{_data}->error);
146              
147             my $topvalues = $self->_top_values;
148             #
149             # Draw all shadows.
150             for my $i (0 .. $#values)
151             {
152             my $value = $values[$i];
153             next unless defined $value;
154              
155             my $l = $self->_get_bottom($ds, $i);
156             my ($r, $xp) = $self->val_to_pixel($i + 1, $value, $ds);
157              
158             # calculate top and bottom of bar
159             my ($t, $b);
160             my $window = $self->{x_step} - $self->{bargroup_spacing};
161              
162             if (ref $self eq 'GD::Graph::mixed' || $self->{overwrite})
163             {
164             $t = $xp - $window/2 + $bar_s + 1;
165             $b = $xp + $window/2 - $bar_s;
166             }
167             else
168             {
169             $t = $xp
170             - $window/2
171             + ($ds - 1) * $window/$self->{_data}->num_sets
172             + $bar_s + 1; # GRANTM thinks this +1 should be conditional on bargroup_spacing being absent
173             $b = $xp
174             - $window/2
175             + $ds * $window/$self->{_data}->num_sets
176             - $bar_s;
177             }
178              
179             $self->_draw_shadow($ds, $i, $value, $topvalues, $l, $t, $r, $b);
180             }
181              
182             for my $i (0 .. $#values)
183             {
184             my $value = $values[$i];
185             next unless defined $value;
186              
187             my $l = $self->_get_bottom($ds, $i);
188             $value = $self->{_data}->get_y_cumulative($ds, $i)
189             if ($self->{cumulate});
190              
191             # CONTRIB Jeremy Wadsack
192             #
193             # cycle_clrs option sets the color based on the point,
194             # not the dataset.
195             $dsci = $self->set_clr($self->pick_data_clr($i + 1))
196             if $self->{cycle_clrs};
197             $brci = $self->set_clr($self->pick_data_clr($i + 1))
198             if $self->{cycle_clrs} > 1;
199              
200             # get coordinates of right and center of bar
201             my ($r, $xp) = $self->val_to_pixel($i + 1, $value, $ds);
202              
203             # calculate top and bottom of bar
204             my ($t, $b);
205             my $window = $self->{x_step} - $self->{bargroup_spacing};
206              
207             if (ref $self eq 'GD::Graph::mixed' || $self->{overwrite})
208             {
209             $t = $xp - $window/2 + $bar_s + 1;
210             $b = $xp + $window/2 - $bar_s;
211             }
212             else
213             {
214             $t = $xp
215             - $window/2
216             + ($ds - 1) * $window/$self->{_data}->num_sets
217             + $bar_s + 1; # GRANTM thinks this +1 should be conditional on bargroup_spacing being absent
218             $b = $xp
219             - $window/2
220             + $ds * $window/$self->{_data}->num_sets
221             - $bar_s;
222             }
223              
224             # draw the bar
225             if ($value < 0) { ($r,$l) = ($l,$r) }
226              
227             $self->{graph}->filledRectangle($l, $t, $r, $b, $dsci)
228             if defined $dsci;
229             $self->{graph}->rectangle($l, $t, $r, $b, $brci)
230             if defined $brci && $b - $t > $self->{accent_treshold};
231              
232             $self->{_hotspots}->[$ds]->[$i] = ['rect', $l, $t, $r, $b];
233             }
234              
235             return $ds;
236             }
237              
238             sub draw_data_set_v
239             {
240             my $self = shift;
241             my $ds = shift;
242              
243             my $bar_s = $self->{bar_spacing}/2;
244              
245             # Pick a data colour
246             my $dsci = $self->set_clr($self->pick_data_clr($ds));
247             # contrib "Bremford, Mike"
248             my $brci = $self->set_clr($self->pick_border_clr($ds));
249              
250             my @values = $self->{_data}->y_values($ds) or
251             return $self->_set_error("Impossible illegal data set: $ds",
252             $self->{_data}->error);
253              
254             my $topvalues = $self->_top_values;
255              
256             my ($bar_sets,$ds_adj) = ( $self->{_data}->num_sets , $ds );
257             if ( $self->isa( 'GD::Graph::mixed' ) ) {
258             my @types = $self->types;
259             $bar_sets = grep { $_ eq 'bars' } @types;
260             $ds_adj = grep { $_ eq 'bars' } @types[0..$ds-1];
261             }
262              
263             # Draw all shadows.
264             for my $i (0 .. $#values)
265             {
266             my $value = $values[$i];
267             next unless defined $value;
268              
269             my $bottom = $self->_get_bottom($ds, $i);
270             my ($xp, $t) = $self->val_to_pixel($i + 1, $value, $ds);
271             my ($l, $r);
272             my $window = $self->{x_step} - $self->{bargroup_spacing};
273              
274             if ($self->{overwrite})
275             {
276             $l = $xp - $window/2 + $bar_s + 1;
277             $r = $xp + $window/2 - $bar_s;
278             }
279             else
280             {
281             $l = $xp
282             - $window/2
283             + ($ds_adj - 1) * $window/$bar_sets
284             + $bar_s + 1; # GRANTM thinks this +1 should be conditional on bargroup_spacing being absent
285             $r = $xp
286             - $window/2
287             + $ds_adj * $window/$bar_sets
288             - $bar_s;
289             }
290              
291             $self->_draw_shadow($ds, $i, $value, $topvalues, $l, $t, $r, $bottom);
292             }
293              
294             # Then all bars.
295             for my $i (0 .. $#values)
296             {
297             my $value = $values[$i];
298             next unless defined $value;
299              
300             my $bottom = $self->_get_bottom($ds, $i);
301             $value = $self->{_data}->get_y_cumulative($ds, $i)
302             if ($self->{cumulate});
303              
304             # CONTRIB Jeremy Wadsack
305             #
306             # cycle_clrs option sets the color based on the point,
307             # not the dataset.
308             $dsci = $self->set_clr($self->pick_data_clr($i + 1))
309             if $self->{cycle_clrs};
310             $brci = $self->set_clr($self->pick_data_clr($i + 1))
311             if $self->{cycle_clrs} > 1;
312              
313             # get coordinates of top and center of bar
314             my ($xp, $t) = $self->val_to_pixel($i + 1, $value, $ds);
315              
316             # calculate left and right of bar
317             my ($l, $r);
318             my $window = $self->{x_step} - $self->{bargroup_spacing};
319              
320             if ($self->{overwrite})
321             {
322             $l = $xp - $window/2 + $bar_s + 1;
323             $r = $xp + $window/2 - $bar_s;
324             }
325             else
326             {
327             $l = $xp
328             - $window/2
329             + ($ds_adj - 1) * $window/$bar_sets
330             + $bar_s + 1; # GRANTM thinks this +1 should be conditional on bargroup_spacing being absent
331             $r = $xp
332             - $window/2
333             + $ds_adj * $window/$bar_sets
334             - $bar_s;
335             }
336              
337             # draw the bar
338              
339             if ($value < 0) { ($bottom,$t) = ($t,$bottom) }
340             $self->{graph}->filledRectangle($l, $t, $r, $bottom, $dsci)
341             if defined $dsci;
342             $self->{graph}->rectangle($l, $t, $r, $bottom, $brci)
343             if defined $brci && $r - $l > $self->{accent_treshold};
344             $self->{_hotspots}->[$ds]->[$i] = ['rect', $l, $t, $r, $bottom]
345             }
346              
347             return $ds;
348             }
349              
350             sub draw_data_set
351             {
352             $_[0]->{rotate_chart} ? goto &draw_data_set_h : goto &draw_data_set_v;
353             }
354              
355             sub draw_values
356             {
357             my $self = shift;
358              
359             return $self unless $self->{show_values};
360             my $has_args = @_;
361            
362             my $text_angle = $self->{values_vertical} ? PI/2 : 0;
363             my @numPoints = $self->{_data}->num_points();
364             my @datasets = $has_args ? @_ : 1 .. $self->{_data}->num_sets;
365              
366             my ($l, $r, $b, $t) = ($self->{left}, $self->{right}, $self->{bottom}, $self->{top});
367              
368             for my $dsn ( @datasets )
369             { # CONTRIB Romeo Juncu
370             my @values = ();
371             if (!$self->get("cumulate")) {
372             @values = $self->{_data}->y_values($dsn) or
373             return $self->_set_error("Impossible illegal data set: $dsn",
374             $self->{_data}->error);
375             } else {
376             my $nPoints = $numPoints[$dsn] || 0;
377             my $vec = $has_args ? \@datasets : undef;
378             @values = map { $self->{_data}->get_y_cumulative($dsn, $_, $vec) }
379             (0..$nPoints - 1) ;
380             }
381             my @display = $self->{show_values}->y_values($dsn) or next;
382              
383             for (my $i = 0; $i < @values; $i++)
384             {
385             next unless defined $display[$i];
386              
387             my $value = $display[$i];
388             if (defined $self->{values_format})
389             {
390             $value = ref $self->{values_format} eq 'CODE' ?
391             &{$self->{values_format}}($value) :
392             sprintf($self->{values_format}, $value);
393             }
394              
395             my ($xp, $yp);
396             if (defined($self->{x_min_value}) && defined($self->{x_max_value}))
397             {
398             ($xp, $yp) = $self->val_to_pixel(
399             $self->{_data}->get_x($i), $values[$i], $dsn);
400             }
401             else
402             {
403             ($xp, $yp) = $self->val_to_pixel($i+1, $values[$i], $dsn);
404             }
405             if ($self->{rotate_chart})
406             {
407             $xp += $self->{values_space};
408             unless ($self->{overwrite})
409             {
410             $yp -= $self->{x_step}/2 - ($dsn - 0.5)
411             * $self->{x_step}/@datasets;
412             }
413             }
414             else
415             {
416             $yp -= $self->{values_space};
417             unless ($self->{overwrite})
418             {
419             $xp -= $self->{x_step}/2 - ($dsn - 0.5)
420             * $self->{x_step}/@datasets;
421             }
422             }
423              
424             $self->{gdta_values}->set_text($value);
425             if ( $self->{'hide_overlapping_values'} ) {
426             my @bbox = $self->{gdta_values}->bounding_box($xp, $yp, $text_angle);
427             next if grep $_ < $l || $_ > $r, @bbox[0, 2];
428             next if grep $_ < $t || $_ > $b, @bbox[1, 5];
429             }
430             $self->{gdta_values}->draw($xp, $yp, $text_angle);
431             }
432             }
433              
434             return $self
435             }
436              
437             "Just another true value";