The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

$Chart::Clicker::Renderer::PolarArea::VERSION = '2.90';
use Moose;
# ABSTRACT: Polar Area renderer
use Scalar::Util qw(refaddr);
has 'border_color' => (
is => 'rw',
isa => 'Graphics::Color::RGB',
default => sub { Graphics::Color::RGB->new },
);
has 'brush' => (
is => 'rw',
isa => 'Graphics::Primitive::Brush',
default => sub { Graphics::Primitive::Brush->new }
);
has '_accum' => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has '_colors' => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has '_largest' => (
is => 'rw',
isa => 'Num',
default => 0
);
my $TO_RAD = (4 * atan2(1, 1)) / 180;
override('prepare', sub {
my $self = shift;
super;
my $clicker = $self->clicker;
# TODO
# This implementation is dumb... the better way would be:
# draw the first slice
# remember once of the corner points
# when drawing the next slice, start at the remembered point and arc-neg with no radius
# then arc pos again
# or something like that
# This is really hinky, basically since figuring out the arcs and whatnot
# is a pain in the ass, we employ the painter's algorithm and draw
# the last series first, then paint the next one over it. As such, we have
# to know the total "accumulated" value for each series' position so that
# we can decrement it on each run through the series... this finds the
# totals
my $dses = $clicker->get_datasets_for_context($self->context);
foreach my $ds (@{ $dses }) {
my $lvs = $ds->largest_value_slice;
if($lvs > $self->_largest) {
$self->_largest($lvs)
}
my $count = $ds->max_key_count;
for my $pos (0..$count - 1) {
my $vals = $ds->get_series_values($pos);
my $total = 0;
foreach my $v (@{ $vals }) {
$total += $v;
}
$self->_accum->[$pos] += $total;
}
}
});
override('finalize', sub {
my $self = shift;
my $clicker = $self->clicker;
my $radius = $self->height;
if($self->width < $self->height) {
$radius = $self->width;
}
$radius = $radius / 2;
# Take into account the line around the edge when working out the radius
$radius -= $self->brush->width;
my $height = $self->height;
my $linewidth = 1;
my $midx = $self->width / 2;
my $midy = $height / 2;
my $per = $radius / $self->_largest;
my $dses = $clicker->get_datasets_for_context($self->context);
foreach my $ds (@{ $dses }) {
foreach my $series (@{ $ds->series }) {
push(@{ $self->_colors }, $clicker->color_allocator->next);
}
}
# my $dses = $clicker->get_datasets_for_context($self->context);
foreach my $ds (reverse @{ $dses }) {
my $ctx = $clicker->get_context($ds->context);
my $domain = $ctx->domain_axis;
my $range = $ctx->range_axis;
foreach my $series (reverse @{ $ds->series }) {
my $pos = 0;
my $degs = 360 / scalar(@{ $series->values });
my $color = pop(@{ $self->_colors });
my $v = 0;
foreach my $val (@{ $series->values }) {
my $foo = $self->_accum->[$v];
# Remove this value worth of accumulate from the accumulator
# so that our size is properly pushed out, see above comment
# in prepare...
$self->_accum->[$v] -= $val;
$self->move_to($midx, $midy);
$self->arc(($self->_accum->[$v] + $val) * $per, ($pos - $degs) * $TO_RAD, $pos * $TO_RAD);
$self->close_path;
my $fop = Graphics::Primitive::Operation::Fill->new(
preserve => 1,
paint => Graphics::Primitive::Paint::Solid->new(
color => $color,
)
);
$self->do($fop);
my $op = Graphics::Primitive::Operation::Stroke->new;
$op->brush($self->brush->clone);
$op->brush->color($self->border_color);
$self->do($op);
$pos += $degs;
$v++;
}
}
}
return 1;
});
__PACKAGE__->meta->make_immutable;
no Moose;
1;
__END__
=pod
=head1 NAME
Chart::Clicker::Renderer::PolarArea - Polar Area renderer
=head1 VERSION
version 2.90
=head1 SYNOPSIS
my $par = Chart::Clicker::Renderer::PolarArea->new;
# Optionally set the stroke
$par->brush->width(2);
# and color
$par->border_color(Graphics::Color::RGB->new(red => 1, green => 1, blue => 1));
=head1 DESCRIPTION
Chart::Clicker::Renderer::PolarArea renders each series as a slice of a pie.
The values of the series determine the radius of each slice, with larger
values making the slices longer. The 360 degrees of pie is divided equally.
=for HTML <p><img src=http://gphat.github.com/chart-clicker/static/images/examples/polararea.png" width="300" height="250" alt="Polar Area Chart" /></p>
=head1 ATTRIBUTES
=head2 border_color
Set/Get the L<color|Graphics::Color::RGB> to use for the border.
=head2 brush
Set/Get a L<brush|Graphics::Primitive::Brush> to be used for the polar area's borders, which are around
each slice.
=head1 AUTHOR
Cory G Watson <gphat@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by Cory G Watson.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut