File Coverage

blib/lib/Chart/Clicker/Renderer/CandleStick.pm
Criterion Covered Total %
statement 21 21 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 28 28 100.0


line stmt bran cond sub pod time code
1             package Chart::Clicker::Renderer::CandleStick;
2             $Chart::Clicker::Renderer::CandleStick::VERSION = '2.88';
3 1     1   63030 use Moose;
  1         535409  
  1         9  
4              
5             extends 'Chart::Clicker::Renderer';
6              
7             # ABSTRACT: CandleStick renderer
8              
9 1     1   9254 use Graphics::Primitive::Brush;
  1         345322  
  1         54  
10 1     1   4766 use Graphics::Primitive::Operation::Fill;
  1         53838  
  1         40  
11 1     1   923 use Graphics::Primitive::Operation::Stroke;
  1         46205  
  1         39  
12 1     1   952 use Graphics::Primitive::Paint::Solid;
  1         39169  
  1         46  
13              
14 1     1   11 use List::Util qw(max min);
  1         3  
  1         1128  
15              
16              
17             has 'bar_padding' => (
18             is => 'rw',
19             isa => 'Int',
20             default => 0
21             );
22              
23              
24             has 'brush' => (
25             is => 'rw',
26             isa => 'Graphics::Primitive::Brush',
27             default => sub { Graphics::Primitive::Brush->new(width => 2) }
28             );
29              
30             override('prepare', sub {
31             my $self = shift;
32              
33             super;
34              
35             my $datasets = $self->clicker->get_datasets_for_context($self->context);
36              
37             $self->{SCOUNT} = 1;
38             $self->{KEYCOUNT} = 0;
39             foreach my $ds (@{ $datasets }) {
40             $self->{SCOUNT} += $ds->count;
41             if($ds->max_key_count > $self->{KEYCOUNT}) {
42             $self->{KEYCOUNT} = $ds->max_key_count;
43             }
44             }
45              
46             return 1;
47             });
48              
49             override('finalize', sub {
50             my ($self) = @_;
51              
52             my $clicker = $self->clicker;
53              
54             my $width = $self->width;
55             my $height = $self->height;
56              
57             my $dses = $clicker->get_datasets_for_context($self->context);
58              
59             my $padding = $self->bar_padding + $self->brush->width;
60              
61             my $bwidth = int(($width / $dses->[0]->max_key_count)) - $self->bar_padding;
62             my $hbwidth = int($bwidth / 2);
63              
64             my $scounter = $self->{SCOUNT};
65             foreach my $ds (@{ $dses }) {
66             foreach my $series (@{ $ds->series }) {
67              
68             my $color = $clicker->color_allocator->next;
69              
70             # TODO if undef...
71             my $ctx = $clicker->get_context($ds->context);
72             my $domain = $ctx->domain_axis;
73             my $range = $ctx->range_axis;
74              
75             my $ocbwidth = $bwidth - ($bwidth * $domain->fudge_amount);
76             my $cbwidth = $ocbwidth / $self->{SCOUNT};
77             my $hcbwidth = $cbwidth / 2;
78             my $offset = $bwidth - ($bwidth / $self->{SCOUNT});
79              
80             my $min = $range->range->lower;
81              
82             my $height = $self->height;
83              
84             my @highs = @{ $series->highs };
85             my @lows = @{ $series->lows };
86             my @opens = @{ $series->opens };
87             my @vals = @{ $series->values };
88              
89             my @keys = @{ $series->keys };
90             for(0..($series->key_count - 1)) {
91             my $x = $domain->mark($width, $keys[$_]);
92              
93             $x -= $cbwidth * $scounter;
94             $x += $offset;
95              
96             my $openy = $height - $range->mark($height, $opens[$_]);
97             my $closey = $height - $range->mark($height, $vals[$_]);
98             my $highy = $height - $range->mark($height, $highs[$_]);
99             my $lowy = $height - $range->mark($height, $lows[$_]);
100              
101             my $height = $closey - $openy;
102              
103             $self->move_to($x - $hcbwidth, $openy);
104             $self->rectangle(
105             $cbwidth, $height
106             );
107              
108             my $op;
109             if($height < 0) {
110             # We fill the bar if it closed higher
111             $op = Graphics::Primitive::Operation::Fill->new(
112             paint => Graphics::Primitive::Paint::Solid->new(
113             color => $color
114             )
115             );
116             } else {
117             # We stroke the bar if it closed lower
118             $op = Graphics::Primitive::Operation::Stroke->new(
119             brush => $self->brush->clone
120             );
121             $op->brush->color($color);
122             $op->brush->width(2);
123             }
124             $self->do($op);
125              
126             $self->move_to($x, min($openy, $closey));
127             $self->line_to($x, $highy);
128              
129             $self->move_to($x, max($openy, $closey));
130             $self->line_to($x, $lowy);
131              
132             my $lineop = Graphics::Primitive::Operation::Stroke->new(
133             brush => $self->brush->clone
134             );
135             $lineop->brush->color($color);
136              
137             $self->do($lineop);
138              
139             }
140              
141             $scounter--;
142             }
143             }
144              
145             return 1;
146             });
147              
148             __PACKAGE__->meta->make_immutable;
149              
150 1     1   8 no Moose;
  1         2  
  1         8  
151              
152             1;
153              
154             __END__
155              
156             =pod
157              
158             =head1 NAME
159              
160             Chart::Clicker::Renderer::CandleStick - CandleStick renderer
161              
162             =head1 VERSION
163              
164             version 2.88
165              
166             =head1 SYNOPSIS
167              
168             my $br = Chart::Clicker::Renderer::CandleStick->new;
169              
170             =head1 DESCRIPTION
171              
172             Chart::Clicker::Renderer::CandleStick renders a dataset as a candlestick style
173             bar chart.
174              
175             =for HTML <p><img src="http://gphat.github.com/chart-clicker/static/images/examples/candlestick.png" width="500" height="250" alt="Candlestick Chart" /></p>
176              
177             =head1 ATTRIBUTES
178              
179             =head2 bar_padding
180              
181             How much padding to put around a bar. A padding of 4 will result in 2 pixels
182             on each side.
183              
184             =head2 brush
185              
186             Set/Get the L<brush|Graphics::Primitive::Brush> to use around each bar and on each line.
187              
188             =head1 AUTHOR
189              
190             Cory G Watson <gphat@cpan.org>
191              
192             =head1 COPYRIGHT AND LICENSE
193              
194             This software is copyright (c) 2014 by Cold Hard Code, LLC.
195              
196             This is free software; you can redistribute it and/or modify it under
197             the same terms as the Perl 5 programming language system itself.
198              
199             =cut