File Coverage

blib/lib/Chart/Clicker/Drawing/ColorAllocator.pm
Criterion Covered Total %
statement 32 35 91.4
branch n/a
condition n/a
subroutine 6 7 85.7
pod 2 2 100.0
total 40 44 90.9


line stmt bran cond sub pod time code
1             package Chart::Clicker::Drawing::ColorAllocator;
2             $Chart::Clicker::Drawing::ColorAllocator::VERSION = '2.88';
3 9     9   1444487 use Moose;
  9         572612  
  9         85  
4              
5             # ABSTRACT: Color picker
6              
7 9     9   72731 use Graphics::Color::RGB;
  9         965429  
  9         317  
8 9     9   15624 use Color::Scheme;
  9         113228  
  9         6352  
9              
10              
11              
12             has 'colors' => (
13             traits => [ 'Array' ],
14             is => 'rw',
15             isa => 'ArrayRef',
16             default => sub { [] },
17             handles => {
18             'add_to_colors' => 'push',
19             'clear_colors' => 'clear',
20             'color_count' => 'count',
21             'get_color' => 'get'
22             }
23             );
24              
25              
26             has 'position' => ( is => 'rw', isa => 'Int', default => -1 );
27              
28              
29             has 'color_scheme' => (
30             is => 'rw',
31             isa => 'Color::Scheme',
32             lazy_build => 1,
33             );
34              
35              
36             has 'seed_hue' => (
37             is => 'rw',
38             isa => 'Int',
39             required => 1,
40             default => sub { 270 },
41             );
42              
43              
44             has hues => (
45             is => 'rw',
46             isa => 'ArrayRef',
47             required => 1,
48             lazy => 1,
49             default => sub {
50             my $seed = shift->seed_hue;
51             [ map { ($seed + $_) % 360 } (0, 45, 75, 15, 60, 30) ]
52             },
53             );
54              
55              
56             has shade_order => (
57             is => 'rw',
58             isa => 'ArrayRef',
59             required => 1,
60             default => sub { [1, 3, 0, 2] },
61             );
62              
63             sub _build_color_scheme {
64 1     1   1 my $self = shift;
65 1         13 my $scheme = Color::Scheme->new;
66 1         455 $scheme->scheme('tetrade');
67 1         17 $scheme->web_safe(1);
68 1         10 $scheme->distance(1);
69 1         62 return $scheme;
70             }
71              
72              
73             sub next {
74             my $self = shift;
75              
76             $self->position($self->position + 1);
77              
78             return $self->colors->[$self->position];
79             }
80              
81             # Before we attempt to get the next color, we'll instantiate it if we need it
82             # that way we don't waste a bunch of memory with useless colors.
83             before 'next' => sub {
84             my $self = shift;
85              
86             my $pos = $self->position;
87             if(!defined($self->colors->[$pos + 1])) {
88             $self->add_to_colors($self->allocate_color);
89             }
90             };
91              
92              
93             sub allocate_color {
94 97     97 1 150 my $self = shift;
95              
96 97         4003 my $pos = $self->position + 1;
97 97         4182 my $scheme = $self->color_scheme;
98              
99 97         153 my $hue_cnt = @{ $self->hues };
  97         3914  
100 97         248 my $hue_pos = int($pos / 4) % $hue_cnt;
101 97         4748 $scheme->from_hue($self->hues->[$hue_pos]);
102              
103 97         8645 my $shade_pos = int($pos / ( $hue_cnt * 4)) % 4;
104 97         4301 my $shade_idx = $self->shade_order->[$shade_pos];
105 97         167 my $color_idx = $pos % 4;
106              
107 97         304 my $color_hex = $scheme->colorset->[$color_idx]->[$shade_idx];
108 97         109263 my ($r,$g,$b) = ( map{ hex } ($color_hex =~ /(..)(..)(..)/));
  291         543  
109 97         3854 my $color = Graphics::Color::RGB->new(
110             red => $r / 255,
111             green => $g / 255,
112             blue => $b / 255,
113             alpha => 1,
114             )
115             }
116              
117              
118             sub reset {
119 0     0 1   my $self = shift;
120              
121 0           $self->position(-1);
122 0           return 1;
123             }
124              
125             __PACKAGE__->meta->make_immutable;
126              
127 9     9   132 no Moose;
  9         21  
  9         113  
128              
129             1;
130              
131             __END__
132              
133             =pod
134              
135             =head1 NAME
136              
137             Chart::Clicker::Drawing::ColorAllocator - Color picker
138              
139             =head1 VERSION
140              
141             version 2.88
142              
143             =head1 SYNOPSIS
144              
145             use Graphics::Color::RGB;
146             use Chart::Clicker::Drawing::ColorAllocator;
147              
148             my $ca = Chart::Clicker::Drawing::ColorAllocator->new({
149             colors => [
150             Graphics::Color::RGB->new(
151             red => 1.0, green => 0, blue => 0, alpha => 1.0
152             ),
153             #...
154             ]
155             });
156              
157             my $red = $ca->get(0);
158              
159             #or let Chart::Clicker autmatically pick complementing colors for you
160             my $ca2 = Chart::Clicker::Drawing::ColorAllocator->new({
161             seed_hue => 0, #red
162             });
163              
164             =head1 DESCRIPTION
165              
166             Allocates colors for use in the chart. The position in the color allocator
167             corresponds to the series that will be colored.
168              
169             =head1 AUTOMATIC COLOR ALLOCATION
170              
171             This module has the capacity to automatically allocate 96 individual colors
172             using L<Color::Scheme>. It does so by picking 4 hues equally spaced in the
173             color wheel from the C<seed_hue> (0 (red) would be complimented by 270 (blue),
174             180 (green) and 90 (yellow)). After those colors are allocated it moves on to
175             picking from the colors between those ( 45, 135, 215, 305 ) etc. Once all
176             values of C<hues> have been utilized, it repeats them using a different shade.
177             This has the effect of generating evenly spaced complementing colors to ensure
178             colors are well ditinguishable from one another and have appropriate contrast.
179              
180             =head2 position
181              
182             Gets the current position.
183              
184             =head1 ATTRIBUTES
185              
186             =head2 colors
187              
188             An arrayref of colors that will be used for series that Clicker draws.
189              
190             =head2 color_scheme
191              
192             A lazy-building L<Color::Scheme> object used to generate the color scheme of
193             the chart;
194              
195             =head2 seed_hue
196              
197             The interger value of the first hue used when computing the tetrade color
198             scheme. Setting this will affect the hue of the first color allocated.
199             Subsequent colors will be allocated based on their distance from this color
200             to maintain sifficient contrast between colors. If not specified the seed_hue
201             will default to 270, blue.
202              
203             =head2 hues
204              
205             An array reference of evenly spaced seed hues for color allocation. By default
206             it will use the seed hue plus 0, 45, 75, 15, 60 and 30 which is enough to cover
207             all web-safe colors when using a tetrade color scheme.
208              
209             =head2 shade_order
210              
211             An array reference of the order in which the different shades of each color
212             will be used for every color scheme generated. It defaults to 1, 3, 0, 2 for
213             optimum color spacing.
214              
215             =head1 METHODS
216              
217             =head2 add_to_colors
218              
219             Add a color to this allocator.
220              
221             =head2 clear_colors
222              
223             Clear this allocator's colors
224              
225             =head2 color_count
226              
227             Get the number of colors in this allocator.
228              
229             =head2 get_color ($index)
230              
231             Gets the color at the specified index. Returns undef if that position has no
232             color.
233              
234             =head2 next
235              
236             Returns the next color. Each call to next increments the position, so
237             subsequent calls will return different colors.
238              
239             =head2 allocate_color
240              
241             Determines what the next color should be.
242              
243             =head2 reset
244              
245             Resets this allocator back to the beginning.
246              
247             =head1 AUTHOR
248              
249             Cory G Watson <gphat@cpan.org>
250              
251             =head1 COPYRIGHT AND LICENSE
252              
253             This software is copyright (c) 2014 by Cold Hard Code, LLC.
254              
255             This is free software; you can redistribute it and/or modify it under
256             the same terms as the Perl 5 programming language system itself.
257              
258             =cut