From Patrick Michaud:
[imager-graph.git] / Graph.pm
1 package Imager::Graph;
2 require 5.005;
3
4 =head1 NAME
5
6 Imager::Graph - Perl extension for producing Graphs using the Imager library.
7
8 =head1 SYNOPSIS
9
10   use Imager::Graph::Sub_class;
11   my $chart = Imager::Graph::Sub_class->new;
12   my $img = $chart->draw(data=> \@data, ...)
13     or die $chart->error;
14
15 =head1 DESCRIPTION
16
17 Imager::Graph provides style information to its base classes.  It
18 defines the colors, text display information and fills based on both
19 built-in styles and modifications supplied by the user to the draw()
20 method.
21
22 =over
23
24 =cut
25
26 use strict;
27 use vars qw($VERSION);
28 use Imager qw(:handy);
29 use Imager::Fountain;
30
31 $VERSION = '0.06';
32
33 # the maximum recursion depth in determining a color, fill or number
34 use constant MAX_DEPTH => 10;
35
36 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
37
38 =item new
39
40 This is a simple constructor.  No parameters required.
41
42 =cut
43
44 sub new {
45   bless {}, $_[0];
46 }
47
48 =item set_graph_size($size)
49
50 Sets the size of the graph (in pixels) within the image.  The size of the image defaults to 1.5 * $graph_size.
51
52 =cut
53
54 sub set_graph_size {
55   $_[0]->{'custom_style'}->{'size'} = $_[1];
56 }
57
58 =item set_image_width($width)
59
60 Sets the width of the image in pixels.
61
62 =cut
63
64 sub set_image_width {
65   $_[0]->{'custom_style'}->{'width'} = $_[1];
66 }
67
68 =item set_image_height($height)
69
70 Sets the height of the image in pixels.
71
72 =cut
73
74 sub set_image_height {
75   $_[0]->{'custom_style'}->{'height'} = $_[1];
76 }
77
78 =item add_data_series([8, 6, 7, 5, 3, 0, 9], 'Series Name');
79
80 Adds a data series to the graph.  For L<Imager::Graph::Pie>, only one data series can be added.
81
82 =cut
83
84 sub add_data_series {
85   my $self = shift;
86   my $data_ref = shift;
87   my $series_name = shift;
88
89   my $graph_data = $self->{'graph_data'} || [];
90
91   push @$graph_data, { data => $data_ref, series_name => $series_name };
92
93   $self->{'graph_data'} = $graph_data;
94   return;
95 }
96
97 sub _get_data_series {
98   my ($self, $opts) = @_;
99
100   # return the data supplied to draw() if any.
101   if ($opts->{data}) {
102     # one or multiple series?
103     my $data = $opts->{data};
104     if (@$data && ref $data->[0] && ref $data->[0] =~ /ARRAY/) {
105       return $data;
106     }
107     else {
108       return [ { data => $data } ];
109     }
110   }
111
112   return $self->{'graph_data'};
113 }
114
115 =item set_labels(['label1', 'label2' ... ])
116
117 Labels the specific data points.  For line/bar graphs, this is the x-axis.  For pie graphs, it is the label for the wedges.
118
119 =cut
120
121 sub set_labels {
122   $_[0]->{'labels'} = $_[1];
123 }
124
125 sub _get_labels {
126   my ($self, $opts) = @_;
127
128   $opts->{labels}
129     and return $opts->{labels};
130
131   return $_[0]->{'labels'}
132 }
133
134 =item set_title($title)
135
136 Sets the title of the graph.  Requires setting a font.
137
138 =cut
139
140 sub set_title {
141   $_[0]->{'custom_style'}->{'title'}->{'text'} = $_[1];
142 }
143
144 =item set_font($font)
145
146 Sets the font to use for text.  Takes an L<Imager::Font> object.
147
148 =cut
149
150 sub set_font {
151   $_[0]->{'custom_style'}->{'font'} = $_[1];
152 }
153
154 =item set_style($style_name)
155
156 Sets the style to be used for the graph.  Imager::Graph comes with several pre-defined styles: fount_lin (default), fount_rad, mono, primary_red, and primary.
157
158 =cut
159
160 sub set_style {
161   $_[0]->{'style'} = $_[1];
162 }
163
164 sub _get_style {
165   my ($self, $opts) = @_;
166
167   $opts->{style}
168     and return $opts->{style};
169
170   return $self->{'style'};
171 }
172
173 =item error
174
175 Returns an error message.  Only valid if the draw() method returns false.
176
177 =cut
178
179 sub error {
180   $_[0]->{_errstr};
181 }
182
183 =item draw
184
185 Creates a new image, draws the chart onto that image and returns it.
186
187 Optionally, instead of using the api methods to configure your chart,
188 you can supply a C<data> parameter in the format
189 required by that particular graph, and if your graph will use any
190 text, a C<font> parameter
191
192 You can also supply many different parameters which control the way
193 the graph looks.  These are supplied as keyword, value pairs, where
194 the value can be a hashref containing sub values.
195
196 The C<style> parameter will selects a basic color set, and possibly
197 sets other related parameters.  See L</"STYLES">.
198
199  my $font = Imager::Font->new(file => 'ImUgly.ttf');
200  my $img = $chart->draw(
201                  data    => \@data,
202                  font    => $font,
203                  title   => {
204                                  text  => "Hello, World!",
205                                  size  => 36,
206                                  color => 'FF0000'
207                             }
208                  );
209
210 When referring to a single sub-value this documentation will refer to
211 'title.color' rather than 'the color element of title'.
212
213 Returns the graph image on success, or false on failure.
214
215 =back
216
217 =head1 STYLES
218
219 The currently defined styles are:
220
221 =over
222
223 =item primary
224
225 a light grey background with no outlines.  Uses primary colors for the
226 data fills.
227
228 =item primary_red
229
230 a light red background with no outlines.  Uses primary colors for the
231 data fills.
232
233 Graphs drawn using this style should save well as a gif, even though
234 some graphs may perform a slight blur.
235
236 This was the default style, but the red was too loud.
237
238 =item mono
239
240 designed for monochrome output, such as most laser printers, this uses
241 hatched fills for the data, and no colors.  The returned image is a
242 one channel image (which can be overridden with the C<channels>
243 parameter.)
244
245 You can also override the colors used by all components for background
246 or drawing by supplying C<fg> and/or C<bg> parameters.  ie.  if you
247 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
248 else will be drawn in red.  Another use might be to set a transparent
249 background, by supplying C<<bg=>'00000000', channels=>4>>.
250
251 This style outlines the legend if present and outlines the hashed fills.
252
253 =item fount_lin
254
255 designed as a "pretty" style this uses linear fountain fills for the
256 background and data fills, and adds a drop shadow.
257
258 You can override the value used for text and outlines by setting the
259 C<fg> parameter.
260
261 This is the default style.
262
263 =item fount_rad
264
265 also designed as a "pretty" style this uses radial fountain fills for
266 the data and a linear blue to green fill for the background.
267
268 =back
269
270 =head1 Style API
271
272 To set or override styles, you can use the following methods:
273
274 =over 4
275
276 =item set_image_background
277
278 =cut
279
280 sub set_image_background {
281   $_[0]->{'custom_style'}->{'back'} = $_[1];
282 }
283
284 =item set_channels
285
286 =cut
287
288 sub set_channels {
289   $_[0]->{'custom_style'}->{'channels'} = $_[1];
290 }
291
292 =item set_line_color
293
294 =cut
295
296 sub set_line_color {
297   $_[0]->{'custom_style'}->{'line'} = $_[1];
298 }
299
300 =item set_title_font_size
301
302 =cut
303
304 sub set_title_font_size {
305   $_[0]->{'custom_style'}->{'title'}->{'size'} = $_[1];
306 }
307
308 =item set_title_font_color
309
310 =cut
311
312 sub set_title_font_color {
313   $_[0]->{'custom_style'}->{'title'}->{'color'} = $_[1];
314 }
315
316 =item set_title_horizontal_align
317
318 =cut
319
320 sub set_title_horizontal_align {
321   $_[0]->{'custom_style'}->{'title'}->{'halign'} = $_[1];
322 }
323
324 =item set_title_vertical_align
325
326 =cut
327
328 sub set_title_vertical_align {
329   $_[0]->{'custom_style'}->{'title'}->{'valign'} = $_[1];
330 }
331
332 =item set_text_font_color
333
334 =cut
335
336 sub set_text_font_color {
337   $_[0]->{'custom_style'}->{'text'}->{'color'} = $_[1];
338 }
339
340 =item set_text_font_size
341
342 =cut
343
344 sub set_text_font_size {
345   $_[0]->{'custom_style'}->{'text'}->{'size'} = $_[1];
346 }
347
348 =item set_graph_background_color
349
350 =cut
351
352 sub set_graph_background_color {
353   $_[0]->{'custom_style'}->{'bg'} = $_[1];
354 }
355
356 =item set_graph_foreground_color
357
358 =cut
359
360 sub set_graph_foreground_color {
361   $_[0]->{'custom_style'}->{'fg'} = $_[1];
362 }
363
364 =item set_legend_font_color
365
366 =cut
367
368 sub set_legend_font_color {
369   $_[0]->{'custom_style'}->{'legend'}->{'color'} = $_[1];
370 }
371
372 =item set_legend_font
373
374 =cut
375
376 sub set_legend_font {
377   $_[0]->{'custom_style'}->{'legend'}->{'font'} = $_[1];
378 }
379
380 =item set_legend_font_size
381
382 =cut
383
384 sub set_legend_font_size {
385   $_[0]->{'custom_style'}->{'legend'}->{'size'} = $_[1];
386 }
387
388 =item set_legend_patch_size
389
390 =cut
391
392 sub set_legend_patch_size {
393   $_[0]->{'custom_style'}->{'legend'}->{'patchsize'} = $_[1];
394 }
395
396 =item set_legend_patch_gap
397
398 =cut
399
400 sub set_legend_patch_gap {
401   $_[0]->{'custom_style'}->{'legend'}->{'patchgap'} = $_[1];
402 }
403
404 =item set_legend_horizontal_align
405
406 =cut
407
408 sub set_legend_horizontal_align {
409   $_[0]->{'custom_style'}->{'legend'}->{'halign'} = $_[1];
410 }
411
412 =item set_legend_vertical_align
413
414 =cut
415
416 sub set_legend_vertical_align {
417   $_[0]->{'custom_style'}->{'legend'}->{'valign'} = $_[1];
418 }
419
420 =item set_legend_padding
421
422 =cut
423
424 sub set_legend_padding {
425   $_[0]->{'custom_style'}->{'legend'}->{'padding'} = $_[1];
426 }
427
428 =item set_legend_outside_padding
429
430 =cut
431
432 sub set_legend_outside_padding {
433   $_[0]->{'custom_style'}->{'legend'}->{'outsidepadding'} = $_[1];
434 }
435
436 =item set_legend_fill
437
438 =cut
439
440 sub set_legend_fill {
441   $_[0]->{'custom_style'}->{'legend'}->{'fill'} = $_[1];
442 }
443
444 =item set_legend_border
445
446 =cut
447
448 sub set_legend_border {
449   $_[0]->{'custom_style'}->{'legend'}->{'border'} = $_[1];
450 }
451
452 =item set_legend_orientation
453
454 =cut
455
456 sub set_legend_orientation {
457   $_[0]->{'custom_style'}->{'legend'}->{'orientation'} = $_[1];
458 }
459
460 =item set_callout_font_color
461
462 =cut
463
464 sub set_callout_font_color {
465   $_[0]->{'custom_style'}->{'callout'}->{'color'} = $_[1];
466 }
467
468 =item set_callout_font
469
470 =cut
471
472 sub set_callout_font {
473   $_[0]->{'custom_style'}->{'callout'}->{'font'} = $_[1];
474 }
475
476 =item set_callout_font_size
477
478 =cut
479
480 sub set_callout_font_size {
481   $_[0]->{'custom_style'}->{'callout'}->{'size'} = $_[1];
482 }
483
484 =item set_callout_line_color
485
486 =cut
487
488 sub set_callout_line_color {
489   $_[0]->{'custom_style'}->{'callout'}->{'line'} = $_[1];
490 }
491
492 =item set_callout_leader_inside_length
493
494 =cut
495
496 sub set_callout_leader_inside_length {
497   $_[0]->{'custom_style'}->{'callout'}->{'inside'} = $_[1];
498 }
499
500 =item set_callout_leader_outside_length
501
502 =cut
503
504 sub set_callout_leader_outside_length {
505   $_[0]->{'custom_style'}->{'callout'}->{'outside'} = $_[1];
506 }
507
508 =item set_callout_leader_length
509
510 =cut
511
512 sub set_callout_leader_length {
513   $_[0]->{'custom_style'}->{'callout'}->{'leadlen'} = $_[1];
514 }
515
516 =item set_callout_gap
517
518 =cut
519
520 sub set_callout_gap {
521   $_[0]->{'custom_style'}->{'callout'}->{'gap'} = $_[1];
522 }
523
524 =item set_label_font_color
525
526 =cut
527
528 sub set_label_font_color {
529   $_[0]->{'custom_style'}->{'label'}->{'color'} = $_[1];
530 }
531
532 =item set_label_font
533
534 =cut
535
536 sub set_label_font {
537   $_[0]->{'custom_style'}->{'label'}->{'font'} = $_[1];
538 }
539
540 =item set_label_font_size
541
542 =cut
543
544 sub set_label_font_size {
545   $_[0]->{'custom_style'}->{'label'}->{'size'} = $_[1];
546 }
547
548 =item set_drop_shadow_fill_color
549
550 =cut
551
552 sub set_drop_shadow_fill_color {
553   $_[0]->{'custom_style'}->{'dropshadow'}->{'fill'} = $_[1];
554 }
555
556 =item set_drop_shadow_offset
557
558 =cut
559
560 sub set_drop_shadow_offset {
561   $_[0]->{'custom_style'}->{'dropshadow'}->{'off'} = $_[1];
562 }
563
564 =item set_drop_shadowXOffset
565
566 =cut
567
568 sub set_drop_shadowXOffset {
569   $_[0]->{'custom_style'}->{'dropshadow'}->{'offx'} = $_[1];
570 }
571
572 =item set_drop_shadowYOffset
573
574 =cut
575
576 sub set_drop_shadowYOffset {
577   $_[0]->{'custom_style'}->{'dropshadow'}->{'offy'} = $_[1];
578 }
579
580 =item set_drop_shadow_filter
581
582 =cut
583
584 sub set_drop_shadow_filter {
585   $_[0]->{'custom_style'}->{'dropshadow'}->{'filter'} = $_[1];
586 }
587
588 =item set_outline_color
589
590 =cut
591
592 sub set_outline_color {
593   $_[0]->{'custom_style'}->{'outline'}->{'line'} = $_[1];
594 }
595
596 =item set_data_area_fills
597
598 =cut
599
600 sub set_data_area_fills {
601   $_[0]->{'custom_style'}->{'fills'} = $_[1];
602 }
603
604 =item set_data_line_colors
605
606 =cut
607
608 sub set_data_line_colors {
609   $_[0]->{'custom_style'}->{'colors'} = $_[1];
610 }
611
612 =back
613
614 =head1 FEATURES
615
616 Each graph type has a number of features.  These are used to add
617 various items that are displayed in the graph area.  Some common
618 methods are:
619
620 =over
621
622 =item show_legend()
623
624 adds a box containing boxes filled with the data filess, with
625 the labels provided to the draw method.  The legend will only be
626 displayed if both the legend feature is enabled and labels are
627 supplied.
628
629 =cut
630
631 sub show_legend {
632     $_[0]->{'custom_style'}->{'features'}->{'legend'} = 1;
633 }
634
635 =item show_outline()
636
637 draws a border around the data areas.
638
639 =cut
640
641 sub show_outline {
642     $_[0]->{'custom_style'}->{'features'}->{'outline'} = 1;
643 }
644
645 =item show_labels()
646
647 labels each data fill, usually by including text inside the data fill.
648 If the text does not fit in the fill, they could be displayed in some
649 other form, eg. as callouts in a pie graph.  There usually isn't much
650 point in including both labels and a legend.
651
652 =cut
653
654 sub show_labels {
655     $_[0]->{'custom_style'}->{'features'}->{'labels'} = 1;
656 }
657
658 =item show_drop_shadow()
659
660 a simple drop shadow is shown behind some of the graph elements.
661
662 =cut
663
664 sub show_drop_shadow {
665     $_[0]->{'custom_style'}->{'features'}->{'dropshadow'} = 1;
666 }
667
668 =item reset_features()
669
670 Unsets all of the features
671
672 =cut
673
674 sub reset_features {
675     $_[0]->{'custom_style'}->{'features'} = {};
676     $_[0]->{'custom_style'}->{'features'}->{'reset'} = 1;
677 }
678
679 =back
680
681 Additionally, features can be set by passing them into the draw() method:
682
683 =over
684
685 =item legend
686
687 adds a box containing boxes filled with the data filess, with
688 the labels provided to the draw method.  The legend will only be
689 displayed if both the legend feature is enabled and labels are
690 supplied.
691
692 =item labels
693
694 labels each data fill, usually by including text inside the data fill.
695 If the text does not fit in the fill, they could be displayed in some
696 other form, eg. as callouts in a pie graph.  There usually isn't much
697 point in including both labels and a legend.
698
699 =item dropshadow
700
701 a simple drop shadow is shown behind some of the graph elements.
702
703 =back
704
705 Each graph also has features specific to that graph.
706
707 =head1 COMMON PARAMETERS
708
709 When referring to a single sub-value this documentation will refer to
710 'title.color' rather than 'the color element of title'.
711
712 Normally, except for the font parameter, these are controlled by
713 styles, but these are the style parameters I'd mostly likely expect
714 you want to use:
715
716 =over
717
718 =item font
719
720 the Imager font object used to draw text on the chart.
721
722 =item back
723
724 the background fill for the graph.  Default depends on the style.
725
726 =item size
727
728 the base size of the graph image.  Default: 256
729
730 =item width
731
732 the width of the graph image.  Default: 1.5 * size (384)
733
734 =item height
735
736 the height of the graph image.  Default: size (256)
737
738 =item channels
739
740 the number of channels in the image.  Default: 3 (the 'mono' style
741 sets this to 1).
742
743 =item line
744
745 the color used for drawing lines, such as outlines or callouts.
746 Default depends on the current style.  Set to undef to remove the
747 outline from a style.
748
749 =item title
750
751 the text used for a graph title.  Default: no title.  Note: this is
752 the same as the title=>{ text => ... } field.
753
754 =over
755
756 =item halign
757
758 horizontal alignment of the title in the graph, one of 'left',
759 'center' or 'right'. Default: center
760
761 =item valign
762
763 vertical alignment of the title, one of 'top', 'center' or 'right'.
764 Default: top.  It's probably a bad idea to set this to 'center' unless
765 you have a very short title.
766
767 =back
768
769 =item text
770
771 This contains basic defaults used in drawing text.
772
773 =over
774
775 =item color
776
777 the default color used for all text, defaults to the fg color.
778
779 =item size
780
781 the base size used for text, also used to scale many graph elements.
782 Default: 14.
783
784 =back
785
786 =back
787
788 =head1 BEYOND STYLES
789
790 In most cases you will want to use just the styles, but you may want
791 to exert more control over the way your chart looks.  This section
792 describes the options you can use to control the way your chart looks.
793
794 Hopefully you don't need to read this.
795
796 =over
797
798 =item back
799
800 The background of the graph.
801
802 =item bg
803
804 =item fg
805
806 Used to define basic background and foreground colors for the graph.
807 The bg color may be used for the background of the graph, and is used
808 as a default for the background of hatcheed fills.  The fg is used as
809 the default for line and text colors.
810
811 =item font
812
813 The default font used by the graph.  Normally you should supply this
814 if your graph as any text.
815
816 =item line
817
818 The default line color.
819
820 =item text
821
822 defaults for drawing text.  Other textual graph elements will inherit
823 or modify these values.
824
825 =over
826
827 =item color
828
829 default text color, defaults to the I<fg> color.
830
831 =item size
832
833 default text size. Default: 14.  This is used to scale many graph
834 elements, including padding and leader sizes.  Other text elements
835 will either use or scale this value.
836
837 =item font
838
839 default font object.  Inherited from I<font>, which should have been
840 supplied by the caller.
841
842 =back
843
844 =item title
845
846 If you supply a scalar value for this element, it will be stored in
847 the I<text> field.
848
849 Defines the text, font and layout information for the title.
850
851 =over
852
853 =item color
854
855 The color of the title, inherited from I<text.color>.
856
857 =item font
858
859 The font object used for the title, inherited from I<text.font>.
860
861 =item size
862
863 size of the title text. Default: double I<text.size>
864
865 =item halign
866
867 =item valign
868
869 The horizontal and vertical alignment of the title.
870
871 =back
872
873 =item legend
874
875 defines attributes of the graph legend, if present.
876
877 =over
878
879 =item color
880
881 =item font
882
883 =item size
884
885 text attributes for the labels used in the legend.
886
887 =item patchsize
888
889 the width and height of the color patch in the legend.  Defaults to
890 90% of the legend text size.
891
892 =item patchgap
893
894 the minimum gap between patches in pixels.  Defaults to 30% of the
895 patchsize.
896
897 =item patchborder
898
899 the color of the border drawn around each patch.  Inherited from I<line>.
900
901 =item halign
902
903 =item valign
904
905 the horizontal and vertical alignment of the legend within the graph.
906 Defaults to 'right' and 'top'.
907
908 =item padding
909
910 the gap between the legend patches and text and the outside of it's
911 box, or to the legend border, if any.
912
913 =item outsidepadding
914
915 the gap between the border and the outside of the legend's box.  This
916 is only used if the I<legend.border> attribute is defined.
917
918 =item fill
919
920 the background fill for the legend.  Default: none
921
922 =item border
923
924 the border color of the legend.  Default: none (no border is drawn
925 around the legend.)
926
927 =item orientation
928
929 The orientation of the legend.  If this is C<vertical> the the patches
930 and labels are stacked on top of each other.  If this is C<horizontal>
931 the patchs and labels are word wrapped across the image.  Default:
932 vertical.
933
934 =back
935
936 For example to create a horizontal legend with borderless patches,
937 darker than the background, you might do:
938
939   my $im = $chart->draw
940     (...,
941     legend =>
942     {
943       patchborder => undef,
944       orientation => 'horizontal',
945       fill => { solid => Imager::Color->new(0, 0, 0, 32), }
946     },
947     ...);
948
949 =item callout
950
951 defines attributes for graph callouts, if any are present.  eg. if the
952 pie graph cannot fit the label into the pie graph segement it will
953 present it as a callout.
954
955 =over
956
957 =item color
958
959 =item font
960
961 =item size
962
963 the text attributes of the callout label.  Inherited from I<text>.
964
965 =item line
966
967 the color of the callout lines.  Inherited from I<line>
968
969 =item inside
970
971 =item outside
972
973 the length of the leader on the inside and the outside of the fill,
974 usually at some angle.  Both default to the size of the callout text.
975
976 =item leadlen
977
978 the length of the horizontal portion of the leader.  Default:
979 I<callout.size>.
980
981 =item gap
982
983 the gap between the callout leader and the callout text.  Defaults to
984 30% of the text callout size.
985
986 =back
987
988 =item label
989
990 defines attributes for labels drawn into the data areas of a graph.
991
992 =over
993
994 =item color
995
996 =item font
997
998 =item size
999
1000 The text attributes of the labels.  Inherited from I<text>.
1001
1002 =back
1003
1004 =item dropshadow
1005
1006 the attributes of the graph's drop shadow
1007
1008 =over
1009
1010 =item fill
1011
1012 the fill used for the drop shadow.  Default: '404040' (dark gray)
1013
1014 =item off
1015
1016 the offset of the drop shadow.  A convenience value inherited by offx
1017 and offy.  Default: 40% of I<text.size>.
1018
1019 =item offx
1020
1021 =item offy
1022
1023 the horizontal and vertical offsets of the drop shadow.  Both
1024 inherited from I<dropshadow.off>.
1025
1026 =item filter
1027
1028 the filter description passed to Imager's filter method to blur the
1029 drop shadow.  Default: an 11 element convolution filter.
1030
1031 =back
1032
1033 =item outline
1034
1035 describes the lines drawn around filled data areas, such as the
1036 segments of a pie chart.
1037
1038 =over
1039
1040 =item line
1041
1042 the line color of the outlines, inherited from I<line>.
1043
1044 =back
1045
1046 =item fills
1047
1048 a reference to an array containing fills for each data item.
1049
1050 You can mix fill types, ie. using a simple color for the first item, a
1051 hatched fill for the second and a fountain fill for the next.
1052
1053 =back
1054
1055 =head1 HOW VALUES WORK
1056
1057 Internally rather than specifying literal color, fill, or font objects
1058 or literal sizes for each element, Imager::Graph uses a number of
1059 special values to inherit or modify values taken from other graph
1060 element names.
1061
1062 =head2 Specifying colors
1063
1064 You can specify colors by either supplying an Imager::Color object, by
1065 supplying lookup of another color, or by supplying a single value that
1066 Imager::Color::new can use as an initializer.  The most obvious is
1067 just a 6 or 8 digit hex value representing the red, green, blue and
1068 optionally alpha channels of the image.
1069
1070 You can lookup another color by using the lookup() "function", for
1071 example if you give a color as "lookup(fg)" then Imager::Graph will
1072 look for the fg element in the current style (or as overridden by
1073 you.)  This is used internally by Imager::Graph to set up the
1074 relationships between the colors of various elements, for example the
1075 default style information contains:
1076
1077    text=>{
1078           color=>'lookup(fg)',
1079           ...
1080          },
1081    legend =>{
1082              color=>'lookup(text.color)',
1083              ...
1084             },
1085
1086 So by setting the I<fg> color, you also set the default text color,
1087 since each text element uses lookup(text.color) as its value.
1088
1089 =head2 Specifying fills
1090
1091 Fills can be used for the graph background color, the background color
1092 for the legend block and for the fills used for each data element.
1093
1094 You can specify a fill as a L<color value|Specifying colors> or as a
1095 general fill, see L<Imager::Fill> for details.
1096
1097 You don't need (or usually want) to call Imager::Fill::new yourself,
1098 since the various fill functions will call it for you, and
1099 Imager::Graph provides some hooks to make them more useful.
1100
1101 =over
1102
1103 =item *
1104
1105 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
1106 Imager::Graph will supply the current graph fg and bg colors.
1107
1108 =item *
1109
1110 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
1111 and yb_ratio parameters, and they will be scaled in the fill area to
1112 define the fountain fills xa, ya, xb and yb parameters.
1113
1114 =back
1115
1116 As with colors, you can use lookup(name) or lookup(name1.name2) to
1117 have one element to inherit the fill of another.
1118
1119 Imager::Graph defaults the fill combine value to C<'normal'>.  This
1120 doesn't apply to simple color fills.
1121
1122 =head2 Specifying numbers
1123
1124 You can specify various numbers, usually representing the size of
1125 something, commonly text, but sometimes the length of a line or the
1126 size of a gap.
1127
1128 You can use the same lookup mechanism as with colors and fills, but
1129 you can also scale values.  For example, 'scale(0.5,text.size)' will
1130 return half the size of the normal text size.
1131
1132 As with colors, this is used internally to scale graph elements based
1133 on the base text size.  If you change the base text size then other
1134 graph elements will scale as well.
1135
1136 =head2 Specifying other elements
1137
1138 Other elements, such as fonts, or parameters for a filter, can also
1139 use the lookup(name) mechanism.
1140
1141 =head1 INTERNAL METHODS
1142
1143 Only useful if you need to fix bugs, add features or create a new
1144 graph class.
1145
1146 =over
1147
1148 =cut
1149
1150 my %style_defs =
1151   (
1152    back=> 'lookup(bg)',
1153    line=> 'lookup(fg)',
1154    aa => 1,
1155    text=>{
1156           color => 'lookup(fg)',
1157           font  => 'lookup(font)',
1158           size  => 14,
1159           aa    => 'lookup(aa)',
1160          },
1161    title=>{ 
1162            color  => 'lookup(text.color)', 
1163            font   => 'lookup(text.font)',
1164            halign => 'center', 
1165            valign => 'top',
1166            size   => 'scale(text.size,2.0)',
1167            aa     => 'lookup(text.aa)',
1168           },
1169    legend =>{
1170              color          => 'lookup(text.color)',
1171              font           => 'lookup(text.font)',
1172              aa             => 'lookup(text.aa)',
1173              size           => 'lookup(text.size)',
1174              patchsize      => 'scale(legend.size,0.9)',
1175              patchgap       => 'scale(legend.patchsize,0.3)',
1176              patchborder    => 'lookup(line)',
1177              halign         => 'right',
1178              valign         => 'top',
1179              padding        => 'scale(legend.size,0.3)',
1180              outsidepadding => 'scale(legend.padding,0.4)',
1181             },
1182    callout => {
1183                color    => 'lookup(text.color)',
1184                font     => 'lookup(text.font)',
1185                size     => 'lookup(text.size)',
1186                line     => 'lookup(line)',
1187                inside   => 'lookup(callout.size)',
1188                outside  => 'lookup(callout.size)',
1189                leadlen  => 'scale(0.8,callout.size)',
1190                gap      => 'scale(callout.size,0.3)',
1191                aa       => 'lookup(text.aa)',
1192                lineaa   => 'lookup(lineaa)',
1193               },
1194    label => {
1195              font          => 'lookup(text.font)',
1196              size          => 'lookup(text.size)',
1197              color         => 'lookup(text.color)',
1198              hpad          => 'lookup(label.pad)',
1199              vpad          => 'lookup(label.pad)',
1200              pad           => 'scale(label.size,0.2)',
1201              pcformat      => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
1202              pconlyformat  => sub { sprintf "%.1f%%", $_[0] },
1203              aa            => 'lookup(text.aa)',
1204              lineaa        => 'lookup(lineaa)',
1205              },
1206    dropshadow => {
1207                   fill    => { solid => Imager::Color->new(0, 0, 0, 96) },
1208                   off     => 'scale(0.4,text.size)',
1209                   offx    => 'lookup(dropshadow.off)',
1210                   offy    => 'lookup(dropshadow.off)',
1211                   filter  => { type=>'conv', 
1212                               # this needs a fairly heavy blur
1213                               coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2, 
1214                                      0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
1215                  },
1216    outline => {
1217                line =>'lookup(line)',
1218                lineaa => 'lookup(lineaa)',
1219               },
1220    size=>256,
1221    width=>'scale(1.5,size)',
1222    height=>'lookup(size)',
1223
1224    # yes, the handling of fill and line AA is inconsistent, lack of
1225    # forethought, unfortunately
1226    fill => {
1227             aa => 'lookup(aa)',
1228            },
1229    lineaa => 'lookup(aa)',
1230   );
1231
1232 =item _error($message)
1233
1234 Sets the error field of the object and returns an empty list or undef,
1235 depending on context.  Should be used for error handling, since it may
1236 provide some user hooks at some point.
1237
1238 The intended usage is:
1239
1240   some action
1241     or return $self->_error("error description");
1242
1243 You should almost always return the result of _error() or return
1244 immediately afterwards.
1245
1246 =cut
1247
1248 sub _error {
1249   my ($self, $error) = @_;
1250
1251   $self->{_errstr} = $error;
1252
1253   return;
1254 }
1255
1256
1257 =item _style_defs()
1258
1259 Returns the style defaults, such as the relationships between line
1260 color and text color.
1261
1262 Intended to be over-ridden by base classes to provide graph specific
1263 defaults.
1264
1265 =cut
1266
1267 sub _style_defs {
1268   \%style_defs;
1269 }
1270
1271 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
1272 my $def_style = 'fount_lin';
1273
1274 my %styles =
1275   (
1276    primary =>
1277    {
1278     fills=>
1279     [
1280      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1281     ],
1282     fg=>'000000',
1283     negative_bg=>'EEEEEE',
1284     bg=>'E0E0E0',
1285     legend=>
1286     {
1287      #patchborder=>'000000'
1288     },
1289    },
1290    primary_red =>
1291    {
1292     fills=>
1293     [
1294      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1295     ],
1296     fg=>'000000',
1297     negative_bg=>'EEEEEE',
1298     bg=>'C08080',
1299     legend=>
1300     {
1301      patchborder=>'000000'
1302     },
1303    },
1304    mono =>
1305    {
1306     fills=>
1307     [
1308      { hatch=>'slash2' },
1309      { hatch=>'slosh2' },
1310      { hatch=>'vline2' },
1311      { hatch=>'hline2' },
1312      { hatch=>'cross2' },
1313      { hatch=>'grid2' },
1314      { hatch=>'stipple3' },
1315      { hatch=>'stipple2' },
1316     ],
1317     channels=>1,
1318     bg=>'FFFFFF',
1319     fg=>'000000',
1320     negative_bg=>'EEEEEE',
1321     features=>{ outline=>1 },
1322     pie =>{
1323            blur=>undef,
1324           },
1325     aa => 0,
1326    },
1327    fount_lin =>
1328    {
1329     fills=>
1330     [
1331      { fountain=>'linear',
1332        xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
1333        segments => Imager::Fountain->simple(positions=>[0, 1],
1334                                             colors=>[ NC('FFC0C0'), NC('FF0000') ]),
1335      },
1336      { fountain=>'linear',
1337        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1338        segments => Imager::Fountain->simple(positions=>[0, 1],
1339                                             colors=>[ NC('C0FFC0'), NC('00FF00') ]),
1340      },
1341      { fountain=>'linear',
1342        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1343        segments => Imager::Fountain->simple(positions=>[0, 1],
1344                                             colors=>[ NC('C0C0FF'), NC('0000FF') ]),
1345      },
1346      { fountain=>'linear',
1347        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1348        segments => Imager::Fountain->simple(positions=>[0, 1],
1349                                             colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
1350      },
1351      { fountain=>'linear',
1352        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1353        segments => Imager::Fountain->simple(positions=>[0, 1],
1354                                             colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
1355      },
1356      { fountain=>'linear',
1357        xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1358        segments => Imager::Fountain->simple(positions=>[0, 1],
1359                                             colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
1360      },
1361     ],
1362     colors  => [
1363      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1364     ],
1365     line_markers =>[
1366       { shape => 'circle',   radius => 4 },
1367       { shape => 'square',   radius => 4 },
1368       { shape => 'diamond',  radius => 4 },
1369       { shape => 'triangle', radius => 4 },
1370       { shape => 'x',        radius => 4 },
1371       { shape => 'plus',     radius => 4 },
1372     ],
1373     back=>{ fountain=>'linear',
1374             xa_ratio=>0, ya_ratio=>0,
1375             xb_ratio=>1.0, yb_ratio=>1.0,
1376             segments=>Imager::Fountain->simple
1377             ( positions=>[0, 1],
1378               colors=>[ NC('6060FF'), NC('60FF60') ]) },
1379     fg=>'000000',
1380     negative_bg=>'EEEEEE',
1381     bg=>'FFFFFF',
1382     features=>{ dropshadow=>1 },
1383    },
1384    fount_rad =>
1385    {
1386     fills=>
1387     [
1388      { fountain=>'radial',
1389        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1390        segments => Imager::Fountain->simple(positions=>[0, 1],
1391                                             colors=>[ NC('FF8080'), NC('FF0000') ]),
1392      },
1393      { fountain=>'radial',
1394        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1395        segments => Imager::Fountain->simple(positions=>[0, 1],
1396                                             colors=>[ NC('80FF80'), NC('00FF00') ]),
1397      },
1398      { fountain=>'radial',
1399        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1400        segments => Imager::Fountain->simple(positions=>[0, 1],
1401                                             colors=>[ NC('808080FF'), NC('0000FF') ]),
1402      },
1403      { fountain=>'radial',
1404        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1405        segments => Imager::Fountain->simple(positions=>[0, 1],
1406                                             colors=>[ NC('FFFF80'), NC('FFFF00') ]),
1407      },
1408      { fountain=>'radial',
1409        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1410        segments => Imager::Fountain->simple(positions=>[0, 1],
1411                                             colors=>[ NC('80FFFF'), NC('00FFFF') ]),
1412      },
1413      { fountain=>'radial',
1414        xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1415        segments => Imager::Fountain->simple(positions=>[0, 1],
1416                                             colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1417      },
1418     ],
1419     colors  => [
1420      qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1421     ],
1422     back=>{ fountain=>'linear',
1423             xa_ratio=>0, ya_ratio=>0,
1424             xb_ratio=>1.0, yb_ratio=>1.0,
1425             segments=>Imager::Fountain->simple
1426             ( positions=>[0, 1],
1427               colors=>[ NC('6060FF'), NC('60FF60') ]) },
1428     fg=>'000000',
1429     negative_bg=>'EEEEEE',
1430     bg=>'FFFFFF',
1431    }
1432   );
1433
1434 $styles{'ocean'} = {
1435     fills  => [
1436              {
1437               fountain =>'linear',
1438               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1439               segments => Imager::Fountain->simple(
1440                                                     positions=>[0, 1],
1441                                                     colors=>[ NC('EFEDCF'), NC('E6E2AF') ]),
1442             },
1443              {
1444               fountain =>'linear',
1445               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1446               segments => Imager::Fountain->simple(
1447                                                     positions=>[0, 1],
1448                                                     colors=>[ NC('DCD7AB'), NC('A7A37E') ]),
1449             },
1450              {
1451               fountain =>'linear',
1452               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1453               segments => Imager::Fountain->simple(
1454                                                     positions=>[0, 1],
1455                                                     colors=>[ NC('B2E5D4'), NC('80B4A2') ]),
1456             },
1457             {
1458               fountain =>'linear',
1459               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1460               segments => Imager::Fountain->simple(
1461                                                     positions=>[0, 1],
1462                                                     colors=>[ NC('7aaab9'), NC('046380') ]),
1463             },
1464             {
1465               fountain =>'linear',
1466               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1467               segments => Imager::Fountain->simple(
1468                                                     positions=>[0, 1],
1469                                                     colors=>[ NC('c3b8e9'), NC('877EA7') ]),
1470             },
1471             {
1472               fountain =>'linear',
1473               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1474               segments => Imager::Fountain->simple(
1475                                                     positions=>[0, 1],
1476                                                     colors=>[ NC('A3DF9A'), NC('67A35E') ]),
1477             },
1478             {
1479               fountain =>'linear',
1480               xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1481               segments => Imager::Fountain->simple(
1482                                                     positions=>[0, 1],
1483                                                     colors=>[ NC('E19C98'), NC('B4726F') ]),
1484             },
1485     ],
1486     colors  => [
1487      qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1488     ],
1489     fg=>'000000',
1490     negative_bg=>'EEEEEE',
1491     bg=>'FFFFFF',
1492     features=>{ dropshadow=>1 },
1493
1494 };
1495
1496 $styles{'ocean_flat'} = {
1497     fills=>
1498     [
1499      qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1500     ],
1501     colors  => [
1502      qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1503     ],
1504     fg=>'000000',
1505     negative_bg=>'EEEEEE',
1506     bg=>'FFFFFF',
1507     features=>{ dropshadow=>1 },
1508
1509 };
1510
1511
1512 =item $self->_style_setup(\%opts)
1513
1514 Uses the values from %opts to build a customized hash describing the
1515 way the graph should be drawn.
1516
1517 =cut
1518
1519 sub _style_setup {
1520   my ($self, $opts) = @_;
1521   my $style_defs = $self->_style_defs;
1522   my $style;
1523
1524   my $pre_def_style = $self->_get_style($opts);
1525   my $api_style = $self->{'custom_style'} || {};
1526   $style = $styles{$pre_def_style} if $pre_def_style;
1527
1528   $style ||= $styles{$def_style};
1529
1530   my @search_list = ( $style_defs, $style, $api_style, $opts);
1531   my %work;
1532
1533   my @composite = $self->_composite();
1534   my %composite;
1535   @composite{@composite} = @composite;
1536
1537   for my $src (@search_list) {
1538     for my $key (keys %$src) {
1539       if ($composite{$key}) {
1540         $work{$key} = {} unless exists $work{$key};
1541         if (ref $src->{$key}) {
1542           # some keys have sub values, especially text
1543           @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1544         }
1545         else {
1546           # assume it's the text for a title or something
1547           $work{$key}{text} = $src->{$key};
1548         }
1549       }
1550       else {
1551         $work{$key} = $src->{$key}
1552           if defined $src->{$key}; # $opts with pmichauds new accessor handling
1553       }
1554     }
1555   }
1556
1557   # features are handled specially
1558   $work{features} = {};
1559   for my $src (@search_list) {
1560     if ($src->{features}) {
1561       if (ref $src->{features}) {
1562         if (ref($src->{features}) =~ /ARRAY/) {
1563           # just set those features
1564           for my $feature (@{$src->{features}}) {
1565             $work{features}{$feature} = 1;
1566           }
1567         }
1568         elsif (ref($src->{features}) =~ /HASH/) {
1569           if ($src->{features}{reset}) {
1570             $work{features} = {}; # only the ones the user specifies
1571           }
1572           @{$work{features}}{keys %{$src->{features}}} =
1573             values(%{$src->{features}});
1574         }
1575       }
1576       else {
1577         # just set that single feature
1578         $work{features}{$src->{features}} = 1;
1579       }
1580     }
1581   }
1582   #use Data::Dumper;
1583   #print Dumper(\%work);
1584
1585   $self->{_style} = \%work;
1586 }
1587
1588 =item $self->_get_thing($name)
1589
1590 Retrieve some general 'thing'.
1591
1592 Supports the 'lookup(foo)' mechanism.
1593
1594 Returns an empty list on failure.
1595
1596 =cut
1597
1598 sub _get_thing {
1599   my ($self, $name, @depth) = @_;
1600
1601   push(@depth, $name);
1602   my $what;
1603   if ($name =~ /^(\w+)\.(\w+)$/) {
1604     $what = $self->{_style}{$1}{$2};
1605   }
1606   else {
1607     $what = $self->{_style}{$name};
1608   }
1609   defined $what or
1610     return;
1611   if (ref $what) {
1612     return $what;
1613   }
1614   elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1615     @depth < MAX_DEPTH
1616       or return $self->_error("too many levels of recursion in lookup(@depth)");
1617     return $self->_get_thing($1, @depth);
1618   }
1619   else {
1620     return $what;
1621   }
1622 }
1623
1624 =item $self->_get_number($name)
1625
1626 Retrieves a number from the style.  The value in the style can be the
1627 number, or one of two functions:
1628
1629 =over
1630
1631 =item lookup(newname)
1632
1633 Recursively looks up I<newname> in the style.
1634
1635 =item scale(value1,value2)
1636
1637 Each value can be a number or a name.  Names are recursively looked up
1638 in the style and the product is returned.
1639
1640 =back
1641
1642 =cut
1643
1644 sub _get_number {
1645   my ($self, $name, @depth) = @_;
1646
1647   push(@depth, $name);
1648   my $what;
1649   if ($name =~ /^(\w+)\.(\w+)$/) {
1650     $what = $self->{_style}{$1}{$2};
1651   }
1652   else {
1653     $what = $self->{_style}{$name};
1654   }
1655   defined $what or
1656     return $self->_error("$name is undef (@depth)");
1657
1658   if (ref $what) {
1659     if ($what =~ /CODE/) {
1660       $what = $what->($self, $name);
1661     }
1662   }
1663   else {
1664     if ($what =~ /^lookup\(([\w.]+)\)$/) {
1665       @depth < MAX_DEPTH
1666         or return $self->_error("too many levels of recursion in lookup (@depth)");
1667       return $self->_get_number($1, @depth);
1668     }
1669     elsif ($what =~ /^scale\(
1670                     ((?:[a-z][\w.]*)|$NUM_RE)
1671                     ,
1672                     ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1673       my ($left, $right) = ($1, $2);
1674       unless ($left =~ /^$NUM_RE$/) {
1675         @depth < MAX_DEPTH 
1676           or return $self->_error("too many levels of recursion in scale (@depth)");
1677         $left = $self->_get_number($left, @depth);
1678       }
1679       unless ($right =~ /^$NUM_RE$/) {
1680         @depth < MAX_DEPTH 
1681           or return $self->_error("too many levels of recursion in scale (@depth)");
1682         $right = $self->_get_number($right, @depth);
1683       }
1684       return $left * $right;
1685     }
1686     else {
1687       return $what+0;
1688     }
1689   }
1690 }
1691
1692 =item $self->_get_integer($name)
1693
1694 Retrieves an integer from the style.  This is a simple wrapper around
1695 _get_number() that rounds the result to an integer.
1696
1697 Returns an empty list on failure.
1698
1699 =cut
1700
1701 sub _get_integer {
1702   my ($self, $name, @depth) = @_;
1703
1704   my $number = $self->_get_number($name, @depth)
1705     or return;
1706
1707   return sprintf("%.0f", $number);
1708 }
1709
1710 =item _get_color($name)
1711
1712 Returns a color object of the given name from the style hash.
1713
1714 Uses Imager::Color->new to translate normal scalars into color objects.
1715
1716 Allows the lookup(name) mechanism.
1717
1718 Returns an empty list on failure.
1719
1720 =cut
1721
1722 sub _get_color {
1723   my ($self, $name, @depth) = @_;
1724
1725   push(@depth, $name);
1726   my $what;
1727   if ($name =~ /^(\w+)\.(\w+)$/) {
1728     $what = $self->{_style}{$1}{$2};
1729   }
1730   else {
1731     $what = $self->{_style}{$name};
1732   }
1733
1734   defined($what)
1735     or return $self->_error("$name was undefined (@depth)");
1736
1737   unless (ref $what) {
1738     if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1739       @depth < MAX_DEPTH or
1740         return $self->_error("too many levels of recursion in lookup (@depth)");
1741
1742       return $self->_get_color($1, @depth);
1743     }
1744     $what = Imager::Color->new($what);
1745   }
1746
1747   $what;
1748 }
1749
1750 =item _translate_fill($what, $box)
1751
1752 Given the value of a fill, either attempts to convert it into a fill
1753 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1754 parameters }>>), or to lookup another fill that is referred to with
1755 the 'lookup(name)' mechanism.
1756
1757 This function does the fg and bg initialization for hatched fills, and
1758 translation of *_ratio for fountain fills (using the $box parameter).
1759
1760 Returns an empty list on failure.
1761
1762 =cut
1763
1764 sub _translate_fill {
1765   my ($self, $what, $box, @depth) = @_;
1766
1767   if (ref $what) {
1768     if (UNIVERSAL::isa($what, "Imager::Color")) {
1769       return ( color=>Imager::Color->new($what), filled=>1 );
1770     }
1771     else {
1772       # a general fill
1773       # default to normal combine mode
1774       my %work = ( combine => 'normal', %$what );
1775       if ($what->{hatch}) {
1776         if (!$work{fg}) {
1777           $work{fg} = $self->_get_color('fg')
1778             or return;
1779         }
1780         if (!$work{bg}) {
1781           $work{bg} = $self->_get_color('bg')
1782             or return;
1783         }
1784         return ( fill=>\%work );
1785       }
1786       elsif ($what->{fountain}) {
1787         for my $key (qw(xa ya xb yb)) {
1788           if (exists $work{"${key}_ratio"}) {
1789             if ($key =~ /^x/) {
1790               $work{$key} = $box->[0] + $work{"${key}_ratio"} 
1791                 * ($box->[2] - $box->[0]);
1792             }
1793             else {
1794               $work{$key} = $box->[1] + $work{"${key}_ratio"} 
1795                 * ($box->[3] - $box->[1]);
1796             }
1797           }
1798         }
1799         return ( fill=>\%work );
1800       }
1801       else {
1802         return ( fill=> \%work );
1803       }
1804     }
1805   }
1806   else {
1807     if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1808       return $self->_get_fill($1, $box, @depth);
1809     }
1810     else {
1811       # assumed to be an Imager::Color single value
1812       return ( color=>Imager::Color->new($what), filled=>1 );
1813     }
1814   }
1815 }
1816
1817 =item _data_fill($index, $box)
1818
1819 Retrieves the fill parameters for a data area fill.
1820
1821 =cut
1822
1823 sub _data_fill {
1824   my ($self, $index, $box) = @_;
1825
1826   my $fills = $self->{_style}{fills};
1827   return $self->_translate_fill($fills->[$index % @$fills], $box,
1828                                 "data.$index");
1829 }
1830
1831 sub _data_color {
1832   my ($self, $index) = @_;
1833
1834   my $colors = $self->{'_style'}{'colors'} || [];
1835   my $fills  = $self->{'_style'}{'fills'} || [];
1836
1837   # Try to just use a fill, so non-fountain styles don't need
1838   # to have a duplicated set of fills and colors
1839   my $fill = $fills->[$index % @$fills];
1840   if (!ref $fill) {
1841     return $fill;
1842   }
1843
1844   if (@$colors) {
1845     return $colors->[$index % @$colors] || '000000';
1846   }
1847   return '000000';
1848 }
1849
1850 =item _get_fill($index, $box)
1851
1852 Retrieves fill parameters for a named fill.
1853
1854 =cut
1855
1856 sub _get_fill {
1857   my ($self, $name, $box, @depth) = @_;
1858
1859   push(@depth, $name);
1860   my $what;
1861   if ($name =~ /^(\w+)\.(\w+)$/) {
1862     $what = $self->{_style}{$1}{$2};
1863   }
1864   else {
1865     $what = $self->{_style}{$name};
1866   }
1867
1868   defined($what)
1869     or return $self->_error("no fill $name found");
1870
1871   return $self->_translate_fill($what, $box, @depth);
1872 }
1873
1874 =item _make_img()
1875
1876 Builds the image object for the graph and fills it with the background
1877 fill.
1878
1879 =cut
1880
1881 sub _make_img {
1882   my ($self) = @_;
1883
1884   my $width = $self->_get_number('width') || 256;
1885   my $height = $self->_get_number('height') || 256;
1886   my $channels = $self->{_style}{channels};
1887
1888   $channels ||= 3;
1889
1890   my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1891
1892   $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1893
1894   $img;
1895 }
1896
1897 sub _get_image {
1898   my $self = shift;
1899
1900   if (!$self->{'_image'}) {
1901     $self->{'_image'} = $self->_make_img();
1902   }
1903   return $self->{'_image'};
1904 }
1905
1906 =item _text_style($name)
1907
1908 Returns parameters suitable for calls to Imager::Font's bounding_box()
1909 and draw() methods intended for use in defining text styles.
1910
1911 Returns an empty list on failure.
1912
1913 Returns the following attributes: font, color, size, aa, sizew
1914 (optionally)
1915
1916 =cut
1917
1918 sub _text_style {
1919   my ($self, $name) = @_;
1920
1921   my %work;
1922
1923   if ($self->{_style}{$name}) {
1924     %work = %{$self->{_style}{$name}};
1925   }
1926   else {
1927     %work = %{$self->{_style}{text}};
1928   }
1929   $work{font}
1930     or return $self->_error("$name has no font parameter");
1931
1932   $work{font} = $self->_get_thing("$name.font")
1933     or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1934   UNIVERSAL::isa($work{font}, "Imager::Font")
1935       or return $self->_error("$name.font is not a font");
1936   if ($work{color} && !ref $work{color}) {
1937     $work{color} = $self->_get_color("$name.color")
1938       or return;
1939   }
1940   $work{size} = $self->_get_number("$name.size");
1941   $work{sizew} = $self->_get_number("$name.sizew")
1942     if $work{sizew};
1943   $work{aa} = $self->_get_number("$name.aa");
1944
1945   %work;
1946 }
1947
1948 =item _text_bbox($text, $name)
1949
1950 Returns a bounding box for the specified $text as styled by $name.
1951
1952 Returns an empty list on failure.
1953
1954 =cut
1955
1956 sub _text_bbox {
1957   my ($self, $text, $name) = @_;
1958
1959   my %text_info = $self->_text_style($name)
1960     or return;
1961
1962   my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1963                                             canon=>1);
1964
1965   return @bbox[0..3];
1966 }
1967
1968 =item _line_style($name)
1969
1970 Return parameters suitable for calls to Imager's line(), polyline(),
1971 and box() methods.
1972
1973 For now this returns only color and aa parameters, but future releases
1974 of Imager may support extra parameters.
1975
1976 =cut
1977
1978 sub _line_style {
1979   my ($self, $name) = @_;
1980
1981   my %line;
1982   $line{color} = $self->_get_color("$name.line")
1983     or return;
1984   $line{aa} = $self->_get_number("$name.lineaa");
1985   defined $line{aa} or $line{aa} = $self->_get_number("aa");
1986
1987   return %line;
1988 }
1989
1990 sub _align_box {
1991   my ($self, $box, $chart_box, $name) = @_;
1992
1993   my $halign = $self->{_style}{$name}{halign}
1994     or $self->_error("no halign for $name");
1995   my $valign = $self->{_style}{$name}{valign};
1996
1997   if ($halign eq 'right') {
1998     $box->[0] += $chart_box->[2] - $box->[2];
1999   }
2000   elsif ($halign eq 'left') {
2001     $box->[0] = $chart_box->[0];
2002   }
2003   elsif ($halign eq 'center' || $halign eq 'centre') {
2004     $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
2005   }
2006   else {
2007     return $self->_error("invalid halign $halign for $name");
2008   }
2009
2010   if ($valign eq 'top') {
2011     $box->[1] = $chart_box->[1];
2012   }
2013   elsif ($valign eq 'bottom') {
2014     $box->[1] = $chart_box->[3] - $box->[3];
2015   }
2016   elsif ($valign eq 'center' || $valign eq 'centre') {
2017     $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
2018   }
2019   else {
2020     return $self->_error("invalid valign $valign for $name");
2021   }
2022   $box->[2] += $box->[0];
2023   $box->[3] += $box->[1];
2024 }
2025
2026 sub _remove_box {
2027   my ($self, $chart_box, $object_box) = @_;
2028
2029   my $areax;
2030   my $areay;
2031   if ($object_box->[0] - $chart_box->[0] 
2032       < $chart_box->[2] - $object_box->[2]) {
2033     $areax = ($object_box->[2] - $chart_box->[0]) 
2034       * ($chart_box->[3] - $chart_box->[1]);
2035   }
2036   else {
2037     $areax = ($chart_box->[2] - $object_box->[0]) 
2038       * ($chart_box->[3] - $chart_box->[1]);
2039   }
2040
2041   if ($object_box->[1] - $chart_box->[1] 
2042       < $chart_box->[3] - $object_box->[3]) {
2043     $areay = ($object_box->[3] - $chart_box->[1]) 
2044       * ($chart_box->[2] - $chart_box->[0]);
2045   }
2046   else {
2047     $areay = ($chart_box->[3] - $object_box->[1]) 
2048       * ($chart_box->[2] - $chart_box->[0]);
2049   }
2050
2051   if ($areay < $areax) {
2052     if ($object_box->[1] - $chart_box->[1] 
2053         < $chart_box->[3] - $object_box->[3]) {
2054       $chart_box->[1] = $object_box->[3];
2055     }
2056     else {
2057       $chart_box->[3] = $object_box->[1];
2058     }
2059   }
2060   else {
2061     if ($object_box->[0] - $chart_box->[0] 
2062         < $chart_box->[2] - $object_box->[2]) {
2063       $chart_box->[0] = $object_box->[2];
2064     }
2065     else {
2066       $chart_box->[2] = $object_box->[0];
2067     }
2068   }
2069 }
2070
2071 sub _draw_legend {
2072   my ($self, $img, $labels, $chart_box) = @_;
2073
2074   my $orient = $self->_get_thing('legend.orientation');
2075   defined $orient or $orient = 'vertical';
2076
2077   if ($orient eq 'vertical') {
2078     return $self->_draw_legend_vertical($img, $labels, $chart_box);
2079   }
2080   elsif ($orient eq 'horizontal') {
2081     return $self->_draw_legend_horizontal($img, $labels, $chart_box);
2082   }
2083   else {
2084     return $self->_error("Unknown legend.orientation $orient");
2085   }
2086 }
2087
2088 sub _draw_legend_horizontal {
2089   my ($self, $img, $labels, $chart_box) = @_;
2090
2091   defined(my $padding = $self->_get_integer('legend.padding'))
2092     or return;
2093   my $patchsize = $self->_get_integer('legend.patchsize')
2094     or return;
2095   defined(my $gap = $self->_get_integer('legend.patchgap'))
2096     or return;
2097
2098   my $minrowsize = $patchsize + $gap;
2099   my ($width, $height) = (0,0);
2100   my $row_height = $minrowsize;
2101   my $pos = 0;
2102   my @sizes;
2103   my @offsets;
2104   for my $label (@$labels) {
2105     my @text_box = $self->_text_bbox($label, 'legend')
2106       or return;
2107     push(@sizes, \@text_box);
2108     my $entry_width = $patchsize + $gap + $text_box[2];
2109     if ($pos == 0) {
2110       # never re-wrap the first entry
2111       push @offsets, [ 0, $height ];
2112     }
2113     else {
2114       if ($pos + $gap + $entry_width > $chart_box->[2]) {
2115         $pos = 0;
2116         $height += $row_height;
2117       }
2118       push @offsets, [ $pos, $height ];
2119     }
2120     my $entry_right = $pos + $entry_width;
2121     $pos += $gap + $entry_width;
2122     $entry_right > $width and $width = $entry_right;
2123     if ($text_box[3] > $row_height) {
2124       $row_height = $text_box[3];
2125     }
2126   }
2127   $height += $row_height;
2128   my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
2129   my $outsidepadding = 0;
2130   if ($self->{_style}{legend}{border}) {
2131     defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2132       or return;
2133     $box[2] += 2 * $outsidepadding;
2134     $box[3] += 2 * $outsidepadding;
2135   }
2136   $self->_align_box(\@box, $chart_box, 'legend')
2137     or return;
2138   if ($self->{_style}{legend}{fill}) {
2139     $img->box(xmin=>$box[0]+$outsidepadding, 
2140               ymin=>$box[1]+$outsidepadding, 
2141               xmax=>$box[2]-$outsidepadding, 
2142               ymax=>$box[3]-$outsidepadding,
2143              $self->_get_fill('legend.fill', \@box));
2144   }
2145   $box[0] += $outsidepadding;
2146   $box[1] += $outsidepadding;
2147   $box[2] -= $outsidepadding;
2148   $box[3] -= $outsidepadding;
2149   my %text_info = $self->_text_style('legend')
2150     or return;
2151   my $patchborder;
2152   if ($self->{_style}{legend}{patchborder}) {
2153     $patchborder = $self->_get_color('legend.patchborder')
2154       or return;
2155   }
2156   
2157   my $dataindex = 0;
2158   for my $label (@$labels) {
2159     my ($left, $top) = @{$offsets[$dataindex]};
2160     $left += $box[0] + $padding;
2161     $top += $box[1] + $padding;
2162     my $textpos = $left + $patchsize + $gap;
2163     my @patchbox = ( $left, $top,
2164                      $left + $patchsize, $top + $patchsize );
2165     my @fill = $self->_data_fill($dataindex, \@patchbox)
2166       or return;
2167     $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2168                ymax=>$top + $patchsize, @fill);
2169     if ($self->{_style}{legend}{patchborder}) {
2170       $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2171                 ymax=>$top + $patchsize,
2172                 color=>$patchborder);
2173     }
2174     $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize, 
2175                  text=>$label);
2176
2177     ++$dataindex;
2178   }
2179   if ($self->{_style}{legend}{border}) {
2180     my $border_color = $self->_get_color('legend.border')
2181       or return;
2182     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2183               color=>$border_color);
2184   }
2185   $self->_remove_box($chart_box, \@box);
2186   1;
2187 }
2188
2189 sub _draw_legend_vertical {
2190   my ($self, $img, $labels, $chart_box) = @_;
2191
2192   defined(my $padding = $self->_get_integer('legend.padding'))
2193     or return;
2194   my $patchsize = $self->_get_integer('legend.patchsize')
2195     or return;
2196   defined(my $gap = $self->_get_integer('legend.patchgap'))
2197     or return;
2198   my $minrowsize = $patchsize + $gap;
2199   my ($width, $height) = (0,0);
2200   my @sizes;
2201   for my $label (@$labels) {
2202     my @box = $self->_text_bbox($label, 'legend')
2203       or return;
2204     push(@sizes, \@box);
2205     $width = $box[2] if $box[2] > $width;
2206     if ($minrowsize > $box[3]) {
2207       $height += $minrowsize;
2208     }
2209     else {
2210       $height += $box[3];
2211     }
2212   }
2213   my @box = (0, 0, 
2214              $width + $patchsize + $padding * 2 + $gap,
2215              $height + $padding * 2 - $gap);
2216   my $outsidepadding = 0;
2217   if ($self->{_style}{legend}{border}) {
2218     defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2219       or return;
2220     $box[2] += 2 * $outsidepadding;
2221     $box[3] += 2 * $outsidepadding;
2222   }
2223   $self->_align_box(\@box, $chart_box, 'legend')
2224     or return;
2225   if ($self->{_style}{legend}{fill}) {
2226     $img->box(xmin=>$box[0]+$outsidepadding, 
2227               ymin=>$box[1]+$outsidepadding, 
2228               xmax=>$box[2]-$outsidepadding, 
2229               ymax=>$box[3]-$outsidepadding,
2230              $self->_get_fill('legend.fill', \@box));
2231   }
2232   $box[0] += $outsidepadding;
2233   $box[1] += $outsidepadding;
2234   $box[2] -= $outsidepadding;
2235   $box[3] -= $outsidepadding;
2236   my $ypos = $box[1] + $padding;
2237   my $patchpos = $box[0]+$padding;
2238   my $textpos = $patchpos + $patchsize + $gap;
2239   my %text_info = $self->_text_style('legend')
2240     or return;
2241   my $patchborder;
2242   if ($self->{_style}{legend}{patchborder}) {
2243     $patchborder = $self->_get_color('legend.patchborder')
2244       or return;
2245   }
2246   my $dataindex = 0;
2247   for my $label (@$labels) {
2248     my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
2249                      $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
2250
2251     my @fill;
2252     if ($self->_draw_flat_legend()) {
2253       @fill = (color => $self->_data_color($dataindex), filled => 1);
2254     }
2255     else {
2256       @fill = $self->_data_fill($dataindex, \@patchbox)
2257         or return;
2258     }
2259     $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2260                ymax=>$ypos + $patchsize, @fill);
2261     if ($self->{_style}{legend}{patchborder}) {
2262       $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2263                 ymax=>$ypos + $patchsize,
2264                 color=>$patchborder);
2265     }
2266     $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize, 
2267                  text=>$label);
2268
2269     my $step = $patchsize + $gap;
2270     if ($minrowsize < $sizes[$dataindex][3]) {
2271       $ypos += $sizes[$dataindex][3];
2272     }
2273     else {
2274       $ypos += $minrowsize;
2275     }
2276     ++$dataindex;
2277   }
2278   if ($self->{_style}{legend}{border}) {
2279     my $border_color = $self->_get_color('legend.border')
2280       or return;
2281     $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2282               color=>$border_color);
2283   }
2284   $self->_remove_box($chart_box, \@box);
2285   1;
2286 }
2287
2288 sub _draw_title {
2289   my ($self, $img, $chart_box) = @_;
2290
2291   my $title = $self->{_style}{title}{text};
2292   my @box = $self->_text_bbox($title, 'title')
2293     or return;
2294   my $yoff = $box[1];
2295   @box[0,1] = (0,0);
2296   $self->_align_box(\@box, $chart_box, 'title');
2297   my %text_info = $self->_text_style('title')
2298     or return;
2299   $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
2300   $self->_remove_box($chart_box, \@box);
2301   1;
2302 }
2303
2304 sub _small_extent {
2305   my ($self, $box) = @_;
2306
2307   if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
2308     return $box->[3] - $box->[1];
2309   }
2310   else {
2311     return $box->[2] - $box->[0];
2312   }
2313 }
2314
2315 sub _draw_flat_legend {
2316   return 0;
2317 }
2318
2319 =item _composite()
2320
2321 Returns a list of style fields that are stored as composites, and
2322 should be merged instead of just being replaced.
2323
2324 =cut
2325
2326 sub _composite {
2327   qw(title legend text label dropshadow outline callout);
2328 }
2329
2330 sub _filter_region {
2331   my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
2332
2333   unless (ref $filter) {
2334     my $name = $filter;
2335     $filter = $self->_get_thing($name)
2336       or return;
2337     $filter->{type}
2338       or return $self->_error("no type for filter $name");
2339   }
2340
2341   $left > 0 or $left = 0;
2342   $top > 0 or $top = 0;
2343
2344   # newer versions of Imager let you work on just part of an image
2345   if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
2346     my $masked = $img->masked(left=>$left, top=>$top,
2347                               right=>$right, bottom=>$bottom);
2348     $masked->filter(%$filter);
2349   }
2350   else {
2351     # for older versions of Imager
2352     my $subset = $img->crop(left=>$left, top=>$top,
2353                             right=>$right, bottom=>$bottom);
2354     $subset->filter(%$filter);
2355     $img->paste(left=>$left, top=>$top, img=>$subset);
2356   }
2357 }
2358
2359 1;
2360 __END__
2361
2362 =back
2363
2364 =head1 SEE ALSO
2365
2366 Imager::Graph::Pie(3), Imager(3), perl(1).
2367
2368 =head1 AUTHOR
2369
2370 Tony Cook <tony@develop-help.com>
2371
2372 =head1 LICENSE
2373
2374 Imager::Graph is licensed under the same terms as perl itself.
2375
2376 =head1 BLAME
2377
2378 Addi for producing a cool imaging module. :)
2379
2380 =cut