Chart
view release on metacpan or search on metacpan
lib/Chart/Pie.pm view on Meta::CPAN
package Chart::Pie;
our @ISA = qw(Chart::Base);
our $VERSION = 'v2.403.9';
use Carp;
use GD;
use Chart::Constants;
use Chart::Base ;
#>>>>>>>>>>>>>>>>>>>>>>>>>>#
# public methods go here #
#<<<<<<<<<<<<<<<<<<<<<<<<<<#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>#
# private methods go here #
#<<<<<<<<<<<<<<<<<<<<<<<<<<<#
## @fn private _draw_data
# @brief
# finally get around to plotting the data
#
# @details
# The user may define the kind of labelling the data by setting\n
# 'label_values' to 'percent' if she wants to have the percentages\n
# 'label_values' to 'values' if she wants to have the absolut values\n
# 'label_values' to 'both' if she wants to have absolut values and percentages\n
# 'label_values' to 'none' if she wants to have neither absolute values nor percentages\n
# 'ring' to a number less then 1 to define a ring as output;
# if 'ring' is 1 ore greater a full pie is plotted\n
#
sub _draw_data
{
my $self = shift;
my $data = $self->{'dataref'};
my $misccolor = $self->_color_role_to_index('misc');
my $textcolor = $self->_color_role_to_index('text');
my $background = $self->_color_role_to_index('background');
my ( $width, $height, $centerX, $centerY, $diameter, $diameter_previous, $text_diameter );
my $dataset_sum;
my ( $start_degrees, $end_degrees, $label_degrees, $label_old_degrees, $labelY_repeat_count );
my ( $pi, $rd2dg, $dg2rd );
my ( $font, $fontW, $fontH, $labelX, $labelY );
my $label;
my ( $i, $j, $color );
my $label_length = 0;
my $degrees = 0;
my $insidecolor;
my $forbidden_degrees = 0; # last occupied degree
my %labelinfo;
my $max_val_len = 0;
my $max_label_len = 0;
# set up initial constant values
$pi = Chart::Constants::PI;
$dg2rd = $pi / 180; # Degree to Radians
$rd2dg = 180 / $pi; # Radian to Degree
$start_degrees = 0;
$end_degrees = 0;
$font = $self->{'legend_font'};
$fontW = $self->{'legend_font'}->width;
$fontH = $self->{'legend_font'}->height;
$label_degrees = $labelY_repeat_count = 0;
# init the imagemap data field if they wanted it
if ( $self->true( $self->{'imagemap'} ) )
{
$self->{'imagemap_data'} = [];
}
# find width and height of the plotting area
$width = $self->{'curr_x_max'} - $self->{'curr_x_min'};
$height = $self->{'curr_y_max'} - $self->{'curr_y_min'};
# okay, add up all the numbers of all the datasets, to get the
# sum total. This will be used to determine the percentage
# of each dataset. Obviously, negative numbers might be bad :)
$dataset_sum = 0;
for $j ( 0 .. $self->{'num_datapoints'} )
{
if ( defined $data->[1][$j] && $data->[1][$j] > 0 )
{
#add to sum
$dataset_sum += $data->[1][$j];
#don't allow negativ values
if ( $data->[1][$j] < 0 )
{
croak "We need positiv data for a pie chart (which is not true for data[$j])!";
}
}
}
# find the longest label
# first we need the length of the values
$max_label_len = 1;
for $j ( 0 .. ( $self->{'num_datapoints'} - 1 ) )
{
# don't try to draw anything if there's no data
$labelinfo{$j}{data} = 'undefined';
if ( defined( $data->[1][$j] ) && $data->[1][$j] > 0 )
{
$labelinfo{$j}{data} = $data->[1][$j];
$label = $data->[0][$j];
$labelinfo{$j}{labeldata} = $label;
if ( defined $self->{'label_values'} )
{
if ( $self->{'label_values'} =~ /^percent$/i )
{
$label = sprintf( "%s %4.2f%%", $label, $data->[1][$j] / ( $dataset_sum || 1 ) * 100 );
}
elsif ( $self->{'label_values'} =~ /^value$/i )
{
if ( $data->[1][$j] =~ /\./ )
{
$label = sprintf( "%s %.2f", $label, $data->[1][$j] );
}
else
lib/Chart/Pie.pm view on Meta::CPAN
$winkel = cos( $label_degrees * $dg2rd );
$winkel = abs($winkel);
if ( abs($winkel) < 0.01 )
{
$h = 0;
}
else
{
$h = $fontH / $winkel;
}
my $atan = atan2( $h, 0.5 * $text_diameter ); # -pi ... +pi
$forbidden_degrees = $label_degrees + $rd2dg * $atan;
# for debugging
#printf("Index=%2d winkel=%6.2f, H=%3d atan=%5.2f label=%6.2f forbidden=%6.2f\n",
# $j, $winkel*$dg2rd,$h, $atan*$rd2dg, $label_degrees,$forbidden_degrees);
# end for debugging
}
$labelX = $centerX + $text_diameter * 0.5 * cos( $label_degrees * $dg2rd );
$labelY = $centerY + $text_diameter * 0.5 * sin( $label_degrees * $dg2rd );
#!!DEBUG!!!!
#print "Text=".$label.": labelX=$labelX, y=$labelY\n";
# # For debugging
# # Draw Point
# # reset the brush for points
# my $brush = $self->_prepare_brush($color, 'point',
# $self->{'pointStyle' . '0'});
# $self->{'gd_obj'}->setBrush($brush);
#
# # draw the point
# $self->{'gd_obj'}->line($labelX, $labelY, $labelX, $labelY, gdBrushed);
# # end for debugging
# Okay, if a bunch of very small datasets are close together, they can
# overwrite each other. The following if statement is to help keep
# labels of neighbor datasets from being overlapped. It ain't perfect,
# but it does a pretty good job.
if ( ( $label_degrees >= 270 && $label_degrees <= 360 )
|| ( $label_degrees >= 0 && $label_degrees <= 90 ) )
{
# right side of the circle
# as 0 degrees means east
# $textcolor marks everything black
$self->{'gd_obj'}->string( $font, $labelX, $labelY - $fontH * 0.5, $label, $textcolor );
}
else
{
# $textcolor marks everything black
$self->{'gd_obj'}->string( $font, $labelX - length($label) * $fontW, $labelY - $fontH * 0.5, $label, $textcolor );
}
if ( $self->true( $self->{'legend_lines'} ) )
{
$self->{'gd_obj'}->line(
$centerX + 0.5 * $diameter * cos( $degrees * $dg2rd ),
$centerY + 0.5 * $diameter * sin( $degrees * $dg2rd ),
$labelX, $labelY, $color
);
}
# reset starting point for next dataset and continue.
$start_degrees = $end_degrees;
} # end for $j
# print "Center $centerX, $centerY\n";
# print "Durchmesser $diameter\n";
# print "Hintergrund $background\n";
if ( defined( $self->{'ring'} ) && abs( $self->{'ring'} ) < 1 )
{
# print "bground $bground\n";
my $hole = ( 1 - abs( $self->{'ring'} ) );
if ( $self->true( $self->{'grey_background'} ) )
{
$insidecolor = $self->_color_role_to_index('grey_background');
}
else
{
$insidecolor = $background;
}
$self->{'gd_obj'}->filledArc( $centerX, $centerY, $hole * $diameter, $hole * $diameter, 0, 360, $insidecolor );
$self->{'gd_obj'}->arc( $centerX, $centerY, $hole * $diameter, $hole * $diameter, 0, 360, $misccolor );
}
# and finaly box it off
$self->{'gd_obj'}
->rectangle( $self->{'curr_x_min'}, $self->{'curr_y_min'}, $self->{'curr_x_max'}, $self->{'curr_y_max'}, $misccolor );
return;
}
## @fn private _draw_right_legend
# Overwrite the legend methods to get the right legend
sub _draw_right_legend
{
my $self = shift;
my $data = $self->{'dataref'};
my @labels = @{ $data->[0] };
my ( $x1, $x2, $x3, $y1, $y2, $width, $color, $misccolor, $w, $h, $brush );
my $font = $self->{'legend_font'};
my $l1 = 0;
my $l2 = 0;
my ( $i, $j, $label, $dataset_sum );
my $max_label_len = 1;
# make sure we're using a real font
unless ( ( ref($font) ) eq 'GD::Font' )
{
croak "The font you specified isn\'t a GD Font object";
}
# get the size of the font
( $h, $w ) = ( $font->height, $font->width );
# get the miscellaneous color
$misccolor = $self->_color_role_to_index('misc');
#find out what the sum of all datapoits is, needed for the Labels with percent
$dataset_sum = 0;
for my $j ( 0 .. $self->{'num_datapoints'} )
{
if ( defined $data->[1][$j] )
{
$dataset_sum += $data->[1][$j];
}
}
# find out how who wide the largest label text is
foreach (@labels)
{
if ( length($_) > $l1 )
{
$l1 = length($_);
}
}
for ( my $i = 0 ; $i < ( $self->{'num_datapoints'} ) ; $i++ )
{
if ( length( $data->[1][$i] ) > $l2 )
{
$l2 = length( $data->[1][$i] );
}
}
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$max_label_len = $l1 + $l2 + 1;
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$max_label_len = $l1 + 7;
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
$max_label_len = $l1 + $l2 + 9;
}
else
{
$max_label_len = $l1;
}
# find out how wide the largest label is
$width = ( 2 * $self->{'text_space'} )
#+ ($self->{'max_legend_label'} * $w)
+ $max_label_len * $w + $self->{'legend_example_size'} + ( 2 * $self->{'legend_space'} );
# get some starting x-y values
$x1 = $self->{'curr_x_max'} - $width;
$x2 = $self->{'curr_x_max'};
$y1 = $self->{'curr_y_min'} + $self->{'graph_border'};
$y2 =
$self->{'curr_y_min'} +
$self->{'graph_border'} +
$self->{'text_space'} +
( $self->{'num_datapoints'} * ( $h + $self->{'text_space'} ) ) +
( 2 * $self->{'legend_space'} );
# box the legend off
$self->{'gd_obj'}->rectangle( $x1, $y1, $x2, $y2, $misccolor );
# leave that nice space inside the legend box
$x1 += $self->{'legend_space'};
$y1 += $self->{'legend_space'} + $self->{'text_space'};
# now draw the actual legend
for ( 0 .. $#labels )
{
# get the color
$color = $self->_color_role_to_index( 'dataset' . $_ );
# find the x-y coords
$x2 = $x1;
$x3 = $x2 + $self->{'legend_example_size'};
$y2 = $y1 + ( $_ * ( $self->{'text_space'} + $h ) ) + $h / 2;
# do the line first
$self->{'gd_obj'}->line( $x2, $y2, $x3, $y2, $color );
# reset the brush for points
$brush = $self->_prepare_brush( $color, 'point', $self->{ 'pointStyle' . $_ } );
$self->{'gd_obj'}->setBrush($brush);
# draw the point
$self->{'gd_obj'}->line( int( ( $x3 + $x2 ) / 2 ), $y2, int( ( $x3 + $x2 ) / 2 ), $y2, gdBrushed );
# now the label
$x2 = $x3 + ( 2 * $self->{'text_space'} );
$y2 -= $h / 2;
if ( defined $data->[1][$_] )
{
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$self->{'gd_obj'}->string( $font, $x2, $y2, $labels[$_] . ' ' . $data->[1][$_], $color );
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$label = sprintf( "%s %4.2f%%", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100 );
$self->{'gd_obj'}->string( $font, $x2, $y2, $label, $color );
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
if ( $data->[1][$_] =~ /\./ )
{
$label =
sprintf( "%s %4.2f%% %.2f", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100, $data->[1][$_] );
}
else
{
$label =
sprintf( "%s %4.2f%% %d", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100, $data->[1][$_] );
}
$self->{'gd_obj'}->string( $font, $x2, $y2, $label, $color );
}
else
{
$self->{'gd_obj'}->string( $font, $x2, $y2, $labels[$_], $color );
}
}
}
# mark off the used space
$self->{'curr_x_max'} -= $width;
# and return
return 1;
}
## @fn private _draw_left_legend
# put the legend on the left of the chart
sub _draw_left_legend
{
my $self = shift;
my $data = $self->{'dataref'};
my @labels = @{ $data->[0] };
my ( $x1, $x2, $x3, $y1, $y2, $width, $color, $misccolor, $w, $h, $brush );
my $font = $self->{'legend_font'};
my $max_label_len = 1;
my $l1 = 0;
my $l2 = 0;
my ( $dataset_sum, $label );
# make sure we're using a real font
unless ( ( ref($font) ) eq 'GD::Font' )
{
croak "The font you specified isn\'t a GD Font object";
}
# get the size of the font
( $h, $w ) = ( $font->height, $font->width );
# get the miscellaneous color
$misccolor = $self->_color_role_to_index('misc');
#find out what the sum of all datapoits is, needed for the Labels with percent
$dataset_sum = 0;
for my $j ( 0 .. $self->{'num_datapoints'} )
{
if ( defined $data->[1][$j] )
{
$dataset_sum += $data->[1][$j];
}
}
# find out how who wide the largest label text is
foreach (@labels)
{
if ( length($_) > $l1 )
{
$l1 = length($_);
}
}
for ( my $i = 0 ; $i < ( $self->{'num_datapoints'} ) ; $i++ )
{
if ( length( $data->[1][$i] ) > $l2 )
{
$l2 = length( $data->[1][$i] );
}
}
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$max_label_len = $l1 + $l2 + 1;
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$max_label_len = $l1 + 7;
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
$max_label_len = $l1 + $l2 + 9;
}
else
{
$max_label_len = $l1;
}
# find out how wide the largest label is
$width =
( 2 * $self->{'text_space'} ) +
( $max_label_len * $w ) +
$self->{'legend_example_size'} +
( 2 * $self->{'legend_space'} );
# get some base x-y coordinates
$x1 = $self->{'curr_x_min'};
$x2 = $self->{'curr_x_min'} + $width;
$y1 = $self->{'curr_y_min'} + $self->{'graph_border'};
$y2 =
$self->{'curr_y_min'} +
$self->{'graph_border'} +
$self->{'text_space'} +
( $self->{'num_datapoints'} * ( $h + $self->{'text_space'} ) ) +
( 2 * $self->{'legend_space'} );
# box the legend off
$self->{'gd_obj'}->rectangle( $x1, $y1, $x2, $y2, $misccolor );
# leave that nice space inside the legend box
$x1 += $self->{'legend_space'};
$y1 += $self->{'legend_space'} + $self->{'text_space'};
# now draw the actual legend
for ( 0 .. $#labels )
{
# get the color
$color = $self->_color_role_to_index( 'dataset' . $_ );
# find the x-y coords
$x2 = $x1;
$x3 = $x2 + $self->{'legend_example_size'};
$y2 = $y1 + ( $_ * ( $self->{'text_space'} + $h ) ) + $h / 2;
# do the line first
$self->{'gd_obj'}->line( $x2, $y2, $x3, $y2, $color );
# reset the brush for points
$brush = $self->_prepare_brush( $color, 'point', $self->{ 'pointStyle' . $_ } );
$self->{'gd_obj'}->setBrush($brush);
# draw the point
$self->{'gd_obj'}->line( int( ( $x3 + $x2 ) / 2 ), $y2, int( ( $x3 + $x2 ) / 2 ), $y2, gdBrushed );
# now the label
$x2 = $x3 + ( 2 * $self->{'text_space'} );
$y2 -= $h / 2;
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$self->{'gd_obj'}->string( $font, $x2, $y2, $labels[$_] . ' ' . $data->[1][$_], $color );
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$label = sprintf( "%s %4.2f%%", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100 );
$self->{'gd_obj'}->string( $font, $x2, $y2, $label, $color );
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
if ( $data->[1][$_] =~ /\./ )
{
$label =
sprintf( "%s %4.2f%% %.2f", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100, $data->[1][$_] );
}
else
{
$label = sprintf( "%s %4.2f%% %d", $labels[$_], $data->[1][$_] / ( $dataset_sum || 1 ) * 100, $data->[1][$_] );
}
$self->{'gd_obj'}->string( $font, $x2, $y2, $label, $color );
}
else
{
$self->{'gd_obj'}->string( $font, $x2, $y2, $labels[$_], $color );
}
}
# mark off the used space
$self->{'curr_x_min'} += $width;
# and return
return 1;
}
## @fn private _draw_bottom_legend
# put the legend on the bottom of the chart
sub _draw_bottom_legend
{
my $self = shift;
my $data = $self->{'dataref'};
my @labels = @{ $data->[0] };
my ( $x1, $y1, $x2, $x3, $y2, $empty_width, $max_label_width, $cols, $rows, $color, $brush );
my ( $col_width, $row_height, $r, $c, $index, $x, $y, $w, $h );
my $font = $self->{'legend_font'};
my $max_label_len;
my $l1 = 0;
my $l2 = 0;
my ( $dataset_sum, $j );
my $label;
my $text_color = $self->_color_role_to_index( 'text' );
# make sure we're using a real font
unless ( ( ref($font) ) eq 'GD::Font' )
{
croak "The font you specified isn\'t a GD Font object";
}
# get the size of the font
( $h, $w ) = ( $font->height, $font->width );
# find the base x values
$x1 = $self->{'curr_x_min'} + $self->{'graph_border'};
# + ($self->{'y_tick_label_length'} * $self->{'tick_label_font'}->width)
# + $self->{'tick_len'} + (3 * $self->{'text_space'});
$x2 = $self->{'curr_x_max'} - $self->{'graph_border'};
if ( $self->{'y_label'} )
{
$x1 += $self->{'label_font'}->height + 2 * $self->{'text_space'};
}
if ( $self->{'y_label2'} )
{
$x2 -= $self->{'label_font'}->height + 2 * $self->{'text_space'};
}
#find out what the sum of all datapoits is, needed for the Labels with percent
$dataset_sum = 0;
for $j ( 0 .. $self->{'num_datapoints'} )
{
if ( defined $data->[1][$j] )
{
$dataset_sum += $data->[1][$j];
}
}
# find out how who wide the largest label text is, especially look what kind of
# label is needed
foreach (@labels)
{
if ( length($_) > $l1 )
{
$l1 = length($_);
}
}
for ( my $i = 0 ; $i < ( $self->{'num_datapoints'} ) ; $i++ )
{
if ( length( $data->[1][$i] ) > $l2 )
{
$l2 = length( $data->[1][$i] );
}
}
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$max_label_len = $l1 + $l2 + 1;
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$max_label_len = $l1 + 7;
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
$max_label_len = $l1 + $l2 + 9;
}
else
{
$max_label_len = $l1;
}
# figure out how wide the columns need to be, and how many we
# can fit in the space available
$empty_width = ( $x2 - $x1 ) - ( 2 * $self->{'legend_space'} );
$max_label_width = $max_label_len * $w
#$self->{'max_legend_label'} * $w
+ ( 4 * $self->{'text_space'} ) + $self->{'legend_example_size'};
$cols = int( $empty_width / $max_label_width );
unless ($cols)
{
$cols = 1;
}
$col_width = $empty_width / $cols;
# figure out how many rows we need, remember how tall they are
$rows = int( $self->{'num_datapoints'} / $cols );
unless ( ( $self->{'num_datapoints'} % $cols ) == 0 )
{
$rows++;
}
unless ($rows)
{
$rows = 1;
}
$row_height = $h + $self->{'text_space'};
# box the legend off
$y1 = $self->{'curr_y_max'} - $self->{'text_space'} - ( $rows * $row_height ) - ( 2 * $self->{'legend_space'} );
$y2 = $self->{'curr_y_max'};
$self->{'gd_obj'}->rectangle( $x1, $y1, $x2, $y2, $self->_color_role_to_index('misc') );
$x1 += $self->{'legend_space'} + $self->{'text_space'};
$x2 -= $self->{'legend_space'};
$y1 += $self->{'legend_space'} + $self->{'text_space'};
$y2 -= $self->{'legend_space'} + $self->{'text_space'};
# draw in the actual legend
for $r ( 0 .. $rows - 1 )
{
for $c ( 0 .. $cols - 1 )
{
$index = ( $r * $cols ) + $c; # find the index in the label array
if ( $labels[$index] )
{
# get the color
$color = $self->_color_role_to_index( 'dataset' . $index );
# get the x-y coordinate for the start of the example line
$x = $x1 + ( $col_width * $c );
$y = $y1 + ( $row_height * $r ) + $h / 2;
# now draw the example line
$self->{'gd_obj'}->line( $x, $y, $x + $self->{'legend_example_size'}, $y, $color );
# reset the brush for points
$brush = $self->_prepare_brush( $color, 'point', $self->{ 'pointStyle' . $index } );
$self->{'gd_obj'}->setBrush($brush);
# draw the point
$x3 = int( $x + $self->{'legend_example_size'} / 2 );
$self->{'gd_obj'}->line( $x3, $y, $x3, $y, gdBrushed );
# adjust the x-y coordinates for the start of the label
$x += $self->{'legend_example_size'} + ( 2 * $self->{'text_space'} );
$y = $y1 + ( $row_height * $r );
# now draw the label
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$self->{'gd_obj'}->string( $font, $x, $y, $labels[$index] . ' ' . $data->[1][$index], $text_color );
#$self->{'gd_obj'}->stringTTF($color, FONT, 10, 0, $x, $y+10, $labels[$index].' '.$data->[1][$index]); ############
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$label = sprintf( "%s %4.2f%%", $labels[$index], $data->[1][$index] / ( $dataset_sum || 1 ) * 100 );
$self->{'gd_obj'}->string( $font, $x, $y, $label, $color );
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
if ( $data->[1][$index] =~ /\./ )
{
$label = sprintf( "%s %4.2f%% %.2f",
$labels[$index],
$data->[1][$index] / ( $dataset_sum || 1 ) * 100,
$data->[1][$index] );
}
else
{
$label = sprintf( "%s %4.2f%% %d",
$labels[$index],
$data->[1][$index] / ( $dataset_sum || 1 ) * 100,
$data->[1][$index] );
}
$self->{'gd_obj'}->string( $font, $x, $y, $label, $text_color ); ###
# $self->{'gd_obj'}->stringTTF($color, FONT, 10, 0, $x, $y, $label);
}
else
{
$self->{'gd_obj'}->string( $font, $x, $y, $labels[$index], $text_color );
}
}
}
}
# mark off the space used
$self->{'curr_y_max'} -= ( $rows * $row_height ) + $self->{'text_space'} + ( 2 * $self->{'legend_space'} );
# now return
return 1;
}
## @fn private _draw_top_legend
# put the legend on top of the chart
sub _draw_top_legend
{
my $self = shift;
my $data = $self->{'dataref'};
my ($max_label_len);
my $l1 = 0;
my $l2 = 0;
my @labels = @{ $data->[0] };
my ( $x1, $y1, $x2, $x3, $y2, $empty_width, $max_label_width, $cols, $rows, $color, $brush );
my ( $col_width, $row_height, $r, $c, $index, $x, $y, $w, $h, $dataset_sum, $label );
my $font = $self->{'legend_font'};
# make sure we're using a real font
unless ( ( ref($font) ) eq 'GD::Font' )
{
croak "The font you specified isn\'t a GD Font object";
}
# get the size of the font
( $h, $w ) = ( $font->height, $font->width );
#find out what the sum of all datapoits is, needed for the Labels with percent
$dataset_sum = 0;
for my $j ( 0 .. $self->{'num_datapoints'} )
{
if ( defined $data->[1][$j] )
{
$dataset_sum += $data->[1][$j];
}
}
# get some base x coordinates
$x1 = $self->{'curr_x_min'} + $self->{'graph_border'};
# + $self->{'y_tick_label_length'} * $self->{'tick_label_font'}->width
# + $self->{'tick_len'} + (3 * $self->{'text_space'});
$x2 = $self->{'curr_x_max'} - $self->{'graph_border'};
if ( $self->{'y_label'} )
{
$x1 += $self->{'label_font'}->height + 2 * $self->{'text_space'};
}
if ( $self->{'y_label2'} )
{
$x2 -= $self->{'label_font'}->height + 2 * $self->{'text_space'};
}
# find out how who wide the largest label text is
foreach (@labels)
{
if ( length($_) > $l1 )
{
$l1 = length($_);
}
}
for ( my $i = 0 ; $i < ( $self->{'num_datapoints'} ) ; $i++ )
{
if ( length( $data->[1][$i] ) > $l2 )
{
$l2 = length( $data->[1][$i] );
}
}
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$max_label_len = $l1 + $l2 + 1;
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$max_label_len = $l1 + 7;
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
$max_label_len = $l1 + $l2 + 9;
}
else
{
$max_label_len = $l1;
}
# figure out how wide the columns can be, and how many will fit
$empty_width = ( $x2 - $x1 ) - ( 2 * $self->{'legend_space'} );
$max_label_width = ( 4 * $self->{'text_space'} ) + $max_label_len * $w + $self->{'legend_example_size'};
$cols = int( $empty_width / $max_label_width );
unless ($cols)
{
$cols = 1;
}
$col_width = $empty_width / $cols;
# figure out how many rows we need and remember how tall they are
$rows = int( $self->{'num_datapoints'} / $cols );
unless ( ( $self->{'num_datapoints'} % $cols ) == 0 )
{
$rows++;
}
unless ($rows)
{
$rows = 1;
}
$row_height = $h + $self->{'text_space'};
# box the legend off
$y1 = $self->{'curr_y_min'};
$y2 = $self->{'curr_y_min'} + $self->{'text_space'} + ( $rows * $row_height ) + ( 2 * $self->{'legend_space'} );
$self->{'gd_obj'}->rectangle( $x1, $y1, $x2, $y2, $self->_color_role_to_index('misc') );
# leave some space inside the legend
$x1 += $self->{'legend_space'} + $self->{'text_space'};
$x2 -= $self->{'legend_space'};
$y1 += $self->{'legend_space'} + $self->{'text_space'};
$y2 -= $self->{'legend_space'} + $self->{'text_space'};
# draw in the actual legend
for $r ( 0 .. $rows - 1 )
{
for $c ( 0 .. $cols - 1 )
{
$index = ( $r * $cols ) + $c; # find the index in the label array
if ( $labels[$index] )
{
# get the color
$color = $self->_color_role_to_index( 'dataset' . $index );
# find the x-y coords
$x = $x1 + ( $col_width * $c );
$y = $y1 + ( $row_height * $r ) + $h / 2;
# draw the line first
$self->{'gd_obj'}->line( $x, $y, $x + $self->{'legend_example_size'}, $y, $color );
# reset the brush for points
$brush = $self->_prepare_brush( $color, 'point', $self->{ 'pointStyle' . $index } );
$self->{'gd_obj'}->setBrush($brush);
# draw the point
$x3 = int( $x + $self->{'legend_example_size'} / 2 );
$self->{'gd_obj'}->line( $x3, $y, $x3, $y, gdBrushed );
# now the label
$x += $self->{'legend_example_size'} + ( 2 * $self->{'text_space'} );
$y -= $h / 2;
if ( $self->{'legend_label_values'} =~ /^value$/i )
{
$self->{'gd_obj'}->string( $font, $x, $y, $labels[$index] . ' ' . $data->[1][$index], $color );
}
elsif ( $self->{'legend_label_values'} =~ /^percent$/i )
{
$label = sprintf( "%s %4.2f%%", $labels[$index], $data->[1][$index] / ( $dataset_sum || 1 ) * 100 );
$self->{'gd_obj'}->string( $font, $x, $y, $label, $color );
}
elsif ( $self->{'legend_label_values'} =~ /^both$/i )
{
if ( $data->[1][$index] =~ /\./ )
{
$label = sprintf( "%s %4.2f%% %.2f",
$labels[$index],
$data->[1][$index] / ( $dataset_sum || 1 ) * 100,
$data->[1][$index] );
}
else
{
$label = sprintf( "%s %4.2f%% %d",
$labels[$index],
$data->[1][$index] / ( $dataset_sum || 1 ) * 100,
$data->[1][$index] );
}
$self->{'gd_obj'}->string( $font, $x, $y, $label, $color );
}
else
{
$self->{'gd_obj'}->string( $font, $x, $y, $labels[$index], $color );
}
}
}
}
# mark off the space used
$self->{'curr_y_min'} += ( $rows * $row_height ) + $self->{'text_space'} + 2 * $self->{'legend_space'};
# now return
return 1;
}
## @fn private _draw_x_ticks
# Override the ticks methods for the pie charts.\n
# Here: do nothing
sub _draw_x_ticks
{
my $self = shift;
return;
}
## @fn private _draw_y_ticks
# Override the ticks methods for the pie charts.\n
sub _draw_y_ticks
{
my $self = shift;
return;
}
## @fn private _find_y_scale
# Override the find_y_scale methods for the pie charts.\n
# Here: do nothing
sub _find_y_scale
{
my $self = shift;
return;
}
## be a good module and return 1
1;
( run in 1.213 second using v1.01-cache-2.11-cpan-5837b0d9d2c )