5 Imager::Graph - Perl extension for producing Graphs using the Imager library.
9 use Imager::Graph::SubClass;
10 my $chart = Imager::Graph::SubClass->new;
11 my $img = $chart->draw(data=>..., ...)
16 Imager::Graph provides style information to its base classes. It
17 defines the colors, text display information and fills based on both
18 built-in styles and modifications supplied by the user to the draw()
21 For best results you need a version of Imager after 0.38. At the time
22 of writing this is only available via CVS:
24 cvs -d :pserver:anoncvs@cvs.imager.perl.org:/u02/cvsroot login
25 cvs -d :pserver:anoncvs@cvs.imager.perl.org:/u02/cvsroot co Imager
27 This provides extra file format support, fountain (gradient), hatch
28 and image fills, and masked images.
35 use vars qw($VERSION);
36 use Imager qw(:handy);
41 my ($im_version) = ($Imager::VERSION =~ /(\d\.[\d_]+)/);
42 if ($im_version > 0.38) {
44 require 'Imager/Fountain.pm';
47 # the maximum recursion depth in determining a color, fill or number
48 use constant MAX_DEPTH => 10;
50 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
54 This is a simple constructor. No parameters required.
64 Returns an error message. Only value if the draw() method returns false.
74 Creates a new image, draws the chart onto that image and returns it.
76 Typically you will need to supply a C<data> parameter in the format
77 required by that particular graph, and if your graph will use any
78 text, a C<font> parameter
80 You can also supply many different parameters which control the way
81 the graph looks. These are supplied as keyword, value pairs, where
82 the value can be a hashref containing sub values.
84 The C<style> parameter will selects a basic color set, and possibly
85 sets other related parameters. See L</"STYLES">.
87 my $img = $graph->draw(data=>\@data,
88 title=>{ text=>"Hello, World!",
92 When referring to a single sub-value this documentation will refer to
93 'title.color' rather than 'the color element of title'.
95 Returns the graph image on success, or false on failure.
101 The currently defined styles are:
107 a light red background with no outlines. Uses primary colors for the
108 data fills. This style is compatible with all versions of Imager.
110 Graphs drawn using this style should save well as a gif, even though
111 some graphs may perform a slight blur.
113 This is the default style.
117 designed for monochrome output, such as most laser printers, this uses
118 hatched fills for the data, and no colors. The returned image is a
119 one channel image (which can be overridden with the C<channels>
122 You can also override the colors used by all components for background
123 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
124 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
125 else will be drawn in red. Another use might be to set a transparent
126 background, by supplying C<<bg=>'00000000', channels=>4>>.
128 This style outlines the legend if present and outlines the hashed fills.
130 This and following styles require versions of Imager after 0.38.
134 designed as a "pretty" style this uses linear fountain fills for the
135 background and data fills, and adds a drop shadow.
137 You can override the value used for text and outlines by setting the
142 also designed as a "pretty" style this uses radial fountain fills for
143 the data and a linear blue to green fill for the background.
149 Each graph type has a number of features. These are used to add
150 various items that are displayed in the graph area. Some common
157 adds a box containing boxes filled with the data filess, with
158 the labels provided to the draw method. The legend will only be
159 displayed if both the legend feature is enabled and labels are
164 labels each data fill, usually by including text inside the data fill.
165 If the text does not fit in the fill, they could be displayed in some
166 other form, eg. as callouts in a pie graph. There usually isn't much
167 point in including both labels and a legend.
171 a simple drop shadow is shown behind some of the graph elements.
175 Each graph also has features specific to that graph.
177 =head1 COMMON PARAMETERS
179 When referring to a single sub-value this documentation will refer to
180 'title.color' rather than 'the color element of title'.
182 Normally, except for the font parameter, these are controlled by
183 styles, but these are the style parameters I'd mostly likely expect
190 the Imager font object used to draw text on the chart.
194 the background fill for the graph. Default depends on the style.
198 the base size of the graph image. Default: 256
202 the width of the graph image. Default: 1.5 * size (384)
206 the height of the graph image. Default: size (256)
210 the number of channels in the image. Default: 3 (the 'mono' style
215 the color used for drawing lines, such as outlines or callouts.
216 Default depends on the current style. Set to undef to remove the
217 outline from a style.
221 the text used for a graph title. Default: no title. Note: this is
222 the same as the title=>{ text => ... } field.
228 horizontal alignment of the title in the graph, one of 'left',
229 'center' or 'right'. Default: center
233 vertical alignment of the title, one of 'top', 'center' or 'right'.
234 Default: top. It's probably a bad idea to set this to 'center' unless
235 you have a very short title.
241 This contains basic defaults used in drawing text.
247 the default color used for all text, defaults to the fg color.
251 the base size used for text, also used to scale many graph elements.
260 In most cases you will want to use just the styles, but you may want
261 to exert more control over the way your chart looks. This section
262 describes the options you can use to control the way your chart looks.
264 Hopefully you don't need to read this.
270 The background of the graph.
276 Used to define basic background and foreground colors for the graph.
277 The bg color may be used for the background of the graph, and is used
278 as a default for the background of hatcheed fills. The fg is used as
279 the default for line and text colors.
283 The default font used by the graph. Normally you should supply this
284 if your graph as any text.
288 The default line color.
292 defaults for drawing text. Other textual graph elements will inherit
293 or modify these values.
299 default text color, defaults to the I<fg> color.
303 default text size. Default: 14. This is used to scale many graph
304 elements, including padding and leader sizes. Other text elements
305 will either use or scale this value.
309 default font object. Inherited from I<font>, which should have been
310 supplied by the caller.
316 If you supply a scalar value for this element, it will be stored in
319 Defines the text, font and layout information for the title.
325 The color of the title, inherited from I<text.color>.
329 The font object used for the title, inherited from I<text.font>.
333 size of the title text. Default: double I<text.size>
339 The horizontal and vertical alignment of the title.
345 defines attributes of the graph legend, if present.
355 text attributes for the labels used in the legend.
359 the width and height of the color patch in the legend. Defaults to
360 90% of the legend text size.
364 the minimum gap between patches in pixels. Defaults to 30% of the
369 the color of the border drawn around each patch. Inherited from I<line>.
375 the horizontal and vertical alignment of the legend within the graph.
376 Defaults to 'right' and 'top'.
380 the gap between the legend patches and text and the outside of it's
381 box, or to the legend border, if any.
385 the gap between the border and the outside of the legend's box. This
386 is only used if the I<legend.border> attribute is defined.
390 the background fill for the legend. Default: none
394 the border color of the legend. Default: none (no border is drawn
401 defines attributes for graph callouts, if any are present. eg. if the
402 pie graph cannot fit the label into the pie graph segement it will
403 present it as a callout.
413 the text attributes of the callout label. Inherited from I<text>.
417 the color of the callout lines. Inherited from I<line>
423 the length of the leader on the inside and the outside of the fill,
424 usually at some angle. Both default to the size of the callout text.
428 the length of the horizontal portion of the leader. Default:
433 the gap between the callout leader and the callout text. Defaults to
434 30% of the text callout size.
440 defines attributes for labels drawn into the data areas of a graph.
450 The text attributes of the labels. Inherited from I<text>.
456 the attributes of the graph's drop shadow
462 the fill used for the drop shadow. Default: '404040' (dark gray)
466 the offset of the drop shadow. A convenience value inherited by offx
467 and offy. Default: 40% of I<text.size>.
473 the horizontal and vertical offsets of the drop shadow. Both
474 inherited from I<dropshadow.off>.
478 the filter description passed to Imager's filter method to blur the
479 drop shadow. Default: an 11 element convolution filter.
485 describes the lines drawn around filled data areas, such as the
486 segments of a pie chart.
492 the line color of the outlines, inherited from I<line>.
498 a reference to an array containing fills for each data item.
500 You can mix fill types, ie. using a simple color for the first item, a
501 hatched fill for the second and a fountain fill for the next.
505 =head1 HOW VALUES WORK
507 Internally rather than specifying literal color, fill, or font objects
508 or literal sizes for each element, Imager::Graph uses a number of
509 special values to inherit or modify values taken from other graph
512 =head2 Specifying colors
514 You can specify colors by either supplying an Imager::Color object, by
515 supplying lookup of another color, or by supplying a single value that
516 Imager::Color::new can use as an initializer. The most obvious is
517 just a 6 or 8 digit hex value representing the red, green, blue and
518 optionally alpha channels of the image.
520 You can lookup another color by using the lookup() "function", for
521 example if you give a color as "lookup(fg)" then Imager::Graph will
522 look for the fg element in the current style (or as overridden by
523 you.) This is used internally by Imager::Graph to set up the
524 relationships between the colors of various elements, for example the
525 default style information contains:
532 color=>'lookup(text.color)',
536 So by setting the I<fg> color, you also set the default text color,
537 since each text element uses lookup(text.color) as its value.
539 =head2 Specifying fills
541 Fills can be used for the graph background color, the background color
542 for the legend block and for the fills used for each data element.
544 You can specify a fill as a L<color value|Specifying colors> or as a
545 general fill, see L<Imager::Fill> for details. To use a general fill
546 you need a version of Imager after 0.38.
548 You don't need (or usually want) to call Imager::Fill::new yourself,
549 since the various fill functions will call it for you, and
550 Imager::Graph provides some hooks to make them more useful.
556 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
557 Imager::Graph will supply the current graph fg and bg colors.
561 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
562 and yb_ratio parameters, and they will be scaled in the fill area to
563 define the fountain fills xa, ya, xb and yb parameters.
567 As with colors, you can use lookup(name) or lookup(name1.name2) to
568 have one element to inherit the fill of another.
570 =head2 Specifying numbers
572 You can specify various numbers, usually representing the size of
573 something, commonly text, but sometimes the length of a line or the
576 You can use the same lookup mechanism as with colors and fills, but
577 you can also scale values. For example, 'scale(0.5,text.size)' will
578 return half the size of the normal text size.
580 As with colors, this is used internally to scale graph elements based
581 on the base text size. If you change the base text size then other
582 graph elements will scale as well.
584 =head2 Specifying other elements
586 Other elements, such as fonts, or parameters for a filter, can also
587 use the lookup(name) mechanism.
589 =head1 INTERNAL METHODS
591 Only useful if you need to fix bugs, add features or create a new
603 color => 'lookup(fg)',
604 font => 'lookup(font)',
608 color => 'lookup(text.color)',
609 font => 'lookup(text.font)',
612 size => 'scale(text.size,2.0)',
615 color => 'lookup(text.color)',
616 font => 'lookup(text.font)',
617 size => 'lookup(text.size)',
618 patchsize => 'scale(legend.size,0.9)',
619 patchgap => 'scale(legend.patchsize,0.3)',
620 patchborder => 'lookup(line)',
623 padding => 'scale(legend.size,0.3)',
624 outsidepadding => 'scale(legend.padding,0.4)',
627 color => 'lookup(text.color)',
628 font => 'lookup(text.font)',
629 size => 'lookup(text.size)',
630 line => 'lookup(line)',
631 inside => 'lookup(callout.size)',
632 outside => 'lookup(callout.size)',
633 leadlen => 'scale(0.8,callout.size)',
634 gap => 'scale(callout.size,0.3)',
637 font => 'lookup(text.font)',
638 size => 'lookup(text.size)',
639 color => 'lookup(text.color)',
640 hpad => 'lookup(label.pad)',
641 vpad => 'lookup(label.pad)',
642 pad => 'scale(label.size,0.2)',
643 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
644 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
648 off => 'scale(0.4,text.size)',
649 offx => 'lookup(dropshadow.off)',
650 offy => 'lookup(dropshadow.off)',
651 filter => { type=>'conv',
652 # this needs a fairly heavy blur
653 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
654 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
657 line =>'lookup(line)',
660 width=>'scale(1.5,size)',
661 height=>'lookup(size)',
664 =item _error($message)
666 Sets the error field of the object and returns an empty list or undef,
667 depending on context. Should be used for error handling, since it may
668 provide some user hooks at some point.
673 my ($self, $error) = @_;
675 $self->{_errstr} = $error;
683 Returns the style defaults, such as the relationships between line
684 color and text color.
686 Intended to be over-ridden by base classes to provide graph specific
695 my $def_style = 'primary_red';
703 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
709 patchborder=>'000000'
722 { hatch=>'stipple3' },
723 { hatch=>'stipple2' },
728 features=>{ outline=>1 },
740 { fountain=>'linear',
741 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
743 segments => Imager::Fountain->simple(positions=>[0, 1],
744 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
746 { fountain=>'linear',
747 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
748 segments => Imager::Fountain->simple(positions=>[0, 1],
749 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
751 { fountain=>'linear',
752 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
753 segments => Imager::Fountain->simple(positions=>[0, 1],
754 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
756 { fountain=>'linear',
757 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
758 segments => Imager::Fountain->simple(positions=>[0, 1],
759 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
761 { fountain=>'linear',
762 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
763 segments => Imager::Fountain->simple(positions=>[0, 1],
764 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
766 { fountain=>'linear',
767 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
768 segments => Imager::Fountain->simple(positions=>[0, 1],
769 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
772 back=>{ fountain=>'linear',
773 xa_ratio=>0, ya_ratio=>0,
774 xb_ratio=>1.0, yb_ratio=>1.0,
775 segments=>Imager::Fountain->simple
777 colors=>[ NC('6060FF'), NC('60FF60') ]) },
780 features=>{ dropshadow=>1 },
786 { fountain=>'radial',
787 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
788 segments => Imager::Fountain->simple(positions=>[0, 1],
789 colors=>[ NC('FF8080'), NC('FF0000') ]),
791 { fountain=>'radial',
792 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
793 segments => Imager::Fountain->simple(positions=>[0, 1],
794 colors=>[ NC('80FF80'), NC('00FF00') ]),
796 { fountain=>'radial',
797 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
798 segments => Imager::Fountain->simple(positions=>[0, 1],
799 colors=>[ NC('808080FF'), NC('0000FF') ]),
801 { fountain=>'radial',
802 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
803 segments => Imager::Fountain->simple(positions=>[0, 1],
804 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
806 { fountain=>'radial',
807 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
808 segments => Imager::Fountain->simple(positions=>[0, 1],
809 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
811 { fountain=>'radial',
812 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
813 segments => Imager::Fountain->simple(positions=>[0, 1],
814 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
817 back=>{ fountain=>'linear',
818 xa_ratio=>0, ya_ratio=>0,
819 xb_ratio=>1.0, yb_ratio=>1.0,
820 segments=>Imager::Fountain->simple
822 colors=>[ NC('6060FF'), NC('60FF60') ]) },
828 =item $self->_style_setup(\%opts)
830 Uses the values from %opts to build a customized hash describing the
831 way the graph should be drawn.
836 my ($self, $opts) = @_;
837 my $style_defs = $self->_style_defs;
839 $style = $styles{$opts->{style}} if $opts->{style};
840 $style ||= $styles{$def_style};
842 my @search_list = ( $style_defs, $style, $opts);
845 my @composite = $self->_composite();
847 @composite{@composite} = @composite;
849 for my $src (@search_list) {
850 for my $key (keys %$src) {
851 if ($composite{$key}) {
852 $work{$key} = {} unless exists $work{$key};
853 if (ref $src->{$key}) {
854 # some keys have sub values, especially text
855 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
858 # assume it's the text for a title or something
859 $work{$key}{text} = $src->{$key};
863 $work{$key} = $src->{$key};
868 # features are handled specially
869 $work{features} = {};
870 for my $src (@search_list) {
871 if ($src->{features}) {
872 if (ref $src->{features}) {
873 if (ref($src->{features}) =~ /ARRAY/) {
874 # just set those features
875 for my $feature (@{$src->{features}}) {
876 $work{features}{$feature} = 1;
879 elsif (ref($src->{features}) =~ /HASH/) {
880 if ($src->{features}{reset}) {
881 $work{features} = {}; # only the ones the user specifies
883 @{$work{features}}{keys %{$src->{features}}} =
884 values(%{$src->{features}});
888 # just set that single feature
889 $work{features}{$src->{features}} = 1;
894 #print Dumper(\%work);
896 $self->{_style} = \%work;
899 =item $self->_get_thing($name)
901 Retrieve some general 'thing'.
903 Supports the 'lookup(foo)' mechanism.
908 my ($self, $name, @depth) = @_;
912 if ($name =~ /^(\w+)\.(\w+)$/) {
913 $what = $self->{_style}{$1}{$2};
916 $what = $self->{_style}{$name};
923 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
925 or return $self->_error("too many levels of recursion in lookup(@depth)");
926 return $self->_get_thing($1, @depth);
933 =item $self->_get_number($name)
935 Retrieves a number from the style. The value in the style can be the
936 number, or one of two functions:
940 =item lookup(newname)
942 Recursively looks up I<newname> in the style.
944 =item scale(value1,value2)
946 Each value can be a number or a name. Names are recursively looks up
947 in the style and the product is returned.
953 my ($self, $name, @depth) = @_;
957 if ($name =~ /^(\w+)\.(\w+)$/) {
958 $what = $self->{_style}{$1}{$2};
961 $what = $self->{_style}{$name};
964 return $self->_error("$name is undef (@depth)");
967 if ($what =~ /CODE/) {
968 $what = $what->($self, $name);
972 if ($what =~ /^lookup\(([\w.]+)\)$/) {
974 or return $self->_error("too many levels of recursion in lookup (@depth)");
975 return $self->_get_number($1, @depth);
977 elsif ($what =~ /^scale\(
978 ((?:[a-z][\w.]*)|$NUM_RE)
980 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
981 my ($left, $right) = ($1, $2);
982 unless ($left =~ /^$NUM_RE$/) {
984 or return $self->_error("too many levels of recursion in scale (@depth)");
985 $left = $self->_get_number($left, @depth);
987 unless ($right =~ /^$NUM_RE$/) {
989 or return $self->_error("too many levels of recursion in scale (@depth)");
990 $right = $self->_get_number($right, @depth);
992 return $left * $right;
1000 =item _get_color($name)
1002 Returns a color object of the given name from the style hash.
1004 Uses Imager::Color->new to translate normal scalars into color objects.
1006 Allows the lookup(name) mechanism.
1011 my ($self, $name, @depth) = @_;
1013 push(@depth, $name);
1015 if ($name =~ /^(\w+)\.(\w+)$/) {
1016 $what = $self->{_style}{$1}{$2};
1019 $what = $self->{_style}{$name};
1023 or return $self->_error("$name was undefined (@depth)");
1025 unless (ref $what) {
1026 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1027 @depth < MAX_DEPTH or
1028 return $self->_error("too many levels of recursion in lookup (@depth)");
1030 return $self->_get_color($1, @depth);
1032 $what = Imager::Color->new($what);
1038 =item _translate_fill($what, $box)
1040 Given the value of a fill, either attempts to convert it into a fill
1041 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1042 parameters }>>), or to lookup another fill that is referred to with
1043 the 'lookup(name)' mechanism.
1045 This function does the fg and bg initialization for hatched fills, and
1046 translation of *_ratio for fountain fills (using the $box parameter).
1050 sub _translate_fill {
1051 my ($self, $what, $box, @depth) = @_;
1054 if (UNIVERSAL::isa($what, "Imager::Color")) {
1055 return ( color=>Imager::Color->new($what), filled=>1 );
1059 if ($what->{hatch}) {
1062 $work{fg} = $self->_get_color('fg')
1066 $work{bg} = $self->_get_color('bg')
1069 return ( fill=>\%work );
1071 elsif ($what->{fountain}) {
1073 for my $key (qw(xa ya xb yb)) {
1074 if (exists $work{"${key}_ratio"}) {
1076 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1077 * ($box->[2] - $box->[0]);
1080 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1081 * ($box->[3] - $box->[1]);
1085 return ( fill=>\%work );
1088 return ( fill=> $what );
1093 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1094 return $self->_get_fill($1, $box, @depth);
1097 # assumed to be an Imager::Color single value
1098 return ( color=>Imager::Color->new($what), filled=>1 );
1103 =item _data_fill($index, $box)
1105 Retrieves the fill parameters for a data area fill.
1110 my ($self, $index, $box) = @_;
1112 my $fills = $self->{_style}{fills};
1113 return $self->_translate_fill($fills->[$index % @$fills], $box,
1117 =item _get_fill($index, $box)
1119 Retrieves fill parameters for a named fill.
1124 my ($self, $name, $box, @depth) = @_;
1126 push(@depth, $name);
1128 if ($name =~ /^(\w+)\.(\w+)$/) {
1129 $what = $self->{_style}{$1}{$2};
1132 $what = $self->{_style}{$name};
1136 or return $self->_error("no fill $name found");
1138 return $self->_translate_fill($what, $box, @depth);
1143 Builds the image object for the graph and fills it with the background
1151 my ($width, $height) = (256, 256);
1153 $width = $self->_get_number('width');
1154 $height = $self->_get_number('height');
1155 my $channels = $self->{_style}{channels};
1159 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1161 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1167 my ($self, $name) = @_;
1171 if ($self->{_style}{$name}) {
1172 %work = %{$self->{_style}{$name}};
1175 %work = %{$self->{_style}{text}};
1178 or return $self->_error("$name has no font parameter");
1180 $work{font} = $self->_get_thing("$name.font")
1181 or return $self->_error("invalid font");
1182 UNIVERSAL::isa($work{font}, "Imager::Font")
1183 or return $self->_error("$name.font is not a font");
1184 if ($work{color} && !ref $work{color}) {
1185 $work{color} = $self->_get_color("$name.color")
1188 $work{size} = $self->_get_number("$name.size");
1189 $work{sizew} = $self->_get_number("$name.sizew")
1196 my ($self, $text, $name) = @_;
1198 my %text_info = $self->_text_style($name);
1200 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1207 my ($self, $box, $chart_box, $name) = @_;
1209 my $halign = $self->{_style}{$name}{halign}
1210 or $self->_error("no halign for $name");
1211 my $valign = $self->{_style}{$name}{valign};
1213 if ($halign eq 'right') {
1214 $box->[0] += $chart_box->[2] - $box->[2];
1216 elsif ($halign eq 'left') {
1217 $box->[0] = $chart_box->[0];
1219 elsif ($halign eq 'center' || $halign eq 'centre') {
1220 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1223 return $self->_error("invalid halign $halign for $name");
1226 if ($valign eq 'top') {
1227 $box->[1] = $chart_box->[1];
1229 elsif ($valign eq 'bottom') {
1230 $box->[1] = $chart_box->[3] - $box->[3];
1232 elsif ($valign eq 'center' || $valign eq 'centre') {
1233 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1236 return $self->_error("invalid valign $valign for $name");
1238 $box->[2] += $box->[0];
1239 $box->[3] += $box->[1];
1243 my ($self, $chart_box, $object_box) = @_;
1247 if ($object_box->[0] - $chart_box->[0]
1248 < $chart_box->[2] - $object_box->[2]) {
1249 $areax = ($object_box->[2] - $chart_box->[0])
1250 * ($chart_box->[3] - $chart_box->[1]);
1253 $areax = ($chart_box->[2] - $object_box->[0])
1254 * ($chart_box->[3] - $chart_box->[1]);
1257 if ($object_box->[1] - $chart_box->[1]
1258 < $chart_box->[3] - $object_box->[3]) {
1259 $areay = ($object_box->[3] - $chart_box->[1])
1260 * ($chart_box->[2] - $chart_box->[0]);
1263 $areay = ($chart_box->[3] - $object_box->[1])
1264 * ($chart_box->[2] - $chart_box->[0]);
1267 if ($areay < $areax) {
1268 if ($object_box->[1] - $chart_box->[1]
1269 < $chart_box->[3] - $object_box->[3]) {
1270 $chart_box->[1] = $object_box->[3];
1273 $chart_box->[3] = $object_box->[1];
1277 if ($object_box->[0] - $chart_box->[0]
1278 < $chart_box->[2] - $object_box->[2]) {
1279 $chart_box->[0] = $object_box->[2];
1282 $chart_box->[2] = $object_box->[0];
1288 my ($self, $img, $labels, $chart_box) = @_;
1290 defined(my $padding = $self->_get_number('legend.padding'))
1292 my $patchsize = $self->_get_number('legend.patchsize')
1294 defined(my $gap = $self->_get_number('legend.patchgap'))
1296 my $minrowsize = $patchsize + $gap;
1297 my ($width, $height) = (0,0);
1299 for my $label (@$labels) {
1300 my @box = $self->_text_bbox($label, 'legend');
1301 push(@sizes, \@box);
1302 $width = $box[2] if $box[2] > $width;
1303 if ($minrowsize > $box[3]) {
1304 $height += $minrowsize;
1311 $width + $patchsize + $padding * 2 + $gap,
1312 $height + $padding * 2 - $gap);
1313 my $outsidepadding = 0;
1314 if ($self->{_style}{legend}{border}) {
1315 defined($outsidepadding = $self->_get_number('legend.outsidepadding'))
1317 $box[2] += 2 * $outsidepadding;
1318 $box[3] += 2 * $outsidepadding;
1320 $self->_align_box(\@box, $chart_box, 'legend')
1322 if ($self->{_style}{legend}{fill}) {
1323 $img->box(xmin=>$box[0]+$outsidepadding,
1324 ymin=>$box[1]+$outsidepadding,
1325 xmax=>$box[2]-$outsidepadding,
1326 ymax=>$box[3]-$outsidepadding,
1327 $self->_get_fill('legend.fill', \@box));
1329 $box[0] += $outsidepadding;
1330 $box[1] += $outsidepadding;
1331 $box[2] -= $outsidepadding;
1332 $box[3] -= $outsidepadding;
1333 my $ypos = $box[1] + $padding;
1334 my $patchpos = $box[0]+$padding;
1335 my $textpos = $patchpos + $patchsize + $gap;
1336 my %text_info = $self->_text_style('legend')
1339 if ($self->{_style}{legend}{patchborder}) {
1340 $patchborder = $self->_get_color('legend.patchborder')
1344 for my $label (@$labels) {
1345 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
1346 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
1347 my @fill = $self->_data_fill($dataindex, \@patchbox)
1349 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1350 ymax=>$ypos + $patchsize, @fill);
1351 if ($self->{_style}{legend}{patchborder}) {
1352 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1353 ymax=>$ypos + $patchsize,
1354 color=>$patchborder);
1356 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
1359 my $step = $patchsize + $gap;
1360 if ($minrowsize < $sizes[$dataindex][3]) {
1361 $ypos += $sizes[$dataindex][3];
1364 $ypos += $minrowsize;
1368 if ($self->{_style}{legend}{border}) {
1369 my $border_color = $self->_get_color('legend.border')
1371 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1372 color=>$border_color);
1374 $self->_remove_box($chart_box, \@box);
1379 my ($self, $img, $chart_box) = @_;
1381 my $title = $self->{_style}{title}{text};
1382 my @box = $self->_text_bbox($title, 'title');
1385 $self->_align_box(\@box, $chart_box, 'title');
1386 my %text_info = $self->_text_style('title');
1387 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
1388 $self->_remove_box($chart_box, \@box);
1393 my ($self, $box) = @_;
1395 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
1396 return $box->[3] - $box->[1];
1399 return $box->[2] - $box->[0];
1405 Returns a list of style fields that are stored as composites, and
1406 should be merged instead of just being replaced.
1411 qw(title legend text label dropshadow outline callout);
1414 sub _filter_region {
1415 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
1417 unless (ref $filter) {
1419 $filter = $self->_get_thing($name)
1422 or return $self->_error("no type for filter $name");
1425 $left > 0 or $left = 0;
1426 $top > 0 or $top = 0;
1428 # newer versions of Imager let you work on just part of an image
1429 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
1430 my $masked = $img->masked(left=>$left, top=>$top,
1431 right=>$right, bottom=>$bottom);
1432 $masked->filter(%$filter);
1435 # for older versions of Imager
1436 my $subset = $img->crop(left=>$left, top=>$top,
1437 right=>$right, bottom=>$bottom);
1438 $subset->filter(%$filter);
1439 $img->paste(left=>$left, top=>$top, img=>$subset);
1450 Imager::Graph::Pie(3), Imager(3), perl(1).
1454 Tony Cook <tony@develop-help.com>
1458 Addi for producing a cool imaging module. :)