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