| Chart-Clicker documentation | Contained in the Chart-Clicker distribution. |
Chart::Clicker::Renderer::StackedBar - Stacked Bar renderer
Chart::Clicker::Renderer::StackedBar renders a dataset as stacked bars.
my $br = Chart::Clicker::Renderer::Bar->new;
How much padding to put around a bar. A padding of 4 will result in 2 pixels on each side.
Allows you to override the calculation that determines the optimal width for bars. Be careful using this as it can making things look terrible.
A stroke to use on each bar.
If true this value will be used when setting the opacity of the bar's fill.
Prepare the renderer
Cory G Watson <gphat@cpan.org>
perl(1)
You can redistribute and/or modify this code under the same terms as Perl itself.
| Chart-Clicker documentation | Contained in the Chart-Clicker distribution. |
package Chart::Clicker::Renderer::StackedBar; use Moose; extends 'Chart::Clicker::Renderer'; use Graphics::Primitive::Brush; use Graphics::Primitive::Paint::Solid; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; has '+additive' => ( default => 1 ); has 'bar_padding' => ( is => 'rw', isa => 'Int', default => 0 ); has 'bar_width' => ( is => 'rw', isa => 'Num', predicate => 'has_bar_width' ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has 'opacity' => ( is => 'rw', isa => 'Num', default => 0 ); override('prepare', sub { my ($self) = @_; super; my $dses = $self->clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { if(!defined($self->{KEYCOUNT})) { $self->{KEYCOUNT} = $ds->max_key_count; } $self->{SCOUNT} += $ds->count; } return 1; }); override('finalize', sub { my ($self) = @_; my $clicker = $self->clicker; my $height = $self->height; my $width = $self->width; my $dses = $clicker->get_datasets_for_context($self->context); my $ctx = $clicker->get_context($dses->[0]->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $padding = $self->bar_padding; my $strokewidth = $self->brush->width; $padding += $strokewidth; my $bwidth; if($self->has_bar_width) { $bwidth = $self->bar_width; } else { $bwidth = int(($width - ($width * $domain->fudge_amount) - ($padding / 2 * $self->{KEYCOUNT})) / ($self->{KEYCOUNT})); } my $hbwidth = $bwidth / 2; # Fetch all the colors we'll need. Since we build each vertical bar from # top to bottom, we'll need to change colors vertically. for (my $i = 0; $i < $self->{SCOUNT}; $i++) { push(@{ $self->{COLORS} }, $clicker->color_allocator->next); } my @keys = $dses->[0]->get_all_series_keys; # Iterate over each key... for (my $i = 0; $i < scalar(@keys); $i++) { # Get all the values from every dataset's series for each key my @values; foreach my $ds (@{ $dses }) { push(@values, $ds->get_series_values($i)); } # Mark the x, since it's the same for each Y value my $x = $domain->mark($width, $keys[$i],); my $accum = 0; my $val = 0; for my $j (0 .. $#values) { my $sval = $values[$j]; if(defined($sval)) { next if $sval == $range->baseline; # no reason to draw anything if no value $val += $sval; } my $y = $range->mark($height, $val); next unless defined($y); $self->move_to($x - $hbwidth, $height - $y + $self->brush->width * 2); $self->rectangle($bwidth, $y - $accum - 1); # Accumulate the Y value, as it dictates how much we bump up the # next bar. $accum += $y - $accum; my $color = $self->{COLORS}->[$j]; my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new ); if($self->opacity) { my $fillcolor = $color->clone; $fillcolor->alpha($self->opacity); $fillop->paint->color($fillcolor); # Since we're going to stroke this, we want to preserve it. $fillop->preserve(1); } else { $fillop->paint->color($color); } $self->do($fillop); if($self->opacity) { my $strokeop = Graphics::Primitive::Operation::Stroke->new; $strokeop->brush->color($color); $self->do($strokeop); } } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__