File Coverage

blib/lib/GD/Dashboard.pm
Criterion Covered Total %
statement 4 51 7.8
branch 0 6 0.0
condition 0 3 0.0
subroutine 2 12 16.6
pod n/a
total 6 72 8.3


line stmt bran cond sub pod time code
1             package GD::Dashboard;
2            
3 1     1   809 use strict;
  1         2  
  1         831  
4             #use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
5            
6             $GD::Dashboard::VERSION = '0.04';
7            
8            
9             # Preloaded methods go here.
10            
11            
12             #
13             # Constructor options:
14             #
15             # FNAME
16             # QUALITY
17             #
18             sub new
19             {
20 0     0     my $proto = shift;
21            
22 0           my $self = {
23             METERS => {},
24             FNAME => '',
25             QUALITY => 100
26             };
27            
28            
29             # load in options supplied to new()
30 0           for (my $x = 0; $x <= $#_; $x += 2)
31             {
32 0           my $opt = uc($_[$x]);
33            
34 0 0         defined($_[($x + 1)]) or die "Dashboard->new() called with odd number of option parameters - should be of the form option => value";
35 0           $self->{$opt} = $_[($x + 1)];
36             }
37            
38 0           bless($self);
39 0           return $self;
40             }
41            
42             #
43             # There can be many meters on a graphic. To specify them,
44             # you create a new meter, then pass it to this function,
45             # along with its name. All meters will be referred to by
46             # name.
47             #
48             sub add_meter
49             {
50 0     0     my ($self,$name,$meter) = @_;
51 0           $self->{METERS}->{$name} = $meter;
52             }
53            
54             #
55             # Why would you want to use get_meter? A couple of reasons.
56             # First, you might have called add_meter(new Dashboard::Gauge()).
57             # Second, if you have multiple dash layouts, you have probably
58             # written the code so that you don't have access to the original
59             # meter variables at the point where you need to set them.
60             #
61             sub get_meter
62             {
63 0     0     my ($self,$name) = @_;
64 0           $self->{METERS}->{$name};
65             }
66            
67             sub gdimage
68             {
69 0     0     my ($self) = @_;
70 0           my ($aref) = $self->{METERS};
71 0           my $fname = $self->{FNAME};
72            
73 0 0 0       if (!defined($fname) || $fname eq '')
74             {
75 0           warn("GD::Dashboard::gdimage(): You must set FNAME in constructor first!") ;
76 0           return undef;
77             }
78            
79             # Get canvas from specified background graphics
80 0           my $im;
81            
82 0 0         if ($self->{FNAME} =~ /png$/ )
83             {
84 0           $im = GD::Image->newFromPng($self->{FNAME});
85             }
86             else
87             {
88 0           $im = GD::Image->newFromJpeg($self->{FNAME});
89             }
90            
91             # Draw all my meters
92 0           for my $m (keys(%{$aref}))
  0            
93             {
94 0           my $m2 = $aref->{$m};
95 0           $m2->write_gdimagehandle($im);
96             }
97            
98 0           $im;
99             }
100            
101             sub png
102             {
103 0     0     my ($self) = @_;
104            
105 0           my $im = $self->gdimage;
106            
107 0           return $im->png();
108             }
109            
110             sub jpeg
111             {
112 0     0     my ($self) = @_;
113            
114 0           my $im = $self->gdimage;
115            
116 0           return $im->jpeg($self->{QUALITY});
117             }
118            
119             #
120             # Is anything wrong with me using this filehandle (HG1) ?
121             #
122             sub write_jpeg
123             {
124 0     0     my ($self,$fname) = @_;
125            
126 0           open (HG1,'>'.$fname);
127 0           binmode HG1;
128 0           print HG1 $self->jpeg();
129 0           close HG1;
130             }
131            
132             sub write_png
133             {
134 0     0     my ($self,$fname) = @_;
135            
136 0           open (HG1,'>'.$fname);
137 0           binmode HG1;
138 0           print HG1 $self->png();
139 0           close HG1;
140             }
141            
142             package GD::Dashboard::Base;
143            
144             # insert base class for meters here.....
145            
146             # All meters should support:
147             # MIN => 0,
148             # MAX => 100,
149             # VAL => 50,
150             # NX => 0,
151             # NY => 0,
152             # QUALITY => 100,
153            
154             sub jpeg
155 0     0     {
156             }
157            
158             sub write_jpeg
159 0     0     {
160             }
161            
162             package GD::Dashboard::Gauge;
163            
164 1     1   1828 use GD;
  0            
  0            
165            
166            
167             #
168             # Constructor Options
169             #
170             # MIN
171             # MAX
172             # VAL
173             # NX
174             # NY
175             # NLEN
176             # NWIDTH
177             # NA1
178             # NA2
179             # NCOLOR
180             # QUALITY
181             # FNAME
182             # COUNTERCLOCKWISE
183             #
184             sub new
185             {
186             my $proto = shift;
187            
188             my $self = {
189             FNAME => '',
190             MIN => 0,
191             MAX => 100,
192             VAL => 50,
193             NX => 0,
194             NY => 0,
195             NLEN => 0,
196             NWIDTH=>2,
197             NA1=>0,
198             NA2=>0,
199             NCOLOR => [ 0, 0, 255 ],
200             QUALITY => 100,
201             COUNTERCLOCKWISE => 0
202             };
203            
204            
205             # load in options supplied to new()
206             for (my $x = 0; $x <= $#_; $x += 2)
207             {
208             my $opt = uc($_[$x]);
209            
210             defined($_[($x + 1)]) or die "Dashboard::Gauge->new() called with odd number of option parameters - should be of the form option => value";
211             $self->{$opt} = $_[($x + 1)];
212             }
213            
214             bless($self);
215             return $self;
216             }
217            
218             sub write_gdimagehandle
219             {
220             my ($self,$im) = @_;
221             $self->_draw_needle($im);
222             }
223            
224             #sub jpeg
225             #{
226             # my ($self) = @_;
227             #
228             # my $im = GD::Image->newFromJpeg($self->{FNAME});
229             #
230             # $self->write_gdimagehandle($im);
231             #
232             # return $im->jpeg(100);
233             #}
234             #
235             #sub write_jpeg
236             #{
237             # my ($self,$fname) = @_;
238             #
239             # open (HG1,'>'.$fname);
240             # binmode HG1;
241             # print HG1 $self->jpeg();
242             # close HG1;
243             #}
244            
245             sub set_reading
246             {
247             my ($self,$val) = @_;
248            
249             warn "Warning: set_reading called with value less than minimum." if $val < $self->{MIN};
250             warn "Warning: set_reading called with value greater than maximum." if $val > $self->{MAX};
251            
252             $self->{VAL} = $val;
253             }
254            
255            
256             sub _draw_needle
257             {
258             my ($self,$im) = @_;
259             my ($x,$y);
260             my $pi = 3.141592;
261            
262             # Must compute x,y coords for tip of needle.
263             # Angle system for GD is in degrees, 0 is straight up,
264             # and they increase clockwise. Sigh. Angle system
265             # for perl is in radians, 0 is as it is defined
266             # traditionally in math, angles increase counterclockwise.
267             #
268            
269             my $norm = ($self->{VAL}-$self->{MIN}) / ($self->{MAX} - $self->{MIN} );
270             my $angle_width;
271            
272             if ( $self->{NA1} > $self->{NA2} )
273             {
274             if ($self->{COUNTERCLOCKWISE})
275             {
276             $angle_width = (2*$pi) - ($self->{NA1}-$self->{NA2}) ;
277             }
278             else
279             {
280             $angle_width =($self->{NA1}-$self->{NA2}) ;
281             }
282             }
283             else
284             {
285             if ($self->{COUNTERCLOCKWISE})
286             {
287             $angle_width = ($self->{NA2}-$self->{NA1}) ;
288             }
289             else
290             {
291             $angle_width = (2*$pi - ($self->{NA2}-$self->{NA1}) );
292             }
293             }
294            
295             my $angle;
296             if ($self->{COUNTERCLOCKWISE}==1)
297             {
298             $angle = $self->{NA1} + $norm * $angle_width;
299             }
300             else
301             {
302             $angle = $self->{NA1} - $norm * $angle_width;
303             }
304            
305             $x = $self->{NX} + $self->{NLEN} * cos($angle);
306             $y = $self->{NY} - $self->{NLEN} * sin($angle);
307            
308             # To draw a line with a width other than 1, you actually need
309             # to create an image brush. Sigh.
310             #
311             my $brush = _prepare_brush($self->{NWIDTH}, $self->{NCOLOR});
312             $im->setBrush($brush);
313            
314             # draw the needle!
315             #
316             $im->line($self->{NX},$self->{NY},$x,$y,gdBrushed);
317            
318             # how to clean up the brush?
319             }
320            
321            
322            
323             #####################
324             #
325             # Private functions
326             #
327             #####################
328            
329             ## set the gdBrush object to trick GD into drawing fat lines
330             sub _prepare_brush
331             {
332             my ($radius, $ref_color) = @_;
333             my (@rgb, $brush, $white, $newcolor);
334            
335             # get the rgb values for the desired color
336             # @rgb = (0,0,255);
337             # @rgb = (255,0,128);
338             @rgb = @{$ref_color};
339             # create the new image
340             $brush = GD::Image->new ($radius*2, $radius*2);
341            
342             # get the colors, make the background transparent
343             # $white = $brush->colorAllocate (255,255,255);
344             $white = $brush->colorAllocate (0,0,0);
345             $newcolor = $brush->colorAllocate (@rgb);
346             $brush->transparent ($white);
347            
348             # draw the circle
349             $brush->arc ($radius-1, $radius-1, $radius, $radius, 0, 360, $newcolor);
350            
351             # set the new image as the main object's brush
352             return $brush;
353             }
354            
355            
356            
357             package GD::Dashboard::WarningLight;
358            
359             #
360             # TRANSPARENT
361             # NX
362             # NY
363             # FNAME
364             # VAL
365             #
366             sub new
367             {
368             my $proto = shift;
369            
370             my $self = {
371             VAL => 0, # 0=off, 1=on
372             NX => 0,
373             NY => 0,
374             FNAME => ''
375             };
376            
377            
378             # load in options supplied to new()
379             for (my $x = 0; $x <= $#_; $x += 2)
380             {
381             my $opt = uc($_[$x]);
382            
383             defined($_[($x + 1)]) or die "Dashboard::WarningLight->new() called with odd number of option parameters - should be of the form option => value";
384             $self->{$opt} = $_[($x + 1)];
385             }
386            
387             bless($self);
388             return $self;
389             }
390            
391             sub write_gdimagehandle
392             {
393             my ($self,$im) = @_;
394            
395             if ($self->{VAL} == 1)
396             {
397             # load the current image
398             my $im2 = GD::Image->newFromJpeg($self->{FNAME});
399             my ($w,$h) = $im2->getBounds();
400            
401             if (defined($self->{TRANSPARENT}))
402             {
403             my $white = $im2->colorClosest(255,255,255); #TODO this should be a param
404             $im2->transparent($white);
405             }
406             $im->copy($im2,$self->{NX},$self->{NY},0,0,$w,$h);
407             }
408             }
409            
410            
411             sub set_reading
412             {
413             my ($self,$val) = @_;
414            
415             $self->{VAL} = $val;
416             }
417            
418             package GD::Dashboard::HorizontalBar;
419            
420             # Options:
421             # TRANSPARENT = [ r,g,b ]
422             # SPACING = N
423             # MIN
424             # MAX
425             #
426             sub new
427             {
428             my $proto = shift;
429            
430             my $self = {
431             MIN => 0,
432             MAX => 100,
433             VAL => 50,
434             NX => 0,
435             NY => 0,
436             QUALITY => 100,
437             DIRECTION=>0,
438             BARS=>[],
439             SPACING => 0
440             };
441            
442            
443             # load in options supplied to new()
444             for (my $x = 0; $x <= $#_; $x += 2)
445             {
446             my $opt = uc($_[$x]);
447            
448             defined($_[($x + 1)]) or die "Dashboard::HorizontalBar->new() called with odd number of option parameters - should be of the form option => value";
449             $self->{$opt} = $_[($x + 1)];
450             }
451            
452             bless($self);
453             return $self;
454             }
455            
456             sub add_bars
457             {
458             my ($self,$cnt,$fname,$fnameoff) = @_;
459             if (!defined($fnameoff)) { $fnameoff = ''; }
460             push @{$self->{BARS}}, { CNT=>$cnt,FNAME=>$fname,FNAME_OFF=>$fnameoff} ;
461             }
462            
463             sub set_reading
464             {
465             my ($self,$val) = @_;
466            
467             # warn "Warning: set_reading called with value less than minimum." if $val < $self->{MIN};
468             # warn "Warning: set_reading called with value greater than maximum." if $val > $self->{MAX};
469            
470             $self->{VAL} = $val;
471             }
472            
473             sub write_gdimagehandle
474             {
475             my ($self,$im) = @_;
476            
477             # How many bars do we have?
478             my $barcnt = 0;
479             for my $href (@{$self->{BARS}}) { $barcnt += $href->{CNT}; }
480            
481             # How many must we display?
482             my $norm = $self->{VAL} / ($self->{MIN} + $self->{MAX} );
483             my $disp = int ($barcnt * $norm);
484            
485             # OK copy the graphics as necessary
486             my $x = $self->{NX};
487             for my $href (@{$self->{BARS}})
488             {
489             # load the current image
490             my $im2 = GD::Image->newFromJpeg($href->{FNAME});
491            
492             if (defined($self->{TRANSPARENT}))
493             {
494             my $white = $im2->colorClosest(255,255,255); #TODO this should be a param
495             $im2->transparent($white);
496             }
497            
498             my ($w,$h) = $im2->getBounds();
499            
500            
501             my $cnt = $href->{CNT};
502             while ($disp>0 && $cnt>0)
503             {
504             $im->copy($im2,$x,$self->{NY},0,0,$w,$h);
505             $x += $w + $self->{SPACING};
506             $disp--;
507             $barcnt--;
508             $cnt--;
509             }
510            
511             # Now load up dark image and use it if necessary
512             my $fn2 = $href->{FNAME_OFF};
513             if (defined($fn2) && $fn2 ne '')
514             {
515             my $im3 = GD::Image->newFromJpeg($fn2);
516            
517             if (defined($self->{TRANSPARENT}))
518             {
519             my $wt = $im2->colorClosest(255,255,255); #TODO this should be a param
520             $im3->transparent($wt);
521             }
522             my ($w,$h) = $im2->getBounds();
523            
524             while ($cnt>0)
525             {
526             $im->copy($im3,$x,$self->{NY},0,0,$w,$h);
527             $x += $w + $self->{SPACING};
528             $cnt--;
529             }
530             }
531             }
532            
533            
534             }
535            
536            
537            
538            
539            
540             # Autoload methods go after =cut, and are processed by the autosplit program.
541            
542             1;
543             __END__