Tryag File Manager
Home
-
Turbo Force
Current Path :
/
proc
/
self
/
root
/
usr
/
lib
/
perl5
/
vendor_perl
/
5.8.8
/
GD
/
Upload File :
New :
File
Dir
//proc/self/root/usr/lib/perl5/vendor_perl/5.8.8/GD/Dashboard.pm
package GD::Dashboard; use strict; #use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); $GD::Dashboard::VERSION = '0.04'; # Preloaded methods go here. # # Constructor options: # # FNAME # QUALITY # sub new { my $proto = shift; my $self = { METERS => {}, FNAME => '', QUALITY => 100 }; # load in options supplied to new() for (my $x = 0; $x <= $#_; $x += 2) { my $opt = uc($_[$x]); defined($_[($x + 1)]) or die "Dashboard->new() called with odd number of option parameters - should be of the form option => value"; $self->{$opt} = $_[($x + 1)]; } bless($self); return $self; } # # There can be many meters on a graphic. To specify them, # you create a new meter, then pass it to this function, # along with its name. All meters will be referred to by # name. # sub add_meter { my ($self,$name,$meter) = @_; $self->{METERS}->{$name} = $meter; } # # Why would you want to use get_meter? A couple of reasons. # First, you might have called add_meter(new Dashboard::Gauge()). # Second, if you have multiple dash layouts, you have probably # written the code so that you don't have access to the original # meter variables at the point where you need to set them. # sub get_meter { my ($self,$name) = @_; $self->{METERS}->{$name}; } sub gdimage { my ($self) = @_; my ($aref) = $self->{METERS}; my $fname = $self->{FNAME}; if (!defined($fname) || $fname eq '') { warn("GD::Dashboard::gdimage(): You must set FNAME in constructor first!") ; return undef; } # Get canvas from specified background graphics my $im; if ($self->{FNAME} =~ /png$/ ) { $im = GD::Image->newFromPng($self->{FNAME}); } else { $im = GD::Image->newFromJpeg($self->{FNAME}); } # Draw all my meters for my $m (keys(%{$aref})) { my $m2 = $aref->{$m}; $m2->write_gdimagehandle($im); } $im; } sub png { my ($self) = @_; my $im = $self->gdimage; return $im->png(); } sub jpeg { my ($self) = @_; my $im = $self->gdimage; return $im->jpeg($self->{QUALITY}); } # # Is anything wrong with me using this filehandle (HG1) ? # sub write_jpeg { my ($self,$fname) = @_; open (HG1,'>'.$fname); binmode HG1; print HG1 $self->jpeg(); close HG1; } sub write_png { my ($self,$fname) = @_; open (HG1,'>'.$fname); binmode HG1; print HG1 $self->png(); close HG1; } package GD::Dashboard::Base; # insert base class for meters here..... # All meters should support: # MIN => 0, # MAX => 100, # VAL => 50, # NX => 0, # NY => 0, # QUALITY => 100, sub jpeg { } sub write_jpeg { } package GD::Dashboard::Gauge; use GD; # # Constructor Options # # MIN # MAX # VAL # NX # NY # NLEN # NWIDTH # NA1 # NA2 # NCOLOR # QUALITY # FNAME # COUNTERCLOCKWISE # sub new { my $proto = shift; my $self = { FNAME => '', MIN => 0, MAX => 100, VAL => 50, NX => 0, NY => 0, NLEN => 0, NWIDTH=>2, NA1=>0, NA2=>0, NCOLOR => [ 0, 0, 255 ], QUALITY => 100, COUNTERCLOCKWISE => 0 }; # load in options supplied to new() for (my $x = 0; $x <= $#_; $x += 2) { my $opt = uc($_[$x]); defined($_[($x + 1)]) or die "Dashboard::Gauge->new() called with odd number of option parameters - should be of the form option => value"; $self->{$opt} = $_[($x + 1)]; } bless($self); return $self; } sub write_gdimagehandle { my ($self,$im) = @_; $self->_draw_needle($im); } #sub jpeg #{ # my ($self) = @_; # # my $im = GD::Image->newFromJpeg($self->{FNAME}); # # $self->write_gdimagehandle($im); # # return $im->jpeg(100); #} # #sub write_jpeg #{ # my ($self,$fname) = @_; # # open (HG1,'>'.$fname); # binmode HG1; # print HG1 $self->jpeg(); # close HG1; #} sub set_reading { my ($self,$val) = @_; warn "Warning: set_reading called with value less than minimum." if $val < $self->{MIN}; warn "Warning: set_reading called with value greater than maximum." if $val > $self->{MAX}; $self->{VAL} = $val; } sub _draw_needle { my ($self,$im) = @_; my ($x,$y); my $pi = 3.141592; # Must compute x,y coords for tip of needle. # Angle system for GD is in degrees, 0 is straight up, # and they increase clockwise. Sigh. Angle system # for perl is in radians, 0 is as it is defined # traditionally in math, angles increase counterclockwise. # my $norm = ($self->{VAL}-$self->{MIN}) / ($self->{MAX} - $self->{MIN} ); my $angle_width; if ( $self->{NA1} > $self->{NA2} ) { if ($self->{COUNTERCLOCKWISE}) { $angle_width = (2*$pi) - ($self->{NA1}-$self->{NA2}) ; } else { $angle_width =($self->{NA1}-$self->{NA2}) ; } } else { if ($self->{COUNTERCLOCKWISE}) { $angle_width = ($self->{NA2}-$self->{NA1}) ; } else { $angle_width = (2*$pi - ($self->{NA2}-$self->{NA1}) ); } } my $angle; if ($self->{COUNTERCLOCKWISE}==1) { $angle = $self->{NA1} + $norm * $angle_width; } else { $angle = $self->{NA1} - $norm * $angle_width; } $x = $self->{NX} + $self->{NLEN} * cos($angle); $y = $self->{NY} - $self->{NLEN} * sin($angle); # To draw a line with a width other than 1, you actually need # to create an image brush. Sigh. # my $brush = _prepare_brush($self->{NWIDTH}, $self->{NCOLOR}); $im->setBrush($brush); # draw the needle! # $im->line($self->{NX},$self->{NY},$x,$y,gdBrushed); # how to clean up the brush? } ##################### # # Private functions # ##################### ## set the gdBrush object to trick GD into drawing fat lines sub _prepare_brush { my ($radius, $ref_color) = @_; my (@rgb, $brush, $white, $newcolor); # get the rgb values for the desired color # @rgb = (0,0,255); # @rgb = (255,0,128); @rgb = @{$ref_color}; # create the new image $brush = GD::Image->new ($radius*2, $radius*2); # get the colors, make the background transparent # $white = $brush->colorAllocate (255,255,255); $white = $brush->colorAllocate (0,0,0); $newcolor = $brush->colorAllocate (@rgb); $brush->transparent ($white); # draw the circle $brush->arc ($radius-1, $radius-1, $radius, $radius, 0, 360, $newcolor); # set the new image as the main object's brush return $brush; } package GD::Dashboard::WarningLight; # # TRANSPARENT # NX # NY # FNAME # VAL # sub new { my $proto = shift; my $self = { VAL => 0, # 0=off, 1=on NX => 0, NY => 0, FNAME => '' }; # load in options supplied to new() for (my $x = 0; $x <= $#_; $x += 2) { my $opt = uc($_[$x]); defined($_[($x + 1)]) or die "Dashboard::WarningLight->new() called with odd number of option parameters - should be of the form option => value"; $self->{$opt} = $_[($x + 1)]; } bless($self); return $self; } sub write_gdimagehandle { my ($self,$im) = @_; if ($self->{VAL} == 1) { # load the current image my $im2 = GD::Image->newFromJpeg($self->{FNAME}); my ($w,$h) = $im2->getBounds(); if (defined($self->{TRANSPARENT})) { my $white = $im2->colorClosest(255,255,255); #TODO this should be a param $im2->transparent($white); } $im->copy($im2,$self->{NX},$self->{NY},0,0,$w,$h); } } sub set_reading { my ($self,$val) = @_; $self->{VAL} = $val; } package GD::Dashboard::HorizontalBar; # Options: # TRANSPARENT = [ r,g,b ] # SPACING = N # MIN # MAX # sub new { my $proto = shift; my $self = { MIN => 0, MAX => 100, VAL => 50, NX => 0, NY => 0, QUALITY => 100, DIRECTION=>0, BARS=>[], SPACING => 0 }; # load in options supplied to new() for (my $x = 0; $x <= $#_; $x += 2) { my $opt = uc($_[$x]); defined($_[($x + 1)]) or die "Dashboard::HorizontalBar->new() called with odd number of option parameters - should be of the form option => value"; $self->{$opt} = $_[($x + 1)]; } bless($self); return $self; } sub add_bars { my ($self,$cnt,$fname,$fnameoff) = @_; if (!defined($fnameoff)) { $fnameoff = ''; } push @{$self->{BARS}}, { CNT=>$cnt,FNAME=>$fname,FNAME_OFF=>$fnameoff} ; } sub set_reading { my ($self,$val) = @_; # warn "Warning: set_reading called with value less than minimum." if $val < $self->{MIN}; # warn "Warning: set_reading called with value greater than maximum." if $val > $self->{MAX}; $self->{VAL} = $val; } sub write_gdimagehandle { my ($self,$im) = @_; # How many bars do we have? my $barcnt = 0; for my $href (@{$self->{BARS}}) { $barcnt += $href->{CNT}; } # How many must we display? my $norm = $self->{VAL} / ($self->{MIN} + $self->{MAX} ); my $disp = int ($barcnt * $norm); # OK copy the graphics as necessary my $x = $self->{NX}; for my $href (@{$self->{BARS}}) { # load the current image my $im2 = GD::Image->newFromJpeg($href->{FNAME}); if (defined($self->{TRANSPARENT})) { my $white = $im2->colorClosest(255,255,255); #TODO this should be a param $im2->transparent($white); } my ($w,$h) = $im2->getBounds(); my $cnt = $href->{CNT}; while ($disp>0 && $cnt>0) { $im->copy($im2,$x,$self->{NY},0,0,$w,$h); $x += $w + $self->{SPACING}; $disp--; $barcnt--; $cnt--; } # Now load up dark image and use it if necessary my $fn2 = $href->{FNAME_OFF}; if (defined($fn2) && $fn2 ne '') { my $im3 = GD::Image->newFromJpeg($fn2); if (defined($self->{TRANSPARENT})) { my $wt = $im2->colorClosest(255,255,255); #TODO this should be a param $im3->transparent($wt); } my ($w,$h) = $im2->getBounds(); while ($cnt>0) { $im->copy($im3,$x,$self->{NY},0,0,$w,$h); $x += $w + $self->{SPACING}; $cnt--; } } } } # Autoload methods go after =cut, and are processed by the autosplit program. 1; __END__ =head1 NAME GD::Dashboard - Perl module to create JPEG graphics of meters and dials =head1 SYNOPSIS my $dash = new GD::Dashboard(); my $g1 = new GD::Dashboard::Gauge( MIN=>0, MAX=>$empcnt, VAL=>$nopwp_cnt, NA1=>3.14/2+0.85, NA2=>3.14/2-0.85, NX=>51,NY=>77,NLEN=>50 ); $dash->add_meter('RPM', $g1); $dash->write_jpeg('dash.jpg'); The Dashboard module aims at providing users with a quick and easy way to create dashboard or cockpit like JPGs to display key information. Dashboard supports the following instruments: * Gauges with needles * Bar type gauges * Warning Lights Dashboard is built on top of GD.pm, Licoln Stein's interface to the GD library. =head1 Classes The dashboard module contains several classes. These classes typically represent either a dashboard or an instrument on the dashboard. The Dashboard object serves as a collection for the instruments. =head2 Dashboard The Dashboard object serves as the collection object that contains the various instruments in the display. You can add instruments to the dashboard, access instruments through it, or tell it to draw itself. my $dash = new Dashboard(); $dash->add_meter('RPM', $g1); $dash->add_meter('Speedo', $g2); $dash->write_jpeg('dash.jpg'); =over 4 =item * FNAME This is the name of a JPG file to use for the background. This graphic will typically have one or more gauges on it, upon which this module will draw needles or other indicators. =item * QUALITY The quality of the output JPEG, from 1 (low) to 100 (high). Defaults to 100. This value is passed directly to GD. =back 4 =head3 add_meter(name, meter) Adds a meter to the dash. Create the meter using one of the new() constructors first. You can add Gauges, HorizontalBars, and WarningLights. The name is used by the get_meter() function if you need to access the meter later. =head3 get_meter() Gets a meter by name. When adding a meter, you must give it a name. You can then use get_meter to get the meter object. This is useful when you want to change a setting later, such as the meter's value. =head3 jpeg() Returns a JPG as a scalar value. =head3 write_jpeg(fname) Draws the dashboard to a jpg file given by fname. =head3 png() Returns a PNG as a scalar value. =head3 write_png(fname) Draws the dashboard to a PNG file given by fname. =head2 Dashboard::Gauge This class describes a typical dashboard gauge; that is, an instrument that has a needle that rotates. The needle may rotate clockwise or counterclockwise. This gauge is similar to a car speedometer or and airspeed indicator. =head3 new() Most gauge configuration is done in the constructor. Here is a sample for the gauge included with this package (m1.jpg): my $g1 = new GD::Dashboard::Gauge(FNAME=>base_path().'\icons\m1.jpg', MIN=>0, MAX=>$empcnt, VAL=>$nopwp_cnt, NA1=>3.14/2+0.85, NA2=>3.14/2-0.85, NX=>51,NY=>77,NLEN=>50 ); =over 4 =item * VAL This indicates where the needle is pointing. Generally it should be somewhere between MIN and MAX. =item * MIN This is the minimum VAL is ever expected to reach. It corresponds to a needle position of NA1. Lower values are not truncated; however, they will generate warnings. =item * MAX This is the maximum VAL is ever expected to reach. It corresponds to a needle position of NA2. Higher values are not truncated; however, they will generate warnings. =item * NX This is the X coordinate of the base of the needle. =item * NY This is the Y coordinate of the base of the needle. =item * NLEN This is the length of the needle to draw. =item * NWIDTH This is the width of the needle. =item * NA1 NA1 and NA2 are potentially the most confusing parameters. They represent the angle of the needle at its MIN and MAX points. NA1 is the angle that corresponds to VAL=MIN, while NA2 is VAL=MAX. The angle is expressed in radians, the same way you would express an angle to one of perl's trigonometric functions. =item * NA2 See NA1. =item * NCOLOR This is the color of the needle. This value should be passed as a reference to an array of RGB values. =item * COUNTERCLOCKWISE Set to 1 if needle moves from MIN to MAX in a counterclockwise direction. Otherwise you can ignore it. =back 4 =head2 Dashboard::HorizontalBar This class describes an LED bargraph display of the type often found in a graphical equalizer or, on some cars, the oil condition indicator. It may be all one color, or it may use different colors in different ranges. The graph goes from left to right and consists of a number of bars, meant to represent LEDs. Bars can be identical or you can configure different bars, for example to have the last couple of bars be red instead of green. my $m1 = new GD::Dashboard::HorizontalBar( NX => 235, NY => 348, SPACING => 1 ); $m1->add_bars(20,base_path().'\icons\barlight_on.jpg','\icons\barlight_off.jpg'); $dash->add_meter('m1',$m1); =head3 new() =over 4 =item * MIN = N The value representing zero bars illuminated. Defaults to 0. =item * MAX = N The value representing all bars illuminated. Defaults to 100. =item * VAL = N The value to display. Number of bars illuminated will be val / (max-min) percent of total. =item * TRANSPARENT = [ r,g,b ] This is currently not implemented correctly. If you pass any array reference to this parameter, WHITE will be transparent. This allows you to have non-rectangular bars. Email me if the white bit is a problem. =item * SPACING = N If you would like bars to be separated by a number of pixles, specify the number in this parameter. =back 4 =head3 add_bars(count, fname, fnameoff) Call this for each different group of bars you would like to add. Count is the number of bars. Fname is the path to a JPG that represents the bars in their ON state. Fnameoff is an optional filename to a JPG that represents the bar in the off state (these are often just built into the dashboard background, however). =head3 set_reading(val) Sets the number of bars that are illuminated. So if you have 20 bars defined, 'val' should be between 0 and 20 inclusive. =head2 Dashboard::WarningLight This behaves like a warning light on a car dashboard. It can be turned on or off. When VAL is 0, this gauge has basically no effect. When VAL is 1, it draws another graphic on the dashboard (this would typically be the warning light on graphic). Consequently, the dashboard graphic should contain the warning light in its "off" state. =head3 new() Most configuration of the warning light is done via the constructor. =over 4 =item * FNAME This is a JPG file that will be drawn at NX,NY when the warning light is turned on. =item * VAL This can be 0 or 1. A value of 1 turns the warning light on, i.e., it causes the graphic FNAME to be drawn at NX,NY. =item * NX X position of lower right of graphic FNAME. =item * NY Y position of lower right of graphic FNAME. =item * TRANSPARENT Currently, set this to 1 to make WHITE transparent. I probably should make this take an RGB array ref. Email me if you want it. =back 4 =head3 set_reading(val) Sets the VAL parameter. This can be 0 (warning light off) or 1 (warning light on). =head1 NOTES This is the first release. There are a few things on my mind for 0.02. First, PNG support would be easy to add in. I don't use it so I haven't added it (yet). Email if you want it. Second, all of the meters are probably going to derive from a base class. Haven't had time to change it yet. Eventually I should pay more attention to the needle drawing in the Gauge class. If your art is really good, the needles bring it down :( I'm sure the docs could be better. =head1 AUTHOR David Ferrance (dave@ferrance.com) =head1 LICENSE Dashboard: A module for creating dashboard graphics. Copyright (C) 2002 David Ferrance (dave@ferrance.com). All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as perl itself. Sample graphics provided by rabia@rabia.com. This module isn't worth much without a good graphics person to provide you with sweet dashboard layouts. =cut