6 Imager::Graph - Perl extension for producing Graphs using the Imager library.
10 use Imager::Graph::SubClass;
11 my $chart = Imager::Graph::SubClass->new;
12 my $img = $chart->draw(data=>..., ...)
17 Imager::Graph provides style information to its base classes. It
18 defines the colors, text display information and fills based on both
19 built-in styles and modifications supplied by the user to the draw()
22 For best results you need a version of Imager after 0.38. At the time
23 of writing this is only available via CVS:
25 cvs -d :pserver:anoncvs@cvs.imager.perl.org:/u02/cvsroot login
26 cvs -d :pserver:anoncvs@cvs.imager.perl.org:/u02/cvsroot co Imager
28 This provides extra file format support, fountain (gradient), hatch
29 and image fills, and masked images.
36 use vars qw($VERSION);
37 use Imager qw(:handy);
42 # the maximum recursion depth in determining a color, fill or number
43 use constant MAX_DEPTH => 10;
45 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
49 This is a simple constructor. No parameters required.
59 Returns an error message. Only value if the draw() method returns false.
69 Creates a new image, draws the chart onto that image and returns it.
71 Typically you will need to supply a C<data> parameter in the format
72 required by that particular graph, and if your graph will use any
73 text, a C<font> parameter
75 You can also supply many different parameters which control the way
76 the graph looks. These are supplied as keyword, value pairs, where
77 the value can be a hashref containing sub values.
79 The C<style> parameter will selects a basic color set, and possibly
80 sets other related parameters. See L</"STYLES">.
82 my $img = $graph->draw(data=>\@data,
83 title=>{ text=>"Hello, World!",
87 When referring to a single sub-value this documentation will refer to
88 'title.color' rather than 'the color element of title'.
90 Returns the graph image on success, or false on failure.
96 The currently defined styles are:
102 a light red background with no outlines. Uses primary colors for the
103 data fills. This style is compatible with all versions of Imager.
105 Graphs drawn using this style should save well as a gif, even though
106 some graphs may perform a slight blur.
108 This is the default style.
112 designed for monochrome output, such as most laser printers, this uses
113 hatched fills for the data, and no colors. The returned image is a
114 one channel image (which can be overridden with the C<channels>
117 You can also override the colors used by all components for background
118 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
119 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
120 else will be drawn in red. Another use might be to set a transparent
121 background, by supplying C<<bg=>'00000000', channels=>4>>.
123 This style outlines the legend if present and outlines the hashed fills.
125 This and following styles require versions of Imager after 0.38.
129 designed as a "pretty" style this uses linear fountain fills for the
130 background and data fills, and adds a drop shadow.
132 You can override the value used for text and outlines by setting the
137 also designed as a "pretty" style this uses radial fountain fills for
138 the data and a linear blue to green fill for the background.
144 Each graph type has a number of features. These are used to add
145 various items that are displayed in the graph area. Some common
152 adds a box containing boxes filled with the data filess, with
153 the labels provided to the draw method. The legend will only be
154 displayed if both the legend feature is enabled and labels are
159 labels each data fill, usually by including text inside the data fill.
160 If the text does not fit in the fill, they could be displayed in some
161 other form, eg. as callouts in a pie graph. There usually isn't much
162 point in including both labels and a legend.
166 a simple drop shadow is shown behind some of the graph elements.
170 Each graph also has features specific to that graph.
172 =head1 COMMON PARAMETERS
174 When referring to a single sub-value this documentation will refer to
175 'title.color' rather than 'the color element of title'.
177 Normally, except for the font parameter, these are controlled by
178 styles, but these are the style parameters I'd mostly likely expect
185 the Imager font object used to draw text on the chart.
189 the background fill for the graph. Default depends on the style.
193 the base size of the graph image. Default: 256
197 the width of the graph image. Default: 1.5 * size (384)
201 the height of the graph image. Default: size (256)
205 the number of channels in the image. Default: 3 (the 'mono' style
210 the color used for drawing lines, such as outlines or callouts.
211 Default depends on the current style. Set to undef to remove the
212 outline from a style.
216 the text used for a graph title. Default: no title. Note: this is
217 the same as the title=>{ text => ... } field.
223 horizontal alignment of the title in the graph, one of 'left',
224 'center' or 'right'. Default: center
228 vertical alignment of the title, one of 'top', 'center' or 'right'.
229 Default: top. It's probably a bad idea to set this to 'center' unless
230 you have a very short title.
236 This contains basic defaults used in drawing text.
242 the default color used for all text, defaults to the fg color.
246 the base size used for text, also used to scale many graph elements.
255 In most cases you will want to use just the styles, but you may want
256 to exert more control over the way your chart looks. This section
257 describes the options you can use to control the way your chart looks.
259 Hopefully you don't need to read this.
265 The background of the graph.
271 Used to define basic background and foreground colors for the graph.
272 The bg color may be used for the background of the graph, and is used
273 as a default for the background of hatcheed fills. The fg is used as
274 the default for line and text colors.
278 The default font used by the graph. Normally you should supply this
279 if your graph as any text.
283 The default line color.
287 defaults for drawing text. Other textual graph elements will inherit
288 or modify these values.
294 default text color, defaults to the I<fg> color.
298 default text size. Default: 14. This is used to scale many graph
299 elements, including padding and leader sizes. Other text elements
300 will either use or scale this value.
304 default font object. Inherited from I<font>, which should have been
305 supplied by the caller.
311 If you supply a scalar value for this element, it will be stored in
314 Defines the text, font and layout information for the title.
320 The color of the title, inherited from I<text.color>.
324 The font object used for the title, inherited from I<text.font>.
328 size of the title text. Default: double I<text.size>
334 The horizontal and vertical alignment of the title.
340 defines attributes of the graph legend, if present.
350 text attributes for the labels used in the legend.
354 the width and height of the color patch in the legend. Defaults to
355 90% of the legend text size.
359 the minimum gap between patches in pixels. Defaults to 30% of the
364 the color of the border drawn around each patch. Inherited from I<line>.
370 the horizontal and vertical alignment of the legend within the graph.
371 Defaults to 'right' and 'top'.
375 the gap between the legend patches and text and the outside of it's
376 box, or to the legend border, if any.
380 the gap between the border and the outside of the legend's box. This
381 is only used if the I<legend.border> attribute is defined.
385 the background fill for the legend. Default: none
389 the border color of the legend. Default: none (no border is drawn
396 defines attributes for graph callouts, if any are present. eg. if the
397 pie graph cannot fit the label into the pie graph segement it will
398 present it as a callout.
408 the text attributes of the callout label. Inherited from I<text>.
412 the color of the callout lines. Inherited from I<line>
418 the length of the leader on the inside and the outside of the fill,
419 usually at some angle. Both default to the size of the callout text.
423 the length of the horizontal portion of the leader. Default:
428 the gap between the callout leader and the callout text. Defaults to
429 30% of the text callout size.
435 defines attributes for labels drawn into the data areas of a graph.
445 The text attributes of the labels. Inherited from I<text>.
451 the attributes of the graph's drop shadow
457 the fill used for the drop shadow. Default: '404040' (dark gray)
461 the offset of the drop shadow. A convenience value inherited by offx
462 and offy. Default: 40% of I<text.size>.
468 the horizontal and vertical offsets of the drop shadow. Both
469 inherited from I<dropshadow.off>.
473 the filter description passed to Imager's filter method to blur the
474 drop shadow. Default: an 11 element convolution filter.
480 describes the lines drawn around filled data areas, such as the
481 segments of a pie chart.
487 the line color of the outlines, inherited from I<line>.
493 a reference to an array containing fills for each data item.
495 You can mix fill types, ie. using a simple color for the first item, a
496 hatched fill for the second and a fountain fill for the next.
500 =head1 HOW VALUES WORK
502 Internally rather than specifying literal color, fill, or font objects
503 or literal sizes for each element, Imager::Graph uses a number of
504 special values to inherit or modify values taken from other graph
507 =head2 Specifying colors
509 You can specify colors by either supplying an Imager::Color object, by
510 supplying lookup of another color, or by supplying a single value that
511 Imager::Color::new can use as an initializer. The most obvious is
512 just a 6 or 8 digit hex value representing the red, green, blue and
513 optionally alpha channels of the image.
515 You can lookup another color by using the lookup() "function", for
516 example if you give a color as "lookup(fg)" then Imager::Graph will
517 look for the fg element in the current style (or as overridden by
518 you.) This is used internally by Imager::Graph to set up the
519 relationships between the colors of various elements, for example the
520 default style information contains:
527 color=>'lookup(text.color)',
531 So by setting the I<fg> color, you also set the default text color,
532 since each text element uses lookup(text.color) as its value.
534 =head2 Specifying fills
536 Fills can be used for the graph background color, the background color
537 for the legend block and for the fills used for each data element.
539 You can specify a fill as a L<color value|Specifying colors> or as a
540 general fill, see L<Imager::Fill> for details. To use a general fill
541 you need a version of Imager after 0.38.
543 You don't need (or usually want) to call Imager::Fill::new yourself,
544 since the various fill functions will call it for you, and
545 Imager::Graph provides some hooks to make them more useful.
551 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
552 Imager::Graph will supply the current graph fg and bg colors.
556 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
557 and yb_ratio parameters, and they will be scaled in the fill area to
558 define the fountain fills xa, ya, xb and yb parameters.
562 As with colors, you can use lookup(name) or lookup(name1.name2) to
563 have one element to inherit the fill of another.
565 =head2 Specifying numbers
567 You can specify various numbers, usually representing the size of
568 something, commonly text, but sometimes the length of a line or the
571 You can use the same lookup mechanism as with colors and fills, but
572 you can also scale values. For example, 'scale(0.5,text.size)' will
573 return half the size of the normal text size.
575 As with colors, this is used internally to scale graph elements based
576 on the base text size. If you change the base text size then other
577 graph elements will scale as well.
579 =head2 Specifying other elements
581 Other elements, such as fonts, or parameters for a filter, can also
582 use the lookup(name) mechanism.
584 =head1 INTERNAL METHODS
586 Only useful if you need to fix bugs, add features or create a new
598 color => 'lookup(fg)',
599 font => 'lookup(font)',
603 color => 'lookup(text.color)',
604 font => 'lookup(text.font)',
607 size => 'scale(text.size,2.0)',
610 color => 'lookup(text.color)',
611 font => 'lookup(text.font)',
612 size => 'lookup(text.size)',
613 patchsize => 'scale(legend.size,0.9)',
614 patchgap => 'scale(legend.patchsize,0.3)',
615 patchborder => 'lookup(line)',
618 padding => 'scale(legend.size,0.3)',
619 outsidepadding => 'scale(legend.padding,0.4)',
622 color => 'lookup(text.color)',
623 font => 'lookup(text.font)',
624 size => 'lookup(text.size)',
625 line => 'lookup(line)',
626 inside => 'lookup(callout.size)',
627 outside => 'lookup(callout.size)',
628 leadlen => 'scale(0.8,callout.size)',
629 gap => 'scale(callout.size,0.3)',
632 font => 'lookup(text.font)',
633 size => 'lookup(text.size)',
634 color => 'lookup(text.color)',
635 hpad => 'lookup(label.pad)',
636 vpad => 'lookup(label.pad)',
637 pad => 'scale(label.size,0.2)',
638 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
639 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
643 off => 'scale(0.4,text.size)',
644 offx => 'lookup(dropshadow.off)',
645 offy => 'lookup(dropshadow.off)',
646 filter => { type=>'conv',
647 # this needs a fairly heavy blur
648 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
649 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
652 line =>'lookup(line)',
655 width=>'scale(1.5,size)',
656 height=>'lookup(size)',
659 =item _error($message)
661 Sets the error field of the object and returns an empty list or undef,
662 depending on context. Should be used for error handling, since it may
663 provide some user hooks at some point.
668 my ($self, $error) = @_;
670 $self->{_errstr} = $error;
678 Returns the style defaults, such as the relationships between line
679 color and text color.
681 Intended to be over-ridden by base classes to provide graph specific
690 my $def_style = 'primary_red';
698 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
704 patchborder=>'000000'
717 { hatch=>'stipple3' },
718 { hatch=>'stipple2' },
723 features=>{ outline=>1 },
732 { fountain=>'linear',
733 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
735 segments => Imager::Fountain->simple(positions=>[0, 1],
736 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
738 { fountain=>'linear',
739 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
740 segments => Imager::Fountain->simple(positions=>[0, 1],
741 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
743 { fountain=>'linear',
744 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
745 segments => Imager::Fountain->simple(positions=>[0, 1],
746 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
748 { fountain=>'linear',
749 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
750 segments => Imager::Fountain->simple(positions=>[0, 1],
751 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
753 { fountain=>'linear',
754 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
755 segments => Imager::Fountain->simple(positions=>[0, 1],
756 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
758 { fountain=>'linear',
759 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
760 segments => Imager::Fountain->simple(positions=>[0, 1],
761 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
764 back=>{ fountain=>'linear',
765 xa_ratio=>0, ya_ratio=>0,
766 xb_ratio=>1.0, yb_ratio=>1.0,
767 segments=>Imager::Fountain->simple
769 colors=>[ NC('6060FF'), NC('60FF60') ]) },
772 features=>{ dropshadow=>1 },
778 { fountain=>'radial',
779 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
780 segments => Imager::Fountain->simple(positions=>[0, 1],
781 colors=>[ NC('FF8080'), NC('FF0000') ]),
783 { fountain=>'radial',
784 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
785 segments => Imager::Fountain->simple(positions=>[0, 1],
786 colors=>[ NC('80FF80'), NC('00FF00') ]),
788 { fountain=>'radial',
789 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
790 segments => Imager::Fountain->simple(positions=>[0, 1],
791 colors=>[ NC('808080FF'), NC('0000FF') ]),
793 { fountain=>'radial',
794 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
795 segments => Imager::Fountain->simple(positions=>[0, 1],
796 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
798 { fountain=>'radial',
799 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
800 segments => Imager::Fountain->simple(positions=>[0, 1],
801 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
803 { fountain=>'radial',
804 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
805 segments => Imager::Fountain->simple(positions=>[0, 1],
806 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
809 back=>{ fountain=>'linear',
810 xa_ratio=>0, ya_ratio=>0,
811 xb_ratio=>1.0, yb_ratio=>1.0,
812 segments=>Imager::Fountain->simple
814 colors=>[ NC('6060FF'), NC('60FF60') ]) },
820 =item $self->_style_setup(\%opts)
822 Uses the values from %opts to build a customized hash describing the
823 way the graph should be drawn.
828 my ($self, $opts) = @_;
829 my $style_defs = $self->_style_defs;
831 $style = $styles{$opts->{style}} if $opts->{style};
832 $style ||= $styles{$def_style};
834 my @search_list = ( $style_defs, $style, $opts);
837 my @composite = $self->_composite();
839 @composite{@composite} = @composite;
841 for my $src (@search_list) {
842 for my $key (keys %$src) {
843 if ($composite{$key}) {
844 $work{$key} = {} unless exists $work{$key};
845 if (ref $src->{$key}) {
846 # some keys have sub values, especially text
847 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
850 # assume it's the text for a title or something
851 $work{$key}{text} = $src->{$key};
855 $work{$key} = $src->{$key};
860 # features are handled specially
861 $work{features} = {};
862 for my $src (@search_list) {
863 if ($src->{features}) {
864 if (ref $src->{features}) {
865 if (ref($src->{features}) =~ /ARRAY/) {
866 # just set those features
867 for my $feature (@{$src->{features}}) {
868 $work{features}{$feature} = 1;
871 elsif (ref($src->{features}) =~ /HASH/) {
872 if ($src->{features}{reset}) {
873 $work{features} = {}; # only the ones the user specifies
875 @{$work{features}}{keys %{$src->{features}}} =
876 values(%{$src->{features}});
880 # just set that single feature
881 $work{features}{$src->{features}} = 1;
886 #print Dumper(\%work);
888 $self->{_style} = \%work;
891 =item $self->_get_thing($name)
893 Retrieve some general 'thing'.
895 Supports the 'lookup(foo)' mechanism.
900 my ($self, $name, @depth) = @_;
904 if ($name =~ /^(\w+)\.(\w+)$/) {
905 $what = $self->{_style}{$1}{$2};
908 $what = $self->{_style}{$name};
915 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
917 or return $self->_error("too many levels of recursion in lookup(@depth)");
918 return $self->_get_thing($1, @depth);
925 =item $self->_get_number($name)
927 Retrieves a number from the style. The value in the style can be the
928 number, or one of two functions:
932 =item lookup(newname)
934 Recursively looks up I<newname> in the style.
936 =item scale(value1,value2)
938 Each value can be a number or a name. Names are recursively looks up
939 in the style and the product is returned.
946 my ($self, $name, @depth) = @_;
950 if ($name =~ /^(\w+)\.(\w+)$/) {
951 $what = $self->{_style}{$1}{$2};
954 $what = $self->{_style}{$name};
957 return $self->_error("$name is undef (@depth)");
960 if ($what =~ /CODE/) {
961 $what = $what->($self, $name);
965 if ($what =~ /^lookup\(([\w.]+)\)$/) {
967 or return $self->_error("too many levels of recursion in lookup (@depth)");
968 return $self->_get_number($1, @depth);
970 elsif ($what =~ /^scale\(
971 ((?:[a-z][\w.]*)|$NUM_RE)
973 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
974 my ($left, $right) = ($1, $2);
975 unless ($left =~ /^$NUM_RE$/) {
977 or return $self->_error("too many levels of recursion in scale (@depth)");
978 $left = $self->_get_number($left, @depth);
980 unless ($right =~ /^$NUM_RE$/) {
982 or return $self->_error("too many levels of recursion in scale (@depth)");
983 $right = $self->_get_number($right, @depth);
985 return $left * $right;
993 =item _get_color($name)
995 Returns a color object of the given name from the style hash.
997 Uses Imager::Color->new to translate normal scalars into color objects.
999 Allows the lookup(name) mechanism.
1004 my ($self, $name, @depth) = @_;
1006 push(@depth, $name);
1008 if ($name =~ /^(\w+)\.(\w+)$/) {
1009 $what = $self->{_style}{$1}{$2};
1012 $what = $self->{_style}{$name};
1016 or return $self->_error("$name was undefined (@depth)");
1018 unless (ref $what) {
1019 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1020 @depth < MAX_DEPTH or
1021 return $self->_error("too many levels of recursion in lookup (@depth)");
1023 return $self->_get_color($1, @depth);
1025 $what = Imager::Color->new($what);
1031 =item _translate_fill($what, $box)
1033 Given the value of a fill, either attempts to convert it into a fill
1034 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1035 parameters }>>), or to lookup another fill that is referred to with
1036 the 'lookup(name)' mechanism.
1038 This function does the fg and bg initialization for hatched fills, and
1039 translation of *_ratio for fountain fills (using the $box parameter).
1043 sub _translate_fill {
1044 my ($self, $what, $box, @depth) = @_;
1047 if (UNIVERSAL::isa($what, "Imager::Color")) {
1048 return ( color=>Imager::Color->new($what), filled=>1 );
1052 if ($what->{hatch}) {
1055 $work{fg} = $self->_get_color('fg')
1059 $work{bg} = $self->_get_color('bg')
1062 return ( fill=>\%work );
1064 elsif ($what->{fountain}) {
1066 for my $key (qw(xa ya xb yb)) {
1067 if (exists $work{"${key}_ratio"}) {
1069 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1070 * ($box->[2] - $box->[0]);
1073 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1074 * ($box->[3] - $box->[1]);
1078 return ( fill=>\%work );
1081 return ( fill=> $what );
1086 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1087 return $self->_get_fill($1, $box, @depth);
1090 # assumed to be an Imager::Color single value
1091 return ( color=>Imager::Color->new($what), filled=>1 );
1096 =item _data_fill($index, $box)
1098 Retrieves the fill parameters for a data area fill.
1103 my ($self, $index, $box) = @_;
1105 my $fills = $self->{_style}{fills};
1106 return $self->_translate_fill($fills->[$index % @$fills], $box,
1110 =item _get_fill($index, $box)
1112 Retrieves fill parameters for a named fill.
1117 my ($self, $name, $box, @depth) = @_;
1119 push(@depth, $name);
1121 if ($name =~ /^(\w+)\.(\w+)$/) {
1122 $what = $self->{_style}{$1}{$2};
1125 $what = $self->{_style}{$name};
1129 or return $self->_error("no fill $name found");
1131 return $self->_translate_fill($what, $box, @depth);
1136 Builds the image object for the graph and fills it with the background
1144 my ($width, $height) = (256, 256);
1146 $width = $self->_get_number('width');
1147 $height = $self->_get_number('height');
1148 my $channels = $self->{_style}{channels};
1152 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1154 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1160 my ($self, $name) = @_;
1164 if ($self->{_style}{$name}) {
1165 %work = %{$self->{_style}{$name}};
1168 %work = %{$self->{_style}{text}};
1171 or return $self->_error("$name has no font parameter");
1173 $work{font} = $self->_get_thing("$name.font")
1174 or return $self->_error("invalid font");
1175 UNIVERSAL::isa($work{font}, "Imager::Font")
1176 or return $self->_error("$name.font is not a font");
1177 if ($work{color} && !ref $work{color}) {
1178 $work{color} = $self->_get_color("$name.color")
1181 $work{size} = $self->_get_number("$name.size");
1182 $work{sizew} = $self->_get_number("$name.sizew")
1189 my ($self, $text, $name) = @_;
1191 my %text_info = $self->_text_style($name);
1193 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1200 my ($self, $box, $chart_box, $name) = @_;
1202 my $halign = $self->{_style}{$name}{halign}
1203 or $self->_error("no halign for $name");
1204 my $valign = $self->{_style}{$name}{valign};
1206 if ($halign eq 'right') {
1207 $box->[0] += $chart_box->[2] - $box->[2];
1209 elsif ($halign eq 'left') {
1210 $box->[0] = $chart_box->[0];
1212 elsif ($halign eq 'center' || $halign eq 'centre') {
1213 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1216 return $self->_error("invalid halign $halign for $name");
1219 if ($valign eq 'top') {
1220 $box->[1] = $chart_box->[1];
1222 elsif ($valign eq 'bottom') {
1223 $box->[1] = $chart_box->[3] - $box->[3];
1225 elsif ($valign eq 'center' || $valign eq 'centre') {
1226 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1229 return $self->_error("invalid valign $valign for $name");
1231 $box->[2] += $box->[0];
1232 $box->[3] += $box->[1];
1236 my ($self, $chart_box, $object_box) = @_;
1240 if ($object_box->[0] - $chart_box->[0]
1241 < $chart_box->[2] - $object_box->[2]) {
1242 $areax = ($object_box->[2] - $chart_box->[0])
1243 * ($chart_box->[3] - $chart_box->[1]);
1246 $areax = ($chart_box->[2] - $object_box->[0])
1247 * ($chart_box->[3] - $chart_box->[1]);
1250 if ($object_box->[1] - $chart_box->[1]
1251 < $chart_box->[3] - $object_box->[3]) {
1252 $areay = ($object_box->[3] - $chart_box->[1])
1253 * ($chart_box->[2] - $chart_box->[0]);
1256 $areay = ($chart_box->[3] - $object_box->[1])
1257 * ($chart_box->[2] - $chart_box->[0]);
1260 if ($areay < $areax) {
1261 if ($object_box->[1] - $chart_box->[1]
1262 < $chart_box->[3] - $object_box->[3]) {
1263 $chart_box->[1] = $object_box->[3];
1266 $chart_box->[3] = $object_box->[1];
1270 if ($object_box->[0] - $chart_box->[0]
1271 < $chart_box->[2] - $object_box->[2]) {
1272 $chart_box->[0] = $object_box->[2];
1275 $chart_box->[2] = $object_box->[0];
1281 my ($self, $img, $labels, $chart_box) = @_;
1283 defined(my $padding = $self->_get_number('legend.padding'))
1285 my $patchsize = $self->_get_number('legend.patchsize')
1287 defined(my $gap = $self->_get_number('legend.patchgap'))
1289 my $minrowsize = $patchsize + $gap;
1290 my ($width, $height) = (0,0);
1292 for my $label (@$labels) {
1293 my @box = $self->_text_bbox($label, 'legend');
1294 push(@sizes, \@box);
1295 $width = $box[2] if $box[2] > $width;
1296 if ($minrowsize > $box[3]) {
1297 $height += $minrowsize;
1304 $width + $patchsize + $padding * 2 + $gap,
1305 $height + $padding * 2 - $gap);
1306 my $outsidepadding = 0;
1307 if ($self->{_style}{legend}{border}) {
1308 defined($outsidepadding = $self->_get_number('legend.outsidepadding'))
1310 $box[2] += 2 * $outsidepadding;
1311 $box[3] += 2 * $outsidepadding;
1313 $self->_align_box(\@box, $chart_box, 'legend')
1315 if ($self->{_style}{legend}{fill}) {
1316 $img->box(xmin=>$box[0]+$outsidepadding,
1317 ymin=>$box[1]+$outsidepadding,
1318 xmax=>$box[2]-$outsidepadding,
1319 ymax=>$box[3]-$outsidepadding,
1320 $self->_get_fill('legend.fill', \@box));
1322 $box[0] += $outsidepadding;
1323 $box[1] += $outsidepadding;
1324 $box[2] -= $outsidepadding;
1325 $box[3] -= $outsidepadding;
1326 my $ypos = $box[1] + $padding;
1327 my $patchpos = $box[0]+$padding;
1328 my $textpos = $patchpos + $patchsize + $gap;
1329 my %text_info = $self->_text_style('legend')
1332 if ($self->{_style}{legend}{patchborder}) {
1333 $patchborder = $self->_get_color('legend.patchborder')
1337 for my $label (@$labels) {
1338 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
1339 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
1340 my @fill = $self->_data_fill($dataindex, \@patchbox)
1342 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1343 ymax=>$ypos + $patchsize, @fill);
1344 if ($self->{_style}{legend}{patchborder}) {
1345 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1346 ymax=>$ypos + $patchsize,
1347 color=>$patchborder);
1349 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
1352 my $step = $patchsize + $gap;
1353 if ($minrowsize < $sizes[$dataindex][3]) {
1354 $ypos += $sizes[$dataindex][3];
1357 $ypos += $minrowsize;
1361 if ($self->{_style}{legend}{border}) {
1362 my $border_color = $self->_get_color('legend.border')
1364 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1365 color=>$border_color);
1367 $self->_remove_box($chart_box, \@box);
1372 my ($self, $img, $chart_box) = @_;
1374 my $title = $self->{_style}{title}{text};
1375 my @box = $self->_text_bbox($title, 'title');
1378 $self->_align_box(\@box, $chart_box, 'title');
1379 my %text_info = $self->_text_style('title');
1380 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
1381 $self->_remove_box($chart_box, \@box);
1386 my ($self, $box) = @_;
1388 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
1389 return $box->[3] - $box->[1];
1392 return $box->[2] - $box->[0];
1398 Returns a list of style fields that are stored as composites, and
1399 should be merged instead of just being replaced.
1404 qw(title legend text label dropshadow outline callout);
1407 sub _filter_region {
1408 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
1410 unless (ref $filter) {
1412 $filter = $self->_get_thing($name)
1415 or return $self->_error("no type for filter $name");
1418 $left > 0 or $left = 0;
1419 $top > 0 or $top = 0;
1421 # newer versions of Imager let you work on just part of an image
1422 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
1423 my $masked = $img->masked(left=>$left, top=>$top,
1424 right=>$right, bottom=>$bottom);
1425 $masked->filter(%$filter);
1428 # for older versions of Imager
1429 my $subset = $img->crop(left=>$left, top=>$top,
1430 right=>$right, bottom=>$bottom);
1431 $subset->filter(%$filter);
1432 $img->paste(left=>$left, top=>$top, img=>$subset);
1443 Imager::Graph::Pie(3), Imager(3), perl(1).
1447 Tony Cook <tony@develop-help.com>
1451 Imager::Graph is licensed under the same terms as perl itself.
1455 Addi for producing a cool imaging module. :)