File Coverage

blib/lib/Chart/Bars.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             ## @file
2             # Implementation of Chart::Bars
3             #
4             # written by
5             # @author david bonner (dbonner@cs.bu.edu)
6             #
7             # maintained by the
8             # @author Chart Group at Geodetic Fundamental Station Wettzell (Chart@fs.wettzell.de)
9             # @date 2015-03-01
10             # @version 2.4.10
11              
12             ## @class Chart::Bars
13             # Bars class provides all functions which are specific to
14             # vertical bars
15             package Chart::Bars;
16              
17 11     11   17252 use Chart::Base '2.4.10';
  0            
  0            
18             use GD;
19             use Carp;
20              
21             use strict;
22              
23             @Chart::Bars::ISA = qw(Chart::Base);
24             $Chart::Bars::VERSION = '2.4.10';
25              
26             #>>>>>>>>>>>>>>>>>>>>>>>>>>#
27             # public methods go here #
28             #<<<<<<<<<<<<<<<<<<<<<<<<<<#
29              
30             #>>>>>>>>>>>>>>>>>>>>>>>>>>>#
31             # private methods go here #
32             #<<<<<<<<<<<<<<<<<<<<<<<<<<<#
33              
34             ## @method private _draw_data
35             # @brief
36             # finally get around to plotting the data for (vertical) bars
37             #
38             # @details
39             # The user may define the kind of labelling the data by setting\n
40             # 'label_values' to 'value' if she wants to have the absolut values\n
41             # 'label_values' to 'none' if she wants to have no values (default)\n
42             #
43             sub _draw_data
44             {
45             my $self = shift;
46              
47             my $data = $self->{'dataref'};
48             my $misccolor = $self->_color_role_to_index('misc');
49             my ( $x1, $x2, $x3, $y1, $y2, $y3 );
50             my ( $width, $height, $delta1, $delta2, $map, $mod, $cut, $pink );
51             my ( $i, $j, $color );
52             my $temp = 0;
53             my $font = $self->{'legend_font'};
54             my $fontW = $self->{'legend_font'}->width;
55             my $fontH = $self->{'legend_font'}->height;
56             my $textcolor = $self->_color_role_to_index('text');
57              
58             # init the imagemap data field if they wanted it
59             if ( $self->true( $self->{'imagemap'} ) )
60             {
61             $self->{'imagemap_data'} = [];
62             }
63              
64             # find the longest label
65             # first we need the length of the values
66             # draw the bars
67             my $max_label_len = 0;
68             for $i ( 1 .. $self->{'num_datasets'} )
69             {
70             for $j ( 0 .. $self->{'num_datapoints'} )
71             {
72              
73             # don't try to draw anything if there's no data
74             if ( defined( $data->[$i][$j] )
75             && $data->[$i][$j] =~ /^[\-\+]{0,1}\s*[\d\.eE\-\+]+/ )
76             {
77             if ( defined $self->{'label_values'} && $self->{'label_values'} =~ /^value$/i )
78             {
79             my $label = sprintf( "%.2f", $data->[$i][$j] );
80             my $label_length = length($label);
81             $max_label_len = $label_length if ( $max_label_len < $label_length );
82             }
83             }
84             }
85             }
86             $max_label_len *= $fontH;
87              
88             # find both delta values ($delta1 for stepping between different
89             # datapoint names, $delta2 for stepping between datasets for that
90             # point) and the mapping constant
91             $width = $self->{'curr_x_max'} - $self->{'curr_x_min'};
92             $height = $self->{'curr_y_max'} - $self->{'curr_y_min'};
93             $delta1 =
94             ( $self->{'num_datapoints'} > 0 )
95             ? $width / ( $self->{'num_datapoints'} * 1 )
96             : $width;
97              
98             $map =
99             ( ( $self->{'max_val'} - $self->{'min_val'} ) > 0 )
100             ? $height / ( $self->{'max_val'} - $self->{'min_val'} )
101             : $height;
102              
103             if ( $self->true( $self->{'spaced_bars'} ) )
104             {
105              
106             #OLD: $delta2 = $delta1 / ($self->{'num_datasets'} + 2);
107             $delta2 =
108             ( ( $self->{'num_datasets'} + 2 ) > 0 )
109             ? $delta1 / ( $self->{'num_datasets'} + 2 )
110             : $delta1;
111             }
112             else
113             {
114             $delta2 =
115             ( $self->{'num_datasets'} > 0 )
116             ? $delta1 / $self->{'num_datasets'}
117             : $delta1;
118             }
119              
120             # get the base x-y values
121             $x1 = $self->{'curr_x_min'};
122              
123             if ( $self->{'min_val'} >= 0 )
124             {
125             $y1 = $self->{'curr_y_max'};
126             $mod = $self->{'min_val'};
127             }
128             elsif ( $self->{'max_val'} <= 0 )
129             {
130             $y1 = $self->{'curr_y_min'};
131             $mod = $self->{'max_val'};
132             }
133             else
134             {
135             $y1 = $self->{'curr_y_min'} + ( $map * $self->{'max_val'} );
136             $mod = 0;
137             $self->{'gd_obj'}->line( $self->{'curr_x_min'}, $y1, $self->{'curr_x_max'}, $y1, $misccolor );
138             }
139              
140             # draw the bars
141             for $i ( 1 .. $self->{'num_datasets'} )
142             {
143              
144             # get the color for this dataset
145             $color = $self->_color_role_to_index( 'dataset' . ( $i - 1 ) );
146              
147             # draw every bar for this dataset
148             for $j ( 0 .. $self->{'num_datapoints'} )
149             {
150              
151             # don't try to draw anything if there's no data
152             if ( defined( $data->[$i][$j] )
153             && $data->[$i][$j] =~ /^[\-\+]{0,1}\s*[\d\.eE\-\+]+/ )
154             {
155              
156             # find the bounds of the rectangle
157             if ( $self->true( $self->{'spaced_bars'} ) )
158             {
159             $x2 = ( $x1 + ( $j * $delta1 ) + ( $i * $delta2 ) );
160             }
161             else
162             {
163             $x2 = $x1 + ( $j * $delta1 ) + ( ( $i - 1 ) * $delta2 );
164             }
165             $y2 = $y1;
166             $x3 = $x2 + $delta2;
167             $y3 = $y1 - ( ( $data->[$i][$j] - $mod ) * $map );
168              
169             # cut the bars off, if needed
170             if ( $data->[$i][$j] > $self->{'max_val'} )
171             {
172             $y3 = $y1 - ( ( $self->{'max_val'} - $mod ) * $map );
173             $cut = 1;
174             }
175             elsif ( $data->[$i][$j] < $self->{'min_val'} )
176             {
177             $y3 = $y1 - ( ( $self->{'min_val'} - $mod ) * $map );
178             $cut = 1;
179             }
180             else
181             {
182             $cut = 0;
183             }
184              
185             # draw the bar
186             ## y2 and y3 are reversed in some cases because GD's fill
187             ## algorithm is lame
188             if ( $data->[$i][$j] > 0 )
189             {
190             $self->{'gd_obj'}->filledRectangle( $x2, $y3, $x3, $y2, $color );
191             if ( $self->true( $self->{'imagemap'} ) )
192             {
193             $self->{'imagemap_data'}->[$i][$j] = [ $x2, $y3, $x3, $y2 ];
194             }
195              
196             if ( defined $self->{'label_values'} && $self->{'label_values'} =~ /^value$/i )
197             {
198              
199             # draw data
200             my $labelX = $x2;
201             my $labelY = $y3 + $fontH; #$max_label_len;
202             if ( $labelY < 0 ) { $labelY = $y3; }
203             my $label = sprintf( "%.2f", $data->[$i][$j] );
204             $self->{'gd_obj'}->stringUp( $font, $labelX + $fontW * 0.5, $labelY, $label, $textcolor );
205             }
206              
207             }
208             else
209             {
210             $self->{'gd_obj'}->filledRectangle( $x2, $y2, $x3, $y3, $color );
211             if ( $self->true( $self->{'imagemap'} ) )
212             {
213             $self->{'imagemap_data'}->[$i][$j] = [ $x2, $y2, $x3, $y3 ];
214             }
215             }
216              
217             # now outline it. outline red if the bar had been cut off
218             unless ($cut)
219             {
220             $self->{'gd_obj'}->rectangle( $x2, $y3, $x3, $y2, $misccolor );
221             }
222             else
223             {
224             $pink = $self->{'gd_obj'}->colorAllocate( 255, 0, 255 );
225             $self->{'gd_obj'}->rectangle( $x2, $y3, $x3, $y2, $pink );
226             }
227              
228             }
229             else
230             {
231             if ( $self->true( $self->{'imagemap'} ) )
232             {
233             $self->{'imagemap_data'}->[$i][$j] = [ undef(), undef(), undef(), undef() ];
234             }
235             }
236             }
237             }
238              
239             # and finaly box it off
240             $self->{'gd_obj'}
241             ->rectangle( $self->{'curr_x_min'}, $self->{'curr_y_min'}, $self->{'curr_x_max'}, $self->{'curr_y_max'}, $misccolor );
242             return;
243              
244             }
245              
246             ## be a good module and return 1
247             1;