Chart
view release on metacpan or search on metacpan
lib/Chart/Mountain.pm view on Meta::CPAN
# Some Mountain chart details:
#
# The effective y data value for a given x point and dataset
# is the sum of the actual y data values of that dataset and
# all datasets "below" it (i.e., with higher dataset indexes).
#
# If the y data value in any dataset is undef or negative for
# a given x, then all datasets are treated as missing for that x.
#
# The y minimum is always forced to zero.
#
# To avoid a dataset area "cutting into" the area of the dataset below
# it, the y pixel for each dataset point will never be below the y pixel for
# the same point in the dataset below the dataset.
# This probably should have a custom legend method, because each
# dataset is identified by the fill color (and optional pattern)
# of its area, not just a line color. So the legend shou a square
# of the color and pattern for each dataset.
use v5.12;
package Chart::Mountain;
our @ISA = qw(Chart::Base);
our $VERSION = 'v2.403.9';
use Chart::Base;
use GD;
use Carp;
#===================#
# private methods #
#===================#
## @fn private array _find_y_range()
# Find minimum and maximum value of y data sets.
#
# @return ( min, max, flag_all_integers )
sub _find_y_range
{
my $self = shift;
# This finds the maximum point-sum over all x points,
# where the point-sum is the sum of the dataset values at that point.
# If the y value in any dataset is undef for a given x, then all datasets
# are treated as missing for that x.
my $data = $self->{'dataref'};
my $max = undef;
for my $i ( 0 .. $#{ $data->[0] } )
{
my $y_sum = $data->[1]->[$i];
if ( defined $y_sum && $y_sum >= 0 )
{
for my $dataset ( @$data[ 2 .. $#$data ] )
{ # order not important
my $datum = $dataset->[$i];
if ( defined $datum && $datum >= 0 )
{
$y_sum += $datum;
}
else
{ # undef or negative, treat all at same x as missing.
$y_sum = undef;
last;
}
}
}
if ( defined $y_sum )
{
$max = $y_sum unless defined $max && $y_sum <= $max;
}
}
( 0, $max );
}
## @fn private _draw_data
lib/Chart/Mountain.pm view on Meta::CPAN
if ( $patterns[$dataset] )
{
$self->{'gd_obj'}->filledPolygon( $poly, $color ) if $patterns[$dataset]->transparent >= 0;
$self->{'gd_obj'}->setTile( $patterns[$dataset] );
$self->{'gd_obj'}->filledPolygon( $poly, gdTiled );
}
else
{
$self->{'gd_obj'}->filledPolygon( $poly, $color );
}
# delete previous dataset's points from the polygon, update $last_vertex_count.
unless ( $dataset == 0 )
{ # don't bother do delete points after last area
while ($last_vertex_count) { $poly->deletePt(0); $last_vertex_count-- }
}
}
# Enclose the plots
$self->{'gd_obj'}->rectangle( $self->{'curr_x_min'}, $self->{'curr_y_min'}, $self->{'curr_x_max'}, $self->{'curr_y_max'},
$self->_color_role_to_index('misc') );
#get the width and the heigth of the complete picture
( $abs_x_max, $abs_y_max ) = $self->{'gd_obj'}->getBounds();
#repair the chart, if the lines are out of the borders of the chart
if ($repair_top_flag)
{
#overwrite the ugly mistakes
$self->{'gd_obj'}->filledRectangle(
$self->{'curr_x_min'}, 0, $self->{'curr_x_max'},
$self->{'curr_y_min'} - 1,
$self->_color_role_to_index('background')
);
#save the actual x and y values
$t_x_min = $self->{'curr_x_min'};
$t_x_max = $self->{'curr_x_max'};
$t_y_min = $self->{'curr_y_min'};
$t_y_max = $self->{'curr_y_max'};
#get back to the point, where everything began
$self->{'curr_x_min'} = 0;
$self->{'curr_y_min'} = 0;
$self->{'curr_x_max'} = $abs_x_max;
$self->{'curr_y_max'} = $abs_y_max;
#draw the title again
if ( $self->{'title'} )
{
$self->_draw_title();
}
#draw the sub title again
if ( $self->{'sub_title'} )
{
$self->_draw_sub_title();
}
#draw the top legend again
if ( $self->{'legend'} =~ /^top$/i )
{
$self->_draw_top_legend();
}
#reset the actual values
$self->{'curr_x_min'} = $t_x_min;
$self->{'curr_x_max'} = $t_x_max;
$self->{'curr_y_min'} = $t_y_min;
$self->{'curr_y_max'} = $t_y_max;
}
}
###############################################################
### Fix a bug in GD::Polygon.
### A patch has been submitted to Lincoln Stein.
require GD;
unless ( defined &GD::Polygon::deletePt )
{
*GD::Polygon::deletePt = sub {
my ( $self, $index ) = @_;
unless ( ( $index >= 0 ) && ( $index < @{ $self->{'points'} } ) )
{
warn "Attempt to set an undefined polygon vertex";
return undef;
}
my ($vertex) = splice( @{ $self->{'points'} }, $index, 1 );
$self->{'length'}--;
return @$vertex;
}
}
###############################################################
1;
( run in 1.058 second using v1.01-cache-2.11-cpan-5837b0d9d2c )