package Chart::Clicker::Renderer::CandleStick;
$Chart::Clicker::Renderer::CandleStick::VERSION = '2.90';
use Moose;
extends 'Chart::Clicker::Renderer';
# ABSTRACT: CandleStick renderer
use Graphics::Primitive::Brush;
use Graphics::Primitive::Operation::Fill;
use Graphics::Primitive::Operation::Stroke;
use Graphics::Primitive::Paint::Solid;
use List::Util qw(max min);
has 'bar_padding' => (
is => 'rw',
isa => 'Int',
default => 0
);
has 'brush' => (
is => 'rw',
isa => 'Graphics::Primitive::Brush',
default => sub { Graphics::Primitive::Brush->new(width => 2) }
);
override('prepare', sub {
my $self = shift;
super;
my $datasets = $self->clicker->get_datasets_for_context($self->context);
$self->{SCOUNT} = 1;
$self->{KEYCOUNT} = 0;
foreach my $ds (@{ $datasets }) {
$self->{SCOUNT} += $ds->count;
if($ds->max_key_count > $self->{KEYCOUNT}) {
$self->{KEYCOUNT} = $ds->max_key_count;
}
}
return 1;
});
override('finalize', sub {
my ($self) = @_;
my $clicker = $self->clicker;
my $width = $self->width;
my $height = $self->height;
my $dses = $clicker->get_datasets_for_context($self->context);
my $padding = $self->bar_padding + $self->brush->width;
my $bwidth = int(($width / $dses->[0]->max_key_count)) - $self->bar_padding;
my $hbwidth = int($bwidth / 2);
my $scounter = $self->{SCOUNT};
foreach my $ds (@{ $dses }) {
foreach my $series (@{ $ds->series }) {
my $color = $clicker->color_allocator->next;
# TODO if undef...
my $ctx = $clicker->get_context($ds->context);
my $domain = $ctx->domain_axis;
my $range = $ctx->range_axis;
my $ocbwidth = $bwidth - ($bwidth * $domain->fudge_amount);
my $cbwidth = $ocbwidth / $self->{SCOUNT};
my $hcbwidth = $cbwidth / 2;
my $offset = $bwidth - ($bwidth / $self->{SCOUNT});
my $min = $range->range->lower;
my @highs = @{ $series->highs };
my @lows = @{ $series->lows };
my @opens = @{ $series->opens };
my @vals = @{ $series->values };
my @keys = @{ $series->keys };
for(0..($series->key_count - 1)) {
my $x = $domain->mark($width, $keys[$_]);
$x -= $cbwidth * $scounter;
$x += $offset;
my $openy = $height - $range->mark($height, $opens[$_]);
my $closey = $height - $range->mark($height, $vals[$_]);
my $highy = $height - $range->mark($height, $highs[$_]);
my $lowy = $height - $range->mark($height, $lows[$_]);
my $_height = $closey - $openy;
$self->move_to($x - $hcbwidth, $openy);
$self->rectangle(
$cbwidth, $_height
);
my $op;
if($_height < 0) {
# We fill the bar if it closed higher
$op = Graphics::Primitive::Operation::Fill->new(
paint => Graphics::Primitive::Paint::Solid->new(
color => $color
)
);
} else {
# We stroke the bar if it closed lower
$op = Graphics::Primitive::Operation::Stroke->new(
brush => $self->brush->clone
);
$op->brush->color($color);
$op->brush->width(2);
}
$self->do($op);
$self->move_to($x, min($openy, $closey));
$self->line_to($x, $highy);
$self->move_to($x, max($openy, $closey));
$self->line_to($x, $lowy);
my $lineop = Graphics::Primitive::Operation::Stroke->new(
brush => $self->brush->clone
);
$lineop->brush->color($color);
$self->do($lineop);
}
$scounter--;
}
}
return 1;
});
__PACKAGE__->meta->make_immutable;
no Moose;
1;
__END__
=pod
=head1 NAME
Chart::Clicker::Renderer::CandleStick - CandleStick renderer
=head1 VERSION
version 2.90
=head1 SYNOPSIS
my $br = Chart::Clicker::Renderer::CandleStick->new;
=head1 DESCRIPTION
Chart::Clicker::Renderer::CandleStick renders a dataset as a candlestick style
bar chart.
=for HTML <p><img src="http://gphat.github.com/chart-clicker/static/images/examples/candlestick.png" width="500" height="250" alt="Candlestick Chart" /></p>
=head1 ATTRIBUTES
=head2 bar_padding
How much padding to put around a bar. A padding of 4 will result in 2 pixels
on each side.
=head2 brush
Set/Get the L<brush|Graphics::Primitive::Brush> to use around each bar and on each line.
=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