File Coverage

blib/lib/Chart/Lines.pm
Criterion Covered Total %
statement 120 129 93.0
branch 34 46 73.9
condition 9 21 42.9
subroutine 6 6 100.0
pod n/a
total 169 202 83.7


line stmt bran cond sub pod time code
1             #====================================================================
2             # Chart::Lines
3             #
4             # written by david bonner
5             # dbonner@cs.bu.edu
6             #
7             # maintained by the Chart Group
8             # Chart@wettzell.ifag.de
9             #
10             #---------------------------------------------------------------------
11             # History:
12             #----------
13             # $RCSfile: Lines.pm,v $ $Revision: 1.4 $ $Date: 2003/02/14 14:08:24 $
14             # $Author: dassing $
15             # $Log: Lines.pm,v $
16             # Revision 1.4 2003/02/14 14:08:24 dassing
17             # First setup to cvs
18             #
19             #====================================================================
20              
21             package Chart::Lines;
22              
23 11     11   1188 use Chart::Base 2.3;
  11         338  
  11         248  
24 11     11   321 use GD;
  11         106  
  11         194  
25 11     11   196 use Carp;
  11         106  
  11         180  
26 11     11   165 use strict;
  11         100  
  11         158  
27              
28             @Chart::Lines::ISA = qw(Chart::Base);
29             $Chart::Lines::VERSION = '2.3';
30              
31             #>>>>>>>>>>>>>>>>>>>>>>>>>>#
32             # public methods go here #
33             #<<<<<<<<<<<<<<<<<<<<<<<<<<#
34              
35              
36              
37             #>>>>>>>>>>>>>>>>>>>>>>>>>>>#
38             # private methods go here #
39             #<<<<<<<<<<<<<<<<<<<<<<<<<<<#
40              
41             ## finally get around to plotting the data
42             sub _draw_data {
43 11     11   110   my $self = shift;
44 11         115   my $data = $self->{'dataref'};
45 11         149   my $misccolor = $self->_color_role_to_index('misc');
46 11         134   my ($x1, $x2, $x3, $y1, $y2, $y3, $mod, $abs_x_max, $abs_y_max, $tan_alpha);
47 11         108   my ($width, $height, $delta, $delta_num, $map, $t_x_min, $t_x_max, $t_y_min, $t_y_max);
48 11         135   my ($i, $j, $color, $brush, $zero_offset);
49 11         133   my $repair_top_flag = 0;
50 11         99   my $repair_bottom_flag = 0;
51              
52             # init the imagemap data field if they asked for it
53 11 100       149   if ($self->{'imagemap'} =~ /^true$/i) {
54 1         11     $self->{'imagemap_data'} = [];
55               }
56              
57             # find the delta value between data points, as well
58             # as the mapping constant
59 11         118   $width = $self->{'curr_x_max'} - $self->{'curr_x_min'};
60 11         835   $height = $self->{'curr_y_max'} - $self->{'curr_y_min'};
61 11 50       181   $delta = $width / ($self->{'num_datapoints'} > 0 ? $self->{'num_datapoints'} : 1);
62 11         126   $map = $height / ($self->{'max_val'} - $self->{'min_val'});
63              
64             #for a xy-plot, use this delta and maybe an offset for the zero-axes
65 11 100       502   if ($self->{'xy_plot'} =~ /^true$/i ) {
66 1         11     $delta_num = $width / ($self->{'x_max_val'} - $self->{'x_min_val'});
67              
68 1 50 33     18     if ($self->{'x_min_val'} <= 0 && $self->{'x_max_val'} >= 0) {
    0 0        
69 1         12        $zero_offset = abs($self->{'x_min_val'}) * abs($delta_num);
70                 }
71                 elsif ($self->{'x_min_val'} > 0 || $self->{'x_max_val'} < 0) {
72 0         0        $zero_offset = -$self->{'x_min_val'} * $delta_num;
73                 }
74                 else {
75 0         0        $zero_offset = 0;
76                 }
77               }
78               
79             # get the base x-y values
80 11 100       193   if ($self->{'xy_plot'} =~ /^true$/i ) {
81 1         10     $x1 = $self->{'curr_x_min'};
82               }
83               else {
84 10         122     $x1 = $self->{'curr_x_min'} + ($delta / 2);
85               }
86 11 100       194   if ($self->{'min_val'} >= 0 ) {
    50          
87 4         40     $y1 = $self->{'curr_y_max'};
88 4         41     $mod = $self->{'min_val'};
89               }
90               elsif ($self->{'max_val'} <= 0) {
91 0         0     $y1 = $self->{'curr_y_min'};
92 0         0     $mod = $self->{'max_val'};
93               }
94               else {
95 7         130     $y1 = $self->{'curr_y_min'} + ($map * $self->{'max_val'});
96 7         64     $mod = 0;
97 7         183     $self->{'gd_obj'}->line ($self->{'curr_x_min'}, $y1,
98                                          $self->{'curr_x_max'}, $y1,
99                                          $misccolor);
100               }
101              
102             # draw the lines
103 11         124   for $i (1..$self->{'num_datasets'}) {
104             # get the color for this dataset, and set the brush
105 27         418     $color = $self->_color_role_to_index('dataset'.($i-1));
106 27         329     $brush = $self->_prepare_brush ($color);
107 27         706     $self->{'gd_obj'}->setBrush ($brush);
108                 
109             # draw every line for this dataset
110 27         294     for $j (1..$self->{'num_datapoints'}) {
111             # don't try to draw anything if there's no data
112 1692 100 66     28450       if (defined ($data->[$i][$j]) and defined ($data->[$i][$j-1])) {
113 1665 100       22165         if ($self->{'xy_plot'} =~ /^true$/i ) {
114 638         9181            $x2 = $x1 + $delta_num * $data->[0][$j-1] + $zero_offset;
115 638         6788            $x3 = $x1 + $delta_num * $data->[0][$j] + $zero_offset;
116                     }
117                     else {
118 1027         13360            $x2 = $x1 + ($delta * ($j - 1));
119 1027         9233            $x3 = $x1 + ($delta * $j);
120                     }
121 1665         26524 $y2 = $y1 - (($data->[$i][$j-1] - $mod) * $map);
122 1665         19977 $y3 = $y1 - (($data->[$i][$j] - $mod) * $map);
123              
124             # now draw the line
125 1665         28454         $self->{'gd_obj'}->line($x2, $y2, $x3, $y3, gdBrushed);
126                    
127             # set the flags, if the lines are out of the borders of the chart
128 1665 100 100     80601         if ( ($data->[$i][$j] > $self->{'max_val'}) || ($data->[$i][$j-1] > $self->{'max_val'}) ) {
129 51         419            $repair_top_flag = 1;
130                     }
131                     
132 1665 50 0     18192         if ( ($self->{'max_val'} <= 0) &&
      33        
133                          (($data->[$i][$j] > $self->{'max_val'}) || ($data->[$i][$j-1] > $self->{'max_val'})) ) {
134 0         0            $repair_top_flag = 1;
135                     }
136 1665 100 66     50030         if ( ($data->[$i][$j] < $self->{'min_val'}) || ($data->[$i][$j-1] < $self->{'min_val'}) ) {
137 52         425            $repair_bottom_flag = 1;
138                     }
139              
140             # store the imagemap data if they asked for it
141 1665 100       24821 if ($self->{'imagemap'} =~ /^true$/i) {
142 5         60 $self->{'imagemap_data'}->[$i][$j-1] = [ $x2, $y2 ];
143 5         63 $self->{'imagemap_data'}->[$i][$j] = [ $x3, $y3 ];
144             }
145                   } else {
146 27 100       477 if ($self->{'imagemap'} =~ /^true$/i) {
147 1         12 $self->{'imagemap_data'}->[$i][$j-1] = [ undef(), undef() ];
148 1         16 $self->{'imagemap_data'}->[$i][$j] = [ undef(), undef() ];
149                     }
150                   }
151                 }
152               }
153             # and finaly box it off
154 11         703   $self->{'gd_obj'}->rectangle ($self->{'curr_x_min'},
155                $self->{'curr_y_min'},
156             $self->{'curr_x_max'},
157             $self->{'curr_y_max'},
158             $misccolor);
159              
160             #get the width and the heigth of the complete picture
161 11         1222   ($abs_x_max, $abs_y_max) = $self->{'gd_obj'}->getBounds();
162               
163             #repair the chart, if the lines are out of the borders of the chart
164 11 100       139   if ($repair_top_flag) {
165             #overwrite the ugly mistakes
166 1         17    $self->{'gd_obj'}->filledRectangle ($self->{'curr_x_min'}, 0,
167             $self->{'curr_x_max'}, $self->{'curr_y_min'}-1,
168             $self->_color_role_to_index('background'));
169              
170             #save the actual x and y values
171 1         13    $t_x_min = $self->{'curr_x_min'};
172 1         12    $t_x_max = $self->{'curr_x_max'};
173 1         11    $t_y_min = $self->{'curr_y_min'};
174 1         10    $t_y_max = $self->{'curr_y_max'};
175              
176              
177             #get back to the point, where everything began
178 1         10    $self->{'curr_x_min'} = 0;
179 1         9    $self->{'curr_y_min'} = 0;
180 1         10    $self->{'curr_x_max'} = $abs_x_max;
181 1         10    $self->{'curr_y_max'} = $abs_y_max;
182              
183             #draw the title again
184 1 50       14    if ($self->{'title'}) {
185 1         17     $self->_draw_title
186                }
187              
188             #draw the sub title again
189 1 50       13    if ($self->{'sub_title'}) {
190 0         0     $self->_draw_sub_title
191                }
192              
193             #draw the top legend again
194 1 50       13    if ($self->{'legend'} =~ /^top$/i) {
195 0         0     $self->_draw_top_legend;
196                }
197                
198             #reset the actual values
199 1         9    $self->{'curr_x_min'} = $t_x_min;
200 1         10    $self->{'curr_x_max'} = $t_x_max;
201 1         10    $self->{'curr_y_min'} = $t_y_min;
202 1         11    $self->{'curr_y_max'} = $t_y_max;
203               }
204              
205 11 100       126   if ($repair_bottom_flag) {
206              
207             #overwrite the ugly mistakes
208 1         15    $self->{'gd_obj'}->filledRectangle ($self->{'curr_x_min'}, $self->{'curr_y_max'}+1,
209             $self->{'curr_x_max'}, $abs_y_max,
210             $self->_color_role_to_index('background'));
211             #save the actual x and y values
212 1         10    $t_x_min = $self->{'curr_x_min'};
213 1         11    $t_x_max = $self->{'curr_x_max'};
214 1         12    $t_y_min = $self->{'curr_y_min'};
215 1         10    $t_y_max = $self->{'curr_y_max'};
216              
217             #get back to the point, where everything began
218 1         10    $self->{'curr_x_min'} = 0;
219 1         10    $self->{'curr_y_min'} = 0;
220 1         9    $self->{'curr_x_max'} = $abs_x_max;
221 1         11    $self->{'curr_y_max'} = $abs_y_max-1;
222              
223             # mark off the graph_border space
224 1         10    $self->{'curr_y_max'} -= 2* $self->{'graph_border'};
225                
226             #draw the bottom legend again
227 1 50       12    if ($self->{'legend'} =~ /^bottom$/i) {
228 0         0     $self->_draw_bottom_legend;
229                }
230                
231             #draw the x label again
232 1 50       13    if ($self->{'x_label'}) {
233 1         13     $self->_draw_x_label;
234                }
235              
236             #get back to the start point for the ticks
237 1         10    $self->{'curr_x_min'} = $self->{'temp_x_min'};
238 1         11    $self->{'curr_y_min'} = $self->{'temp_y_min'};
239 1         10    $self->{'curr_x_max'} = $self->{'temp_x_max'};
240 1         10    $self->{'curr_y_max'} = $self->{'temp_y_max'};
241                
242             #draw the x ticks again
243 1 50       13    if ($self->{'xy_plot'} =~ /^true$/i) {
244 0         0       $self->_draw_x_number_ticks;
245                }
246                else {
247 1         13       $self->_draw_x_ticks;
248                }
249              
250             #reset the actual values
251 1         10    $self->{'curr_x_min'} = $t_x_min;
252 1         10    $self->{'curr_x_max'} = $t_x_max;
253 1         9    $self->{'curr_y_min'} = $t_y_min;
254 1         10    $self->{'curr_y_max'} = $t_y_max;
255               }
256                 
257 11         280   return;
258              
259             }
260              
261              
262             ## set the gdBrush object to trick GD into drawing fat lines
263             sub _prepare_brush {
264 49     49   875   my $self = shift;
265 49         2288   my $color = shift;
266 49         526   my $radius = $self->{'brush_size'}/2;
267 49         520   my (@rgb, $brush, $white, $newcolor);
268              
269             # get the rgb values for the desired color
270 49         3106   @rgb = $self->{'gd_obj'}->rgb($color);
271              
272             # create the new image
273 49         941   $brush = GD::Image->new ($radius*2, $radius*2);
274              
275             # get the colors, make the background transparent
276 49         6503   $white = $brush->colorAllocate (255,255,255);
277 49         585   $newcolor = $brush->colorAllocate (@rgb);
278 49         655   $brush->transparent ($white);
279              
280             # draw the circle
281 49         2462   $brush->arc ($radius-1, $radius-1, $radius, $radius, 0, 360, $newcolor);
282              
283             # set the new image as the main object's brush
284 49         568   return $brush;
285             }
286              
287             ## be a good module and return 1
288             1;
289