use GD;
#NOTE: yInc should normally be a multiple of ygrid, if not specifying low
# and high values for y.
#THIS FUNCTION PLOTS BOTH BARS AND LINES ON SAME CHART.
#TO PRINT LINES IN ADDITION TO BARS, INCLUDE THE FOLLOWING ARGS:
#
# lnlegend => \@list (like xlegend)
# ylnvals => \@list (like yvals)
# 20031022: ADDED -ylnplotlegend => [0|1..] TO ALLOW PLOTTING LINES AGAINST
# THE *LEFT* MARGIN IF SET. THE LIST CORRESPONDS TO THE NUMBER OF
# "ylnvals". 1=PLOT AGAINST LEFT LEGEND, 0=RIGHT LEGEND (DEFAULT).
sub BarLnChart
{
my %parm;
my (@barcolrs, @linecolrs, $linecolr);
my ($g, $v);
my ($ycnt, $ylncnt, $h, $i, $j, $k, $legendx, $legendy, $mapstr, @l);
while (@_)
{
$v = shift;
$v =~ s/^\-//;
$parm{$v} = shift;
}
my ($sfw,$sfh) = (gdSmallFont->width,gdSmallFont->height);
my ($lfw,$lfh) = (gdLargeFont->width,gdSmallFont->height);
my ($sfh2) = $sfh + 2;
my ($sfh_2) = $sfh / 2;
#SET UP PARAMETER DEFAULTS.
#$parm{lmgn} = 60 unless($parm{lmgn});
$parm{minlmgn} ||= 20; #ADDED 20030910.
#REMOVED 20030616: $parm{rmgn} = 20 unless($parm{rmgn});
#$parm{bmgn} = 80 unless($parm{bmgn});
my @titles;
#NEXT LINE ADDED 20030527 TO SUPPORT 2 KINDS OF "BOTTOM" VALUES.
$parm{showvalues} =~ s/\bbottom/lnbottom,xbottom/;
#NEXT LINE ADDED 20030527 TO SUPPORT MULTILINE TITLES!
@titles = split(/\n|\
/i, $parm{title}) if (defined($parm{title}));
unless($tmgn)
{
$parm{tmgn} = $parm{minlmgn};
#$parm{tmgn} += $lfh if (defined($parm{title}));
$parm{tmgn} += ($lfh+2)*scalar(@titles) + $sfh if ($#titles >= 0); #ADDED 20030527 TO SUPPORT MULTILINE TITLES!
}
#$parm{border} = 3 unless (defined($parm{border})); #FOR DEBUG ONLY.
#$parm{barcolor} = 'blue' unless ($parm{barcolor});
#$parm{bgcolor} = 'white' unless ($parm{bgcolor});
$parm{valcolor} = 'white' unless ($parm{valcolor});
my ($contrastchk) = 0;
$contrastchk = 1 if ($parm{valcolor} eq 'white');
$parm{axiscolor} = 'black' unless ($parm{axiscolor});
$parm{titlecolor} = $parm{axiscolor} unless ($parm{titlecolor});
$parm{valxcolor} = $parm{axiscolor} unless ($parm{valxcolor});
#$parm{barcolors} = [qw(Steelblue4 DarkGreen brown4 Yellow3 darkorchid skyblue darkorange gray khaki salmon bisque4 olivedrab)] unless(defined($parm{barcolors}));
$parm{barcolors} = [qw(SteelBlue gray brown4 khaki3 DarkGreen salmon skyblue bisque3 purple darkorange olivedrab yellow3)] unless(defined($parm{barcolors}));
for ($j=0;$j<$parm{shiftcolors};$j++)
{
$ix = shift(@{$parm{barcolors}});
@{$parm{barcolors}} = (@{$parm{barcolors}},$ix);
}
if (defined($parm{barcolor}))
{
$parm{barcolors} = [$parm{barcolor}];
}
#elsif (defined($parm{xlegend}) && $#{$parm{barcolors}} > 0 && $#{$parm{xlegend}} > 0) #CHGD. TO NEXT 20030630.
elsif (defined($parm{xlegend}) && $#{$parm{barcolors}} > 0 && $#{$parm{xlegend}} >= 0)
{
$_ = 0;
$_ = $#{$parm{xlegend}} if (defined($parm{xlegend}));
$_ += $#{$parm{lnlegend}}+1 if (defined($parm{lnlegend}) && $#{$parm{lnlegend}} >= 0);
$#{$parm{barcolors}} = $_ if ($#{$parm{barcolors}} > $_);
$parm{barcolor} = ${$parm{barcolors}}[0];
}
else
{
$parm{barcolor} = ${$parm{barcolors}}[0];
}
my ($shadowcolor) = 'black';
if (defined($parm{shadowcolor}))
{
$shadowcolor = $parm{shadowcolor};
}
else
{
if (defined($parm{bgcolor}))
{
$shadowcolor = 'gray' if ($parm{bgcolor} =~ /black/i);
}
}
$parm{gridcolor} = $parm{barcolor} unless ($parm{gridcolor});
$parm{headercolor} = $parm{barcolor} unless ($parm{headercolor});
$parm{bordercolor} = 'black' unless ($parm{bordercolor});
$parm{shadowcolor} = $shadowcolor;
$ycnt = $#{$parm{xlegend}} + 1 if (defined($parm{xlegend}));
$ycnt = 1 unless ($ycnt > 1);
my $lnlegendsz = 0;
if (defined($parm{lnlegend}))
{
$ylncnt = $#{$parm{lnlegend}} + 1;
#$lnlegendsz = $ylncnt; #CHGD. TO NEXT 4 20020626.
for ($i=0;$i<$ylncnt;$i++)
{
++$lnlegendsz if (defined(${$parm{lnlegend}}[$i]));
}
}
my $ybottomcnt = 0;
if (defined($parm{xlegend}))
{
for ($i=0;$i<$ycnt;$i++)
{
++$ybottomcnt if (defined(${$parm{xlegend}}[$i]) && length(${$parm{xlegend}}[$i]));
}
}
$ylncnt = 1 unless ($ylncnt > 1);
my ($yvalcnt) = $ycnt * ($#{$parm{xvals}}+1); #NO. OF YVALS THERE "SHOULD" BE.
for ($i=0;$i<$yvalcnt;$i++) #MAKE SURE ALL Y-VALUES HAVE A VALUE!
{
${$parm{yvals}}[$i] = '0' unless (${$parm{yvals}}[$i]);
}
if ($parm{debug})
{
$ix = 0;
for ($j=0;$j<=$#{$parm{yvals}};$j+=$ycnt)
{
for ($i=0;$i<$ycnt;$i++)
{
$g .= "
$parm{xvals}[$i]: $parm{yvals}[$ix]\n";
}
}
$g .= '
---- LINE VALUES '.$#{$parm{ylnvals}}.'----' if (defined($parm{ylnvals}));
for ($j=0;$j<=$#{$parm{ylnvals}};$j+=$ycnt)
{
for ($i=0;$i<$ylncnt;$i++)
{
$g .= "
$parm{xvals}[$i]= $parm{ylnvals}[$ix]\n";
}
}
print "
$g
\n";
return ($g);
}
if (defined($parm{yloval}))
{
$parm{ymin} = $parm{yloval};
$ymin = $parm{ymin};
}
else
{
$parm{ymin} = 99999;
$parm{ymin} = 0 if (defined($parm{yhival}));
}
if (defined($parm{yhival}))
{
$parm{ymax} = $parm{yhival};
$ymax = $parm{ymax};
}
else
{
$parm{ymax} = -99999;
}
my $ymaxwidthval = '0'; #ADDED 20030619
my $ymax2widthval = '0'; #ADDED 20030703
#YVALPREFIX & YVALSUFFIX ADDED 20050204 TO APPEND "$" AND OR "%" TO VALUES FOR DISPLAY!
my $yvalprefix = defined $parm{yvalprefix} ? $parm{yvalprefix} : '';
my $yvalsuffix .= defined $parm{yvalsuffix} ? $parm{yvalsuffix} : '';
unless (defined($parm{yhival}) && defined($parm{yloval})) #CALCULATE HIGH AND LO Y-VALUES.
{
for ($j=0;$j<=$#{$parm{yvals}};$j+=$ycnt) #FIND LOWEST & HIGHEST Y.
{
for ($i=0;$i<$ycnt;$i++)
{
$_ = $i + $j;
if (defined(${$parm{yvals}}[$_]))
{
$parm{ymin} = ${$parm{yvals}}[$_] unless ($parm{ymin} <= ${$parm{yvals}}[$_]);
$parm{ymax} = ${$parm{yvals}}[$_] unless ($parm{ymax} >= ${$parm{yvals}}[$_]);
}
}
}
#NEXT 3 LINES ADDED 20030619 TO PREVENT WIDE NUMBERS FROM DISPLAYING ON BARS.
$ymaxwidthval = &commatize($parm{ymax}, $parm{commatize}, $yvalprefix, $yvalsuffix);
$ymaxwidthval = &commatize($parm{ymin}, $parm{commatize}, $yvalprefix, $yvalsuffix)
if (length($parm{ymin}) > length($parm{ymax}));
unless (defined $parm{ylnmin} || defined $parm{ylnmax})
{
if (defined $parm{ylnvals})
{
for ($j=0;$j<=$#{$parm{ylnvals}};$j+=$ylncnt) #FIND LOWEST & HIGHEST Y.
{
for ($i=0;$i<$ylncnt;$i++)
{
$_ = $i + $j;
if (defined(${$parm{ylnvals}}[$_]))
{
$parm{ymin} = ${$parm{ylnvals}}[$_] unless ($parm{ymin} <= ${$parm{ylnvals}}[$_]);
$parm{ymax} = ${$parm{ylnvals}}[$_] unless ($parm{ymax} >= ${$parm{ylnvals}}[$_]);
}
}
}
}
}
$ymin = $parm{ymin};
$ymax = $parm{ymax};
#if (defined($parm{yHival}) && defined($parm{ybase}))
#{
$parm{ygrid} = 4 unless(defined($parm{ygrid}));
# $parm{yInc} = &xfincx($parm{yHival},$parm{ygrid});
# $parm{ymax} = ($parm{ygrid} * $parm{yInc}) - $parm{yLoval};
# $parm{ymin} = $parm{yLoval};
#}
#elsif ($parm{yInc} && defined($parm{ybase})) #FIND NEXT EVEN GRIDPOINTS.
if ($parm{yInc} && defined($parm{ybase})) #FIND NEXT EVEN GRIDPOINTS.
{
unless ($parm{yloval})
{
$y = $parm{ybase};
$y -= $parm{yInc} while ($y > $parm{ymin});
$parm{ymin} = $y;
}
unless ($parm{yhival})
{
$y = $parm{ybase};
$y += $parm{yInc} while ($y < $parm{ymax});
$parm{ymax} = $y;
}
$parm{yInc} = ($parm{ymax} - $parm{ymin}) / $parm{ygrid}
if ($parm{ygrid} > 0);
}
else
{
my ($ygrid);
if (defined($parm{ygrid}))
{
$ygrid = $parm{ygrid};
}
else
{
$parm{ygrid} = 4;
}
if (defined($parm{ybase}))
{
$parm{ymin} = $parm{ybase} if ($parm{ymin} > $parm{ybase});
$parm{ymax} = $parm{ybase} if ($parm{ymax} < $parm{ybase});
my ($yrange) = $parm{ymax} - $parm{ymin};
if ($parm{ymin} < $parm{ybase} && $parm{ymax} > $parm{ybase})
{
for ($j=$parm{ygrid};$j>=$parm{ygrid}-1;$j--)
{
$parm{yInc} = &xfincx($yrange,$j);
$ymin = $parm{ybase};
while ($ymin > $parm{ymin})
{
$ymin -= $parm{yInc};
}
$ymax = $ymin + $parm{yInc} * $parm{ygrid};
last if ($ymax >= $parm{ymax});
}
$parm{ymin} = $ymin;
unless ($ygrid)
{
while ($parm{ygrid} && $ymax > $parm{ymax})
{
--$parm{ygrid};
$ymax -= $parm{yInc};
}
$parm{ygrid} = 1 unless ($parm{ygrid});
unless ($ymax >= $parm{ymax})
{
++$parm{ygrid};
$ymax += $parm{yInc};
}
}
$parm{ymax} = $ymax;
}
else
{
$parm{yInc} = &xfincx($yrange,$parm{ygrid});
$parm{ymax} = $parm{yInc} * $parm{ygrid};
}
}
else
{
unless ($parm{yInc})
{
$parm{yInc} = &xfincx(($parm{ymax} - $parm{ymin}),
$parm{ygrid});
$parm{ymax} = $parm{ymin} + $parm{yInc} * $parm{ygrid};
}
}
}
}
else #ADDED 20030619 TO PREVENT WIDE NUMBERS FROM DISPLAYING ON BARS.
{
$ymaxwidthval = &commatize($parm{yhival}, $parm{commatize}, $yvalprefix, $yvalsuffix);
$ymaxwidthval = &commatize($parm{yloval}, $parm{commatize}, $yvalprefix, $yvalsuffix)
if (length($parm{yloval}) > length($parm{yhival}));
}
unless ($ycnt == 1 || $parm{showvalues} =~ /nobar|top/) #ADDED 20030703
{
my @l = (); my @l2 = ();
for ($i=0;$i<=$#{$parm{yvals}};$i+=$ycnt)
{
@l = ();
for (my $j=0;$j<$ycnt;$j++)
{
$l[$j] = ${$parm{yvals}}[$i+$j] unless ($l[$j] > ${$parm{yvals}}[$i+$j]);
}
@l2 = sort {$b <=> $a} @l;
$ymax2widthval = $l2[1] unless ($ymax2widthval > $l2[1]);
}
}
else
{
$ymax2widthval = 9999;
}
$parm{ymax} = $parm{ygrid} unless ($parm{ymin} || $parm{ymax});
#ADDED 20030616 TO HANDLE DUAL RANGES!
$rightlegend = 1;
if (defined $parm{ylnmin} && defined $parm{ylnmax})
{
$parm{ylnInc} = ($parm{ylnmax} - $parm{ylnmin}) / $parm{ygrid};
}
elsif (defined $parm{ylnmin} && defined $parm{ylnvals})
{
my $jx = 0;
for ($j=0;$j<=$#{$parm{ylnvals}};$j+=$ylncnt) #FIND LOWEST & HIGHEST Y.
{
#NEXT UNLESS ADDED 20031022 TO ALLOW PARAMETER TO SPECIFY PLOTTING LINES AGAINST *LEFT* LEGEND!
unless (defined($parm{ylnplotlegend}[$jx]) && $parm{ylnplotlegend}[$jx])
{
for ($i=0;$i<$ylncnt;$i++)
{
$_ = $i + $j;
if (defined(${$parm{ylnvals}}[$_]))
{
$parm{ylnmax} = ${$parm{ylnvals}}[$_] unless ($parm{ylnmax} >= ${$parm{ylnvals}}[$_]);
}
}
}
++$jx;
}
$parm{ylnInc} = &xfincx(($parm{ylnmax}-$parm{ylnmin}), $parm{ygrid}) || 1;
#NEXT LINE ADDED 20040122.
$parm{ylnmax} = $parm{ygrid} * $parm{ylnInc}
if ($parm{ylnmax} < ($parm{ygrid} * $parm{ylnInc}));
}
elsif (defined $parm{ylnmax} && defined $parm{ylnvals})
{
my $jx = 0;
for ($j=0;$j<=$#{$parm{ylnvals}};$j+=$ylncnt) #FIND LOWEST & HIGHEST Y.
{
#NEXT UNLESS ADDED 20031022 TO ALLOW PARAMETER TO SPECIFY PLOTTING LINES AGAINST *LEFT* LEGEND!
unless (defined($parm{ylnplotlegend}[$jx]) && $parm{ylnplotlegend}[$jx])
{
for ($i=0;$i<$ylncnt;$i++)
{
$_ = $i + $j;
if (defined(${$parm{ylnvals}}[$_]))
{
$parm{ylnmin} = ${$parm{ylnvals}}[$_] unless ($parm{ylnmin} <= ${$parm{ylnvals}}[$_]);
}
}
}
++$jx;
}
$parm{ylnInc} = &xfincx(($parm{ylnmax}-$parm{ylnmin}), $parm{ygrid});
}
else
{
$parm{ylnmin} = $parm{ymin};
$parm{ylnmax} = $parm{ymax};
$parm{ylnInc} = $parm{yInc};
$rightlegend = 0;
}
$parm{ylnbase} ||= $parm{ybase};
my $prelegendlength = 0; #ADDED 20030910.
unless ($parm{lmgn}) #CALCULATE LEFT MARGIN, IF NOT SPECIFIED.
{
if (length("$parm{ymin}") > length("$parm{ymax}"))
{
$x = length(&commatize($parm{ymin}, $parm{commatize}, $yvalprefix, $yvalsuffix));
}
else
{
$x = length(&commatize($parm{ymax}, $parm{commatize}, $yvalprefix, $yvalsuffix));
}
#$parm{lmgn} = ($x*$sfw) + 23;
$parm{lmgn} = ($x*$sfw) + $sfw + $parm{minlmgn};
$parm{lmgn} += $sfh + 2 if (defined($parm{ytitle}));
if (defined($parm{prelegend})) #ADDED 20030910 TO SUPPORT HEADERS LEFT OF X-VALUES.
{
@l = split(/\n/, $parm{prelegend});
foreach my $i (@l)
{
$prelegendlength = length($i) if ($prelegendlength < length($i));
}
if ($prelegendlength > 0)
{
$prelegendlength *= $sfw;
$_ = $prelegendlength + $parm{minlmgn} + $sfh;
$parm{lmgn} = $_ if ($parm{lmgn} < $_);
}
}
}
if ($rightlegend) #ADDED 20030616 TO HANDLE DUAL RANGES!
{
unless ($parm{rmgn}) #CALCULATE RIGHT MARGIN, IF NOT SPECIFIED.
{
if (length("$parm{ylnmin}") > length("$parm{ylnmax}"))
{
$x = length(&commatize($parm{ylnmin}, $parm{commatize}, $yvalprefix, $yvalsuffix));
}
else
{
$x = length(&commatize($parm{ylnmax}, $parm{commatize}, $yvalprefix, $yvalsuffix));
}
$parm{rmgn} = ($x*$sfw) + $sfw + $parm{minlmgn};
$parm{rmgn} += $sfh + 2 if (defined($parm{ylntitle}));
}
}
unless ($parm{rmgn})
{
$parm{rmgn} = $parm{minlmgn};
$parm{rmgn} += $sfh + 2 if (defined($parm{ylntitle}));
}
my ($pointdiam) = 0;
#$pointdiam = abs($parm{points}) if (defined($parm{points}));
#my ($pointdiam0) = $pointdiam;
#$pointdiam0 = 1 if ($parm{points} > 0);
#$pointrad = $pointdiam / 2;
$pointrad = 0;
if (defined ($parm{points}) && @{$parm{points}})
{
for ($i=0;$i<=$#{$parm{points}};$i++)
{
$pointrad = ${$parm{points}}[$i] if ($pointrad < ${$parm{points}}[$i]);
}
}
elsif ($parm{points} > 0)
{
$pointrad = $parm{points};
}
my ($xvallines) = 0;
foreach (@{@parm{xvals}}) #REPLACED WITH NEXT ADDITION 20030408.
{
(@l) = split(/\n/);
$xvallines = $#l if ($#l > $xvallines);
}
$truebmgn = $parm{bmgn} || 30;
unless ($parm{bmgn}) #CALCULATE BOTTOM MARGIN, IF NOT SPECIFIED.
{
$parm{bmgn} = ($xvallines*$sfh) + $sfh2 + 12 unless ($parm{bmgn}); #CALCULATE BOTTOM MARGIN, IF NOT SPECIFIED.
#$parm{bmgn} += $sfh2 if (defined($parm{xtitle})); #CHGD. TO NEXT 20030820!
$parm{bmgn} += 2 * $sfh2 if (defined($parm{xtitle}));
$parm{bmgn} += $sfh2 if ($parm{showvalues} =~ /total/i);
$parm{bmgn} += $sfh if ($parm{ymin} < $parm{ybase}); #ALLOW ROOM FOR VALUES BELOW DOWNWARD BARS.
#$parm{bmgn} += $sfh2 if (defined($parm{xlegend}));
$parm{bmgn} += $sfh2 if (defined($parm{xlegend})
|| defined($parm{barseplegend}) || defined($parm{lnlegend})
|| defined($parm{lnprelegend}));
$parm{bmgn} += $sfh2 if (defined($parm{ylnvals})); #NEEDED!
$parm{bmgn} += $sfh2 if (defined($parm{ylnvals}) || defined($parm{xlegend}));
$parm{bmgn} += $sfh2 if (defined($parm{barseplegend}));
if ($parm{showvalues} =~ /xbottom/i && $ybottomcnt > 0) #ADDED 20030527.
{
#$parm{bmgn} += ($ycnt * $sfh2) + 2; #CHGD. TO NEXT 20030626.
$parm{bmgn} += ($ybottomcnt * $sfh2) + 2;
}
if ($parm{showvalues} =~ /lnbottom/i && $lnlegendsz > 0) #ADDED 20030408.
{
$parm{bmgn} += ($lnlegendsz * $sfh2) + 2;
}
}
unless ($parm{maxxsiz})
{
#$parm{barxsiz} = 60 unless ($parm{barxsiz});
unless ($parm{barxsiz})
{
$x = 0;
foreach (@{$parm{xvals}}) #FIND WIDEST X HEADER TO COMPUTE BAR SIZE.
{
#$i = $sfw * length($_);
#$x = $i unless ($x > $i);
(@l) = split(/\n/);
for ($k=0;$k<=$#l;$k++)
{
$i = $sfw * length($l[$k]);
$x = $i unless ($x > $i);
}
}
foreach (@{$parm{yvals}}) #FIND WIDEST Y-VALUE TO COMPUTE BAR SIZE.
{
$i = $sfw * length($_);
$x = $i unless ($x > $i);
}
#BARXSIZ REPRESENTS WIDTH OF *ALL* BARS IN SET AND ONLY A SINGLE
#XVALUE PRINTS PER *SET*!
#$parm{barxsiz} = ($x + 4) * $ycnt; #CHGD. TO NEXT 20030619.
$parm{barxsiz} = $x + 4;
}
if ($parm{xbreak} > 0 && $ycnt > 0) #XBREAK STUFF ADDED 20001204 TO ALLOW GROUPING. (ADD HORIZONTAL SPACE AFTER EVERY NTH BAR).
{
$parm{maxxsiz} = ($parm{barxsiz} * ($#{$parm{xvals}}+1+int(($#{$parm{xvals}}/$parm{xbreak})*(1/$ycnt)))) + $parm{lmgn} + $parm{rmgn};
}
else
{
$parm{maxxsiz} = ($parm{barxsiz} * ($#{$parm{xvals}}+1)) + $parm{lmgn} + $parm{rmgn};
}
if (defined($parm{xlegend})) #IF LEGENDS WIDER THAN CHART, WIDEN CHART!
{
$legendx = $parm{minlmgn};
$ix = 0;
$i = $sfh2 + 7;
foreach (@{$parm{xlegend}})
{
$_ = length(${$parm{xlegend}}[$ix]);
$legendx += $i + ($sfw * $_) if ($_);
++$ix;
}
$legendx += 2 * $parm{minlmgn};
$parm{maxxsiz} = $legendx if ($parm{maxxsiz} < $legendx);
#IF ANY TITLE LINE IS WIDER THAN CHART, WIDEN CHART.
for (my $i=0;$i<=$#titles;$i++)
{
$_ = $lfw*length($titles[$i]) + (2 * $parm{minlmgn});
$parm{maxxsiz} = $_ if ($parm{maxxsiz} < $_);
}
}
}
else
{
if ($parm{xbreak} > 0 && $ycnt > 0)
{
$parm{barxsiz} = ($parm{maxxsiz} - ($parm{lmgn} + $parm{rmgn})) / ($#{$parm{xvals}}+1+int(($#{$parm{xvals}}/$parm{xbreak})*(1/$ycnt))) unless ($parm{barxsiz});
}
else
{
if ($#{$parm{xvals}} >= 0) #PREVENT DIVIDE-BY-ZERO ERRORS!
{
$parm{barxsiz} = ($parm{maxxsiz} - ($parm{lmgn} + $parm{rmgn})) / ($#{$parm{xvals}}+1) unless ($parm{barxsiz});
}
else
{
$parm{barxsiz} = $parm{maxxsiz} - ($parm{lmgn} + $parm{rmgn});
}
}
#NEXT 12 LINES ADDED 20030619 TO ENSURE BARS WIDE ENOUGH TO
#ACCOMMODATE X-VALUES (LATER WE PREVENT PRINTING BARS OFF RIGHT
#EDGE OF CHART).
$x = 0;
foreach (@{$parm{xvals}}) #FIND WIDEST X HEADER TO COMPUTE BAR SIZE.
{
(@l) = split(/\n/);
for ($k=0;$k<=$#l;$k++)
{
$i = $sfw * length($l[$k]);
$x = $i unless ($x > $i);
}
}
#DON'T NEED NEXT 5 HERE, I DON'T THINK.
# foreach (@{$parm{yvals}}) #FIND WIDEST Y-VALUE TO COMPUTE BAR SIZE.
# {
# $i = $sfw * length($_);
# $x = $i unless ($x > $i);
# }
$parm{barxsiz} = $x+4 if ($parm{barxsiz} < $x+4);
}
unless ($parm{barpct})
{
$parm{barpct} = 80;
$parm{barpct} = 100 if ($parm{barxsiz} < 10);
}
my $barxpix = (($parm{barxsiz} * $parm{barpct}) / 100) / $ycnt;
#NEXT 24 LINES ADDED 20030619 TO PREVENT NUMBERS WIDER THAN BARS FROM BEING
#DISPLAYED ON THE BARS (IF *ANY* Y-VALUE TOO WIDE, FORCE ALL TO BOTTOM!
my $ymaxwidth = length($ymaxwidthval) * $sfw;
my $ymax2width = length($ymax2widthval) * $sfw;
if ($ymaxwidth > $barxpix && $ymax2width > $barxpix && ($ycnt > 1 || $ymaxwidth > $parm{barxsiz}))
{
$parm{commatize} = 0; #1ST, TRY STRIPPING COMMAS, SEE IF FITS NOW.
$ymaxwidthval =~ s/\,//g;
$ymaxwidth = length($ymaxwidthval) * $sfw;
my $addedbottom = 0;
if ($ymaxwidth > $barxpix)
{
#STILL WON'T FIT, FORCE OFF OF BAR AND ONTO BOTTOM OF CHART.
$addedbottom = 1;
}
#IF STILL WON'T FIT WITHIN THE ALLOWED SPACE AT BOTTOM, DON'T SHOW AT ALL!!!
if ($ymaxwidth > $parm{barxsiz})
{
$parm{bmgn} -= $sfh2 + 2
if ($parm{showvalues} =~ s/(?:xbottom|total)//g);
$parm{showvalues} .= ',nobar';
}
elsif ($addedbottom)
{
unless ($parm{showvalues} =~ /xbottom/)
{
#$parm{bmgn} += $sfh2 + 2; #CHGD. TO NEXT 20030903.
$parm{bmgn} += ($ybottomcnt * $sfh2) + 2;
}
$parm{showvalues} .= ',nobar,xbottom';
}
}
unless ($parm{maxysiz})
{
$parm{barysiz} = 1 unless ($parm{barysiz});
$parm{maxysiz} = ($parm{barysiz} * ($parm{ymax} - $parm{ymin})) + $parm{bmgn} + $parm{tmgn};
}
else
{
$parm{barysiz} = ($parm{maxysiz} - ($parm{tmgn} + $parm{bmgn})) / ($parm{ymax} - $parm{ymin}) unless ($parm{barysiz});
}
my ($ydiff) = $parm{ymax} - $parm{ymin};
if ($parm{xbreak} > 0 && $ycnt > 0)
{
$chartxsiz = $parm{barxsiz} * ($#{$parm{xvals}}+1+int(($#{$parm{xvals}}/$parm{xbreak})*(1/$ycnt))); #(PIXELS)
}
else
{
$chartxsiz = $parm{barxsiz} * ($#{$parm{xvals}}+1); #(PIXELS)
}
$chartxsiz = $parm{maxxsiz} - ($parm{lmgn} + $parm{rmgn})
if ($chartxsiz > $parm{maxxsiz} - ($parm{lmgn} + $parm{rmgn}));
$chartysiz = $parm{barysiz} * $ydiff;
unless ($parm{ygrid}) #CALCULATE YGRID (# OF GRID LINES), IF NECESSARY.
{
##IF Y IS AN LOV, SET YGRID TO # OF ELEMENTS IN LOV!
if ($parm{yInc}) #IF YINC SET, USE YINC.
{
$parm{ygrid} = $ydiff / $parm{yInc} if ($parm{yInc});
}
else
{
$parm{ygrid} = 4;
}
}
unless ($parm{yInc})
{
$parm{yInc} = $ydiff / $parm{ygrid};
}
if ($parm{ybreak})
{
while ( (($ymax == 0) || (($ymax * $parm{ybreak}) < $parm{ymax}))
&& (($ymin == 0) || (($ymin * $parm{ybreak}) > $parm{ymin})))
{
$parm{ymax} /= 2;
$parm{ymin} /= 2;
$parm{yInc} /= 2;
$parm{yinc} /= 2;
$parm{barysiz} *= 2;
}
}
$parm{ybase} = $parm{ymin} unless (defined($parm{ybase}));
$g = new GD::Image($parm{maxxsiz},$parm{maxysiz});
#CONVERT COLOR NAMES TO RGB VALUES.
@linecolrs = ();
if (open(RGB,")
{
chomp;
($rr,$gg,$bb,$color) = split(' ');
$color = "\L$color\E";
foreach (qw(bar bg val axis grid title valx header border shadow line barsep))
{
$x = $parm{$_."color"};
${$_."colr"} = $g->colorAllocate($rr,$gg,$bb) if ($color eq "\L$x\E");
}
for($j=0;$j<=$#{$parm{barcolors}};$j++)
{
if ($color eq "\L${$parm{barcolors}}[$j]\E")
{
$i = $g->colorAllocate($rr,$gg,$bb);
$bcweights[$j] = ($rr > $gg) ? (($bb > $rr) ? $bb : $rr) :
(($bb > $gg) ? $bb : $gg);
$barcolrs[$j] = $i;
}
}
if (defined($parm{linecolors}))
{
for($j=0;$j<=$#{$parm{linecolors}};$j++)
{
if ($color eq "\L${$parm{linecolors}}[$j]\E")
{
$i = $g->colorAllocate($rr,$gg,$bb);
# $bcweights[$j] = ($rr > $gg) ? (($bb > $rr) ? $bb : $rr) :
# (($bb > $gg) ? $bb : $gg);
$linecolrs[$j] = $i;
}
}
}
if (defined($parm{barsepcolors}))
{
for($j=0;$j<=$#{$parm{barsepcolors}};$j++)
{
if ($color eq "\L${$parm{barsepcolors}}[$j]\E")
{
$i = $g->colorAllocate($rr,$gg,$bb);
$barsepcolrs[$j] = $i;
}
}
}
}
close (RGB);
}
$j = 0;
$j += $ycnt if (defined($parm{xlegend}) && !defined($parm{linecolor}) && $#linecolrs < 0);
while ($#linecolrs < $ylncnt)
{
push(@linecolrs, defined($linecolr) ? $linecolr : $barcolrs[$j++]);
}
#SET UP DEFAULTS FOR ANY MISSING COLORS.
$black = $g->colorAllocate(0,0,0);
$barcolr = $black unless ($barcolr);
$valcolr = $black unless ($valcolr);
$axiscolr = $black unless ($axiscolr);
$gridcolr = $black unless ($gridcolr);
$shadowcolr = $g->colorAllocate(0,0,0) unless ($shadowcolr);
$bgcolr = $g->colorAllocate(127,127,127) unless ($bgcolr);
if ($#barcolrs <= 0) #FILL OUT COLOR ARRAY WITH BAR-COLOR IF NOT SPECIFIED.
{
for ($j=0;$j<=$ycnt;$j++)
{
$barcolrs[$j] = $barcolr;
}
}
elsif ($#barcolrs < $ycnt) #FILL OUT COLOR ARRAY TO MATCH Y-ARRAY.
{
for ($j=$#barcolrs+1;$j<$ycnt;$j++)
{
$barcolrs[$j] = $barcolrs[($j % $#barcolrs)];
}
}
if (defined($parm{bgcolor}))
{
#$g->transparent($bgcolr); #MAKE THE BACKGROUND COLOR TRANSPARENT.
$g->fill(1,1,$bgcolr);
}
for (0..($parm{border}-1))
{
$g->rectangle($_,$_,($parm{maxxsiz}-($_+1)),($parm{maxysiz}-($_+1)),$bordercolr);
}
my $barylo = $parm{tmgn} + ($chartysiz * (($parm{ymax}-$parm{ybase}) / ($parm{ymax}-$parm{ymin})));
#goto SKIPIT1;
#DRAW THE X AND Y AXES.
my $maxygridarea = $parm{maxxsiz} - $parm{rmgn};
my $maxygridarea3 = $maxygridarea + 3;
#CHGD. TO NEXT 20030619 SO THAT AXIS SPANS CHART EVEN IF ZERO OR FEW BARS.
#$g->line($parm{lmgn},$barylo,($parm{lmgn}+$chartxsiz),$barylo,$axiscolr);
$g->line($parm{lmgn},$barylo,$maxygridarea,$barylo,$axiscolr);
$g->line($parm{lmgn},$parm{tmgn},$parm{lmgn},($parm{tmgn}+$chartysiz),$axiscolr);
my $xzonewidth = ((100-$parm{barpct})*$parm{barxsiz}) / 200;
if (defined $parm{barseps}) #ADDED 20030730 TO SUPPORT VERTICAL SEPARATORS BETWEEN BARS.
{
my $s;
my $justify = '|';
my $x;
if (ref($parm{barseps}) =~ /ARRAY/i)
{
for (my $i=0;$i<=$#{$parm{barseps}};$i++)
{
$g->line($parm{lmgn}+($parm{barseps}->[$i]*$parm{barxsiz}),$parm{tmgn}-4,
$parm{lmgn}+($parm{barseps}->[$i]*$parm{barxsiz}),($parm{tmgn}+$chartysiz+4),
(defined $barsepcolrs[$i]) ? $barsepcolrs[$i]
: ($barsepcolr||$axiscolr));
#ADDED 20030903 TO SUPPORT LEGEND TEXT ABOVE VERTICAL LINES.
if (defined $parm{barseptoplegend} && ref($parm{barseptoplegend}) =~ /ARRAY/i)
{
$s = $parm{barseptoplegend}->[$x];
$justify = $1 if ($s =~ s/^([\<\|\>])//);
$x = $parm{lmgn}+($parm{barseps}->[$i]*$parm{barxsiz})+2;
if ($justify eq '<')
{
$x -= (length($s)*$sfw) + 2;
}
elsif ($justify eq '|')
{
$x -= (length($s)*$sfw) / 2;
}
$g->string(gdSmallFont, $x, $parm{tmgn}-(2+$sfh), $s,
$headercolr);
}
}
}
else
{
$g->line($parm{lmgn}+($parm{barseps}*$parm{barxsiz}),$parm{tmgn}-4,
$parm{lmgn}+($parm{barseps}*$parm{barxsiz}),($parm{tmgn}+$chartysiz+4),
($barsepcolr||$axiscolr));
#ADDED 20030903 TO SUPPORT LEGEND TEXT ABOVE VERTICAL LINES.
if (defined $parm{barseptoplegend})
{
$s = $parm{barseptoplegend};
$justify = $1 if ($s =~ s/^([\<\|\>])//);
$x = $parm{lmgn}+($parm{barseps}*$parm{barxsiz})+2;
if ($justify eq '<')
{
$x -= (length($s)*$sfw) + 2;
}
elsif ($justify eq '|')
{
$x -= (length($s)*$sfw) / 2;
}
$g->string(gdSmallFont, $x, $parm{tmgn}-(2+$sfh), $s,
$headercolr);
}
}
}
#NOW DRAW THE HORIZ. GRID LINES
my $yhead = $parm{ybase};
my $yhead2 = $parm{ylnbase};
my $ydelta = $parm{barysiz} * $parm{yInc};
my $yheadxmax;
$yheadxmax = length("$yhead") if(defined($parm{ytitle}));
my $yheadxmax2;
$yheadxmax2 = length("$yhead2") if(defined($parm{ylntitle}));
$y = $barylo;
my ($myyval);
while ($y >= $parm{tmgn}-1)
{
$myyval = &commatize($yhead,$parm{commatize}, $yvalprefix, $yvalsuffix);
#CHGD. TO NEXT 20030619 SO THAT AXIS SPANS CHART EVEN IF ZERO OR FEW BARS.
#$g->line($parm{lmgn}-4,$y,($parm{lmgn}+$chartxsiz),$y,$gridcolr);
$g->line($parm{lmgn}-4,$y,$maxygridarea,$y,$gridcolr); #DRAW HORIZ. GRID-LINE.
$g->string(gdSmallFont,$parm{lmgn}-((length($myyval)*$sfw)+5),$y-($sfh/2),
$myyval,$headercolr); #DRAW LEFT LEGEND VALUES.
$yheadxmax = length($myyval) if (defined($parm{ytitle}) && (length($myyval) > $yheadxmax));
$myyval = &commatize($yhead2,$parm{commatize}, $yvalprefix, $yvalsuffix);
$yheadxmax2 = length($myyval) if (defined($parm{ylntitle}) && (length($myyval) > $yheadxmax2));
$g->string(gdSmallFont,$maxygridarea3,$y-($sfh/2),
$myyval,$headercolr) if ($rightlegend); #DRAW RIGHT LEGEND VALUES.
$y -= $ydelta;
$yhead += $parm{yInc};
$yhead2 += $parm{ylnInc};
}
$yhead = $parm{ybase} - $parm{yInc};
$y = $barylo + $ydelta;
while ($y <= ($parm{tmgn} + $chartysiz)+1)
{
$myyval = &commatize($yhead,$parm{commatize}, $yvalprefix, $yvalsuffix);
#CHGD. TO NEXT 20030619 SO THAT AXIS SPANS CHART EVEN IF ZERO OR FEW BARS.
#$g->line($parm{lmgn}-4,$y,($parm{lmgn}+$chartxsiz),$y,$gridcolr);
$g->line($parm{lmgn}-4,$y,$maxygridarea,$y,$gridcolr);
$g->string(gdSmallFont,$parm{lmgn}-((length($myyval)*$sfw)+3),$y-($sfh/2),
$myyval,$headercolr);
$y += $ydelta;
$yhead -= $parm{yInc};
}
if ($parm{yinc} > 1) #DRAW THE HORIZ. TICKMARKS, IF NEEDED.
{
$ydelta = ($parm{barysiz} * $parm{yInc}) / $parm{yinc};
$y = $barylo;
while ($y > $parm{tmgn})
{
$g->line($parm{lmgn}-2,$y,$parm{lmgn},$y,$gridcolr);
$y -= $ydelta;
}
$y = $barylo;
while ($y < ($parm{tmgn} + $chartysiz))
{
$g->line($parm{lmgn}-2,$y,$parm{lmgn},$y,$gridcolr);
$y += $ydelta;
}
}
#SET UP IMAGE MAPPING, IF APPLICABLE.
if (defined($parm{links}) || defined($parm{mouseovers})
|| defined($parm{link}) || defined($parm{mouseover}))
{
$parm{mapname} = "BarChart.$$" unless (defined($parm{mapname}));
$mapstr = '