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=> \@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()
27 use vars qw($VERSION);
28 use Imager qw(:handy);
33 # the maximum recursion depth in determining a color, fill or number
34 use constant MAX_DEPTH => 10;
36 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
40 This is a simple constructor. No parameters required.
50 Returns an error message. Only value if the draw() method returns false.
60 Creates a new image, draws the chart onto that image and returns it.
62 Typically you will need to supply a C<data> parameter in the format
63 required by that particular graph, and if your graph will use any
64 text, a C<font> parameter
66 You can also supply many different parameters which control the way
67 the graph looks. These are supplied as keyword, value pairs, where
68 the value can be a hashref containing sub values.
70 The C<style> parameter will selects a basic color set, and possibly
71 sets other related parameters. See L</"STYLES">.
73 my $font = Imager::Font->new(file => 'ImUgly.ttf');
74 my $img = $chart->draw(
78 text => "Hello, World!",
84 When referring to a single sub-value this documentation will refer to
85 'title.color' rather than 'the color element of title'.
87 Returns the graph image on success, or false on failure.
93 The currently defined styles are:
99 a light grey background with no outlines. Uses primary colors for the
104 a light red background with no outlines. Uses primary colors for the
107 Graphs drawn using this style should save well as a gif, even though
108 some graphs may perform a slight blur.
110 This was the default style, but the red was too loud.
114 designed for monochrome output, such as most laser printers, this uses
115 hatched fills for the data, and no colors. The returned image is a
116 one channel image (which can be overridden with the C<channels>
119 You can also override the colors used by all components for background
120 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
121 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
122 else will be drawn in red. Another use might be to set a transparent
123 background, by supplying C<<bg=>'00000000', channels=>4>>.
125 This style outlines the legend if present and outlines the hashed fills.
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
135 This is the default style.
139 also designed as a "pretty" style this uses radial fountain fills for
140 the data and a linear blue to green fill for the background.
146 Each graph type has a number of features. These are used to add
147 various items that are displayed in the graph area. Some common
154 adds a box containing boxes filled with the data filess, with
155 the labels provided to the draw method. The legend will only be
156 displayed if both the legend feature is enabled and labels are
161 labels each data fill, usually by including text inside the data fill.
162 If the text does not fit in the fill, they could be displayed in some
163 other form, eg. as callouts in a pie graph. There usually isn't much
164 point in including both labels and a legend.
168 a simple drop shadow is shown behind some of the graph elements.
172 Each graph also has features specific to that graph.
174 =head1 COMMON PARAMETERS
176 When referring to a single sub-value this documentation will refer to
177 'title.color' rather than 'the color element of title'.
179 Normally, except for the font parameter, these are controlled by
180 styles, but these are the style parameters I'd mostly likely expect
187 the Imager font object used to draw text on the chart.
191 the background fill for the graph. Default depends on the style.
195 the base size of the graph image. Default: 256
199 the width of the graph image. Default: 1.5 * size (384)
203 the height of the graph image. Default: size (256)
207 the number of channels in the image. Default: 3 (the 'mono' style
212 the color used for drawing lines, such as outlines or callouts.
213 Default depends on the current style. Set to undef to remove the
214 outline from a style.
218 the text used for a graph title. Default: no title. Note: this is
219 the same as the title=>{ text => ... } field.
225 horizontal alignment of the title in the graph, one of 'left',
226 'center' or 'right'. Default: center
230 vertical alignment of the title, one of 'top', 'center' or 'right'.
231 Default: top. It's probably a bad idea to set this to 'center' unless
232 you have a very short title.
238 This contains basic defaults used in drawing text.
244 the default color used for all text, defaults to the fg color.
248 the base size used for text, also used to scale many graph elements.
257 In most cases you will want to use just the styles, but you may want
258 to exert more control over the way your chart looks. This section
259 describes the options you can use to control the way your chart looks.
261 Hopefully you don't need to read this.
267 The background of the graph.
273 Used to define basic background and foreground colors for the graph.
274 The bg color may be used for the background of the graph, and is used
275 as a default for the background of hatcheed fills. The fg is used as
276 the default for line and text colors.
280 The default font used by the graph. Normally you should supply this
281 if your graph as any text.
285 The default line color.
289 defaults for drawing text. Other textual graph elements will inherit
290 or modify these values.
296 default text color, defaults to the I<fg> color.
300 default text size. Default: 14. This is used to scale many graph
301 elements, including padding and leader sizes. Other text elements
302 will either use or scale this value.
306 default font object. Inherited from I<font>, which should have been
307 supplied by the caller.
313 If you supply a scalar value for this element, it will be stored in
316 Defines the text, font and layout information for the title.
322 The color of the title, inherited from I<text.color>.
326 The font object used for the title, inherited from I<text.font>.
330 size of the title text. Default: double I<text.size>
336 The horizontal and vertical alignment of the title.
342 defines attributes of the graph legend, if present.
352 text attributes for the labels used in the legend.
356 the width and height of the color patch in the legend. Defaults to
357 90% of the legend text size.
361 the minimum gap between patches in pixels. Defaults to 30% of the
366 the color of the border drawn around each patch. Inherited from I<line>.
372 the horizontal and vertical alignment of the legend within the graph.
373 Defaults to 'right' and 'top'.
377 the gap between the legend patches and text and the outside of it's
378 box, or to the legend border, if any.
382 the gap between the border and the outside of the legend's box. This
383 is only used if the I<legend.border> attribute is defined.
387 the background fill for the legend. Default: none
391 the border color of the legend. Default: none (no border is drawn
396 The orientation of the legend. If this is C<vertical> the the patches
397 and labels are stacked on top of each other. If this is C<horizontal>
398 the patchs and labels are word wrapped across the image. Default:
403 For example to create a horizontal legend with borderless patches,
404 darker than the background, you might do:
406 my $im = $chart->draw
410 patchborder => undef,
411 orientation => 'horizontal',
412 fill => { solid => Imager::Color->new(0, 0, 0, 32), }
418 defines attributes for graph callouts, if any are present. eg. if the
419 pie graph cannot fit the label into the pie graph segement it will
420 present it as a callout.
430 the text attributes of the callout label. Inherited from I<text>.
434 the color of the callout lines. Inherited from I<line>
440 the length of the leader on the inside and the outside of the fill,
441 usually at some angle. Both default to the size of the callout text.
445 the length of the horizontal portion of the leader. Default:
450 the gap between the callout leader and the callout text. Defaults to
451 30% of the text callout size.
457 defines attributes for labels drawn into the data areas of a graph.
467 The text attributes of the labels. Inherited from I<text>.
473 the attributes of the graph's drop shadow
479 the fill used for the drop shadow. Default: '404040' (dark gray)
483 the offset of the drop shadow. A convenience value inherited by offx
484 and offy. Default: 40% of I<text.size>.
490 the horizontal and vertical offsets of the drop shadow. Both
491 inherited from I<dropshadow.off>.
495 the filter description passed to Imager's filter method to blur the
496 drop shadow. Default: an 11 element convolution filter.
502 describes the lines drawn around filled data areas, such as the
503 segments of a pie chart.
509 the line color of the outlines, inherited from I<line>.
515 a reference to an array containing fills for each data item.
517 You can mix fill types, ie. using a simple color for the first item, a
518 hatched fill for the second and a fountain fill for the next.
522 =head1 HOW VALUES WORK
524 Internally rather than specifying literal color, fill, or font objects
525 or literal sizes for each element, Imager::Graph uses a number of
526 special values to inherit or modify values taken from other graph
529 =head2 Specifying colors
531 You can specify colors by either supplying an Imager::Color object, by
532 supplying lookup of another color, or by supplying a single value that
533 Imager::Color::new can use as an initializer. The most obvious is
534 just a 6 or 8 digit hex value representing the red, green, blue and
535 optionally alpha channels of the image.
537 You can lookup another color by using the lookup() "function", for
538 example if you give a color as "lookup(fg)" then Imager::Graph will
539 look for the fg element in the current style (or as overridden by
540 you.) This is used internally by Imager::Graph to set up the
541 relationships between the colors of various elements, for example the
542 default style information contains:
549 color=>'lookup(text.color)',
553 So by setting the I<fg> color, you also set the default text color,
554 since each text element uses lookup(text.color) as its value.
556 =head2 Specifying fills
558 Fills can be used for the graph background color, the background color
559 for the legend block and for the fills used for each data element.
561 You can specify a fill as a L<color value|Specifying colors> or as a
562 general fill, see L<Imager::Fill> for details.
564 You don't need (or usually want) to call Imager::Fill::new yourself,
565 since the various fill functions will call it for you, and
566 Imager::Graph provides some hooks to make them more useful.
572 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
573 Imager::Graph will supply the current graph fg and bg colors.
577 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
578 and yb_ratio parameters, and they will be scaled in the fill area to
579 define the fountain fills xa, ya, xb and yb parameters.
583 As with colors, you can use lookup(name) or lookup(name1.name2) to
584 have one element to inherit the fill of another.
586 Imager::Graph defaults the fill combine value to C<'normal'>. This
587 doesn't apply to simple color fills.
589 =head2 Specifying numbers
591 You can specify various numbers, usually representing the size of
592 something, commonly text, but sometimes the length of a line or the
595 You can use the same lookup mechanism as with colors and fills, but
596 you can also scale values. For example, 'scale(0.5,text.size)' will
597 return half the size of the normal text size.
599 As with colors, this is used internally to scale graph elements based
600 on the base text size. If you change the base text size then other
601 graph elements will scale as well.
603 =head2 Specifying other elements
605 Other elements, such as fonts, or parameters for a filter, can also
606 use the lookup(name) mechanism.
608 =head1 INTERNAL METHODS
610 Only useful if you need to fix bugs, add features or create a new
622 color => 'lookup(fg)',
623 font => 'lookup(font)',
627 color => 'lookup(text.color)',
628 font => 'lookup(text.font)',
631 size => 'scale(text.size,2.0)',
634 color => 'lookup(text.color)',
635 font => 'lookup(text.font)',
636 size => 'lookup(text.size)',
637 patchsize => 'scale(legend.size,0.9)',
638 patchgap => 'scale(legend.patchsize,0.3)',
639 patchborder => 'lookup(line)',
642 padding => 'scale(legend.size,0.3)',
643 outsidepadding => 'scale(legend.padding,0.4)',
646 color => 'lookup(text.color)',
647 font => 'lookup(text.font)',
648 size => 'lookup(text.size)',
649 line => 'lookup(line)',
650 inside => 'lookup(callout.size)',
651 outside => 'lookup(callout.size)',
652 leadlen => 'scale(0.8,callout.size)',
653 gap => 'scale(callout.size,0.3)',
656 font => 'lookup(text.font)',
657 size => 'lookup(text.size)',
658 color => 'lookup(text.color)',
659 hpad => 'lookup(label.pad)',
660 vpad => 'lookup(label.pad)',
661 pad => 'scale(label.size,0.2)',
662 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
663 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
666 fill => { solid => Imager::Color->new(0, 0, 0, 96) },
667 off => 'scale(0.4,text.size)',
668 offx => 'lookup(dropshadow.off)',
669 offy => 'lookup(dropshadow.off)',
670 filter => { type=>'conv',
671 # this needs a fairly heavy blur
672 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
673 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
676 line =>'lookup(line)',
679 width=>'scale(1.5,size)',
680 height=>'lookup(size)',
683 =item _error($message)
685 Sets the error field of the object and returns an empty list or undef,
686 depending on context. Should be used for error handling, since it may
687 provide some user hooks at some point.
689 The intended usage is:
692 or return $self->_error("error description");
694 You should almost always return the result of _error() or return
695 immediately afterwards.
700 my ($self, $error) = @_;
702 $self->{_errstr} = $error;
710 Returns the style defaults, such as the relationships between line
711 color and text color.
713 Intended to be over-ridden by base classes to provide graph specific
722 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
723 my $def_style = 'fount_lin';
731 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
737 #patchborder=>'000000'
744 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
750 patchborder=>'000000'
763 { hatch=>'stipple3' },
764 { hatch=>'stipple2' },
769 features=>{ outline=>1 },
778 { fountain=>'linear',
779 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
780 segments => Imager::Fountain->simple(positions=>[0, 1],
781 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
783 { fountain=>'linear',
784 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
785 segments => Imager::Fountain->simple(positions=>[0, 1],
786 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
788 { fountain=>'linear',
789 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
790 segments => Imager::Fountain->simple(positions=>[0, 1],
791 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
793 { fountain=>'linear',
794 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
795 segments => Imager::Fountain->simple(positions=>[0, 1],
796 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
798 { fountain=>'linear',
799 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
800 segments => Imager::Fountain->simple(positions=>[0, 1],
801 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
803 { fountain=>'linear',
804 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
805 segments => Imager::Fountain->simple(positions=>[0, 1],
806 colors=>[ NC('FFC0FF'), 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') ]) },
817 features=>{ dropshadow=>1 },
823 { fountain=>'radial',
824 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
825 segments => Imager::Fountain->simple(positions=>[0, 1],
826 colors=>[ NC('FF8080'), NC('FF0000') ]),
828 { fountain=>'radial',
829 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
830 segments => Imager::Fountain->simple(positions=>[0, 1],
831 colors=>[ NC('80FF80'), NC('00FF00') ]),
833 { fountain=>'radial',
834 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
835 segments => Imager::Fountain->simple(positions=>[0, 1],
836 colors=>[ NC('808080FF'), NC('0000FF') ]),
838 { fountain=>'radial',
839 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
840 segments => Imager::Fountain->simple(positions=>[0, 1],
841 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
843 { fountain=>'radial',
844 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
845 segments => Imager::Fountain->simple(positions=>[0, 1],
846 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
848 { fountain=>'radial',
849 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
850 segments => Imager::Fountain->simple(positions=>[0, 1],
851 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
854 back=>{ fountain=>'linear',
855 xa_ratio=>0, ya_ratio=>0,
856 xb_ratio=>1.0, yb_ratio=>1.0,
857 segments=>Imager::Fountain->simple
859 colors=>[ NC('6060FF'), NC('60FF60') ]) },
865 =item $self->_style_setup(\%opts)
867 Uses the values from %opts to build a customized hash describing the
868 way the graph should be drawn.
873 my ($self, $opts) = @_;
874 my $style_defs = $self->_style_defs;
876 $style = $styles{$opts->{style}} if $opts->{style};
877 $style ||= $styles{$def_style};
879 my @search_list = ( $style_defs, $style, $opts);
882 my @composite = $self->_composite();
884 @composite{@composite} = @composite;
886 for my $src (@search_list) {
887 for my $key (keys %$src) {
888 if ($composite{$key}) {
889 $work{$key} = {} unless exists $work{$key};
890 if (ref $src->{$key}) {
891 # some keys have sub values, especially text
892 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
895 # assume it's the text for a title or something
896 $work{$key}{text} = $src->{$key};
900 $work{$key} = $src->{$key};
905 # features are handled specially
906 $work{features} = {};
907 for my $src (@search_list) {
908 if ($src->{features}) {
909 if (ref $src->{features}) {
910 if (ref($src->{features}) =~ /ARRAY/) {
911 # just set those features
912 for my $feature (@{$src->{features}}) {
913 $work{features}{$feature} = 1;
916 elsif (ref($src->{features}) =~ /HASH/) {
917 if ($src->{features}{reset}) {
918 $work{features} = {}; # only the ones the user specifies
920 @{$work{features}}{keys %{$src->{features}}} =
921 values(%{$src->{features}});
925 # just set that single feature
926 $work{features}{$src->{features}} = 1;
931 #print Dumper(\%work);
933 $self->{_style} = \%work;
936 =item $self->_get_thing($name)
938 Retrieve some general 'thing'.
940 Supports the 'lookup(foo)' mechanism.
942 Returns an empty list on failure.
947 my ($self, $name, @depth) = @_;
951 if ($name =~ /^(\w+)\.(\w+)$/) {
952 $what = $self->{_style}{$1}{$2};
955 $what = $self->{_style}{$name};
962 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
964 or return $self->_error("too many levels of recursion in lookup(@depth)");
965 return $self->_get_thing($1, @depth);
972 =item $self->_get_number($name)
974 Retrieves a number from the style. The value in the style can be the
975 number, or one of two functions:
979 =item lookup(newname)
981 Recursively looks up I<newname> in the style.
983 =item scale(value1,value2)
985 Each value can be a number or a name. Names are recursively looked up
986 in the style and the product is returned.
993 my ($self, $name, @depth) = @_;
997 if ($name =~ /^(\w+)\.(\w+)$/) {
998 $what = $self->{_style}{$1}{$2};
1001 $what = $self->{_style}{$name};
1004 return $self->_error("$name is undef (@depth)");
1007 if ($what =~ /CODE/) {
1008 $what = $what->($self, $name);
1012 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1014 or return $self->_error("too many levels of recursion in lookup (@depth)");
1015 return $self->_get_number($1, @depth);
1017 elsif ($what =~ /^scale\(
1018 ((?:[a-z][\w.]*)|$NUM_RE)
1020 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1021 my ($left, $right) = ($1, $2);
1022 unless ($left =~ /^$NUM_RE$/) {
1024 or return $self->_error("too many levels of recursion in scale (@depth)");
1025 $left = $self->_get_number($left, @depth);
1027 unless ($right =~ /^$NUM_RE$/) {
1029 or return $self->_error("too many levels of recursion in scale (@depth)");
1030 $right = $self->_get_number($right, @depth);
1032 return $left * $right;
1040 =item $self->_get_integer($name)
1042 Retrieves an integer from the style. This is a simple wrapper around
1043 _get_number() that rounds the result to an integer.
1045 Returns an empty list on failure.
1050 my ($self, $name, @depth) = @_;
1052 my $number = $self->_get_number($name, @depth)
1055 return sprintf("%.0f", $number);
1058 =item _get_color($name)
1060 Returns a color object of the given name from the style hash.
1062 Uses Imager::Color->new to translate normal scalars into color objects.
1064 Allows the lookup(name) mechanism.
1066 Returns an empty list on failure.
1071 my ($self, $name, @depth) = @_;
1073 push(@depth, $name);
1075 if ($name =~ /^(\w+)\.(\w+)$/) {
1076 $what = $self->{_style}{$1}{$2};
1079 $what = $self->{_style}{$name};
1083 or return $self->_error("$name was undefined (@depth)");
1085 unless (ref $what) {
1086 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1087 @depth < MAX_DEPTH or
1088 return $self->_error("too many levels of recursion in lookup (@depth)");
1090 return $self->_get_color($1, @depth);
1092 $what = Imager::Color->new($what);
1098 =item _translate_fill($what, $box)
1100 Given the value of a fill, either attempts to convert it into a fill
1101 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1102 parameters }>>), or to lookup another fill that is referred to with
1103 the 'lookup(name)' mechanism.
1105 This function does the fg and bg initialization for hatched fills, and
1106 translation of *_ratio for fountain fills (using the $box parameter).
1108 Returns an empty list on failure.
1112 sub _translate_fill {
1113 my ($self, $what, $box, @depth) = @_;
1116 if (UNIVERSAL::isa($what, "Imager::Color")) {
1117 return ( color=>Imager::Color->new($what), filled=>1 );
1121 # default to normal combine mode
1122 my %work = ( combine => 'normal', %$what );
1123 if ($what->{hatch}) {
1125 $work{fg} = $self->_get_color('fg')
1129 $work{bg} = $self->_get_color('bg')
1132 return ( fill=>\%work );
1134 elsif ($what->{fountain}) {
1135 for my $key (qw(xa ya xb yb)) {
1136 if (exists $work{"${key}_ratio"}) {
1138 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1139 * ($box->[2] - $box->[0]);
1142 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1143 * ($box->[3] - $box->[1]);
1147 return ( fill=>\%work );
1150 return ( fill=> \%work );
1155 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1156 return $self->_get_fill($1, $box, @depth);
1159 # assumed to be an Imager::Color single value
1160 return ( color=>Imager::Color->new($what), filled=>1 );
1165 =item _data_fill($index, $box)
1167 Retrieves the fill parameters for a data area fill.
1172 my ($self, $index, $box) = @_;
1174 my $fills = $self->{_style}{fills};
1175 return $self->_translate_fill($fills->[$index % @$fills], $box,
1179 =item _get_fill($index, $box)
1181 Retrieves fill parameters for a named fill.
1186 my ($self, $name, $box, @depth) = @_;
1188 push(@depth, $name);
1190 if ($name =~ /^(\w+)\.(\w+)$/) {
1191 $what = $self->{_style}{$1}{$2};
1194 $what = $self->{_style}{$name};
1198 or return $self->_error("no fill $name found");
1200 return $self->_translate_fill($what, $box, @depth);
1205 Builds the image object for the graph and fills it with the background
1213 my $width = $self->_get_number('width') || 256;
1214 my $height = $self->_get_number('height') || 256;
1215 my $channels = $self->{_style}{channels};
1219 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1221 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1226 =item _text_style($name)
1228 Returns parameters suitable for calls to Imager::Font's bounding_box()
1229 and draw() methods intended for use in defining text styles.
1231 Returns an empty list on failure.
1236 my ($self, $name) = @_;
1240 if ($self->{_style}{$name}) {
1241 %work = %{$self->{_style}{$name}};
1244 %work = %{$self->{_style}{text}};
1247 or return $self->_error("$name has no font parameter");
1249 $work{font} = $self->_get_thing("$name.font")
1250 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1251 UNIVERSAL::isa($work{font}, "Imager::Font")
1252 or return $self->_error("$name.font is not a font");
1253 if ($work{color} && !ref $work{color}) {
1254 $work{color} = $self->_get_color("$name.color")
1257 $work{size} = $self->_get_number("$name.size");
1258 $work{sizew} = $self->_get_number("$name.sizew")
1264 =item _text_bbox($text, $name)
1266 Returns a bounding box for the specified $text as styled by $name.
1268 Returns an empty list on failure.
1273 my ($self, $text, $name) = @_;
1275 my %text_info = $self->_text_style($name)
1278 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1285 my ($self, $box, $chart_box, $name) = @_;
1287 my $halign = $self->{_style}{$name}{halign}
1288 or $self->_error("no halign for $name");
1289 my $valign = $self->{_style}{$name}{valign};
1291 if ($halign eq 'right') {
1292 $box->[0] += $chart_box->[2] - $box->[2];
1294 elsif ($halign eq 'left') {
1295 $box->[0] = $chart_box->[0];
1297 elsif ($halign eq 'center' || $halign eq 'centre') {
1298 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1301 return $self->_error("invalid halign $halign for $name");
1304 if ($valign eq 'top') {
1305 $box->[1] = $chart_box->[1];
1307 elsif ($valign eq 'bottom') {
1308 $box->[1] = $chart_box->[3] - $box->[3];
1310 elsif ($valign eq 'center' || $valign eq 'centre') {
1311 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1314 return $self->_error("invalid valign $valign for $name");
1316 $box->[2] += $box->[0];
1317 $box->[3] += $box->[1];
1321 my ($self, $chart_box, $object_box) = @_;
1325 if ($object_box->[0] - $chart_box->[0]
1326 < $chart_box->[2] - $object_box->[2]) {
1327 $areax = ($object_box->[2] - $chart_box->[0])
1328 * ($chart_box->[3] - $chart_box->[1]);
1331 $areax = ($chart_box->[2] - $object_box->[0])
1332 * ($chart_box->[3] - $chart_box->[1]);
1335 if ($object_box->[1] - $chart_box->[1]
1336 < $chart_box->[3] - $object_box->[3]) {
1337 $areay = ($object_box->[3] - $chart_box->[1])
1338 * ($chart_box->[2] - $chart_box->[0]);
1341 $areay = ($chart_box->[3] - $object_box->[1])
1342 * ($chart_box->[2] - $chart_box->[0]);
1345 if ($areay < $areax) {
1346 if ($object_box->[1] - $chart_box->[1]
1347 < $chart_box->[3] - $object_box->[3]) {
1348 $chart_box->[1] = $object_box->[3];
1351 $chart_box->[3] = $object_box->[1];
1355 if ($object_box->[0] - $chart_box->[0]
1356 < $chart_box->[2] - $object_box->[2]) {
1357 $chart_box->[0] = $object_box->[2];
1360 $chart_box->[2] = $object_box->[0];
1366 my ($self, $img, $labels, $chart_box) = @_;
1368 my $orient = $self->_get_thing('legend.orientation');
1369 defined $orient or $orient = 'vertical';
1371 if ($orient eq 'vertical') {
1372 return $self->_draw_legend_vertical($img, $labels, $chart_box);
1374 elsif ($orient eq 'horizontal') {
1375 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
1378 return $self->_error("Unknown legend.orientation $orient");
1382 sub _draw_legend_horizontal {
1383 my ($self, $img, $labels, $chart_box) = @_;
1385 defined(my $padding = $self->_get_integer('legend.padding'))
1387 my $patchsize = $self->_get_integer('legend.patchsize')
1389 defined(my $gap = $self->_get_integer('legend.patchgap'))
1392 my $minrowsize = $patchsize + $gap;
1393 my ($width, $height) = (0,0);
1394 my $row_height = $minrowsize;
1398 for my $label (@$labels) {
1399 my @text_box = $self->_text_bbox($label, 'legend')
1401 push(@sizes, \@text_box);
1402 my $entry_width = $patchsize + $gap + $text_box[2];
1404 # never re-wrap the first entry
1405 push @offsets, [ 0, $height ];
1408 if ($pos + $gap + $entry_width > $chart_box->[2]) {
1410 $height += $row_height;
1412 push @offsets, [ $pos, $height ];
1414 my $entry_right = $pos + $entry_width;
1415 $pos += $gap + $entry_width;
1416 $entry_right > $width and $width = $entry_right;
1417 if ($text_box[3] > $row_height) {
1418 $row_height = $text_box[3];
1421 $height += $row_height;
1422 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
1423 my $outsidepadding = 0;
1424 if ($self->{_style}{legend}{border}) {
1425 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1427 $box[2] += 2 * $outsidepadding;
1428 $box[3] += 2 * $outsidepadding;
1430 $self->_align_box(\@box, $chart_box, 'legend')
1432 if ($self->{_style}{legend}{fill}) {
1433 $img->box(xmin=>$box[0]+$outsidepadding,
1434 ymin=>$box[1]+$outsidepadding,
1435 xmax=>$box[2]-$outsidepadding,
1436 ymax=>$box[3]-$outsidepadding,
1437 $self->_get_fill('legend.fill', \@box));
1439 $box[0] += $outsidepadding;
1440 $box[1] += $outsidepadding;
1441 $box[2] -= $outsidepadding;
1442 $box[3] -= $outsidepadding;
1443 my %text_info = $self->_text_style('legend')
1446 if ($self->{_style}{legend}{patchborder}) {
1447 $patchborder = $self->_get_color('legend.patchborder')
1452 for my $label (@$labels) {
1453 my ($left, $top) = @{$offsets[$dataindex]};
1454 $left += $box[0] + $padding;
1455 $top += $box[1] + $padding;
1456 my $textpos = $left + $patchsize + $gap;
1457 my @patchbox = ( $left, $top,
1458 $left + $patchsize, $top + $patchsize );
1459 my @fill = $self->_data_fill($dataindex, \@patchbox)
1461 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1462 ymax=>$top + $patchsize, @fill);
1463 if ($self->{_style}{legend}{patchborder}) {
1464 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1465 ymax=>$top + $patchsize,
1466 color=>$patchborder);
1468 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
1473 if ($self->{_style}{legend}{border}) {
1474 my $border_color = $self->_get_color('legend.border')
1476 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1477 color=>$border_color);
1479 $self->_remove_box($chart_box, \@box);
1483 sub _draw_legend_vertical {
1484 my ($self, $img, $labels, $chart_box) = @_;
1486 defined(my $padding = $self->_get_integer('legend.padding'))
1488 my $patchsize = $self->_get_integer('legend.patchsize')
1490 defined(my $gap = $self->_get_integer('legend.patchgap'))
1492 my $minrowsize = $patchsize + $gap;
1493 my ($width, $height) = (0,0);
1495 for my $label (@$labels) {
1496 my @box = $self->_text_bbox($label, 'legend')
1498 push(@sizes, \@box);
1499 $width = $box[2] if $box[2] > $width;
1500 if ($minrowsize > $box[3]) {
1501 $height += $minrowsize;
1508 $width + $patchsize + $padding * 2 + $gap,
1509 $height + $padding * 2 - $gap);
1510 my $outsidepadding = 0;
1511 if ($self->{_style}{legend}{border}) {
1512 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1514 $box[2] += 2 * $outsidepadding;
1515 $box[3] += 2 * $outsidepadding;
1517 $self->_align_box(\@box, $chart_box, 'legend')
1519 if ($self->{_style}{legend}{fill}) {
1520 $img->box(xmin=>$box[0]+$outsidepadding,
1521 ymin=>$box[1]+$outsidepadding,
1522 xmax=>$box[2]-$outsidepadding,
1523 ymax=>$box[3]-$outsidepadding,
1524 $self->_get_fill('legend.fill', \@box));
1526 $box[0] += $outsidepadding;
1527 $box[1] += $outsidepadding;
1528 $box[2] -= $outsidepadding;
1529 $box[3] -= $outsidepadding;
1530 my $ypos = $box[1] + $padding;
1531 my $patchpos = $box[0]+$padding;
1532 my $textpos = $patchpos + $patchsize + $gap;
1533 my %text_info = $self->_text_style('legend')
1536 if ($self->{_style}{legend}{patchborder}) {
1537 $patchborder = $self->_get_color('legend.patchborder')
1541 for my $label (@$labels) {
1542 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
1543 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
1544 my @fill = $self->_data_fill($dataindex, \@patchbox)
1546 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1547 ymax=>$ypos + $patchsize, @fill);
1548 if ($self->{_style}{legend}{patchborder}) {
1549 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1550 ymax=>$ypos + $patchsize,
1551 color=>$patchborder);
1553 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
1556 my $step = $patchsize + $gap;
1557 if ($minrowsize < $sizes[$dataindex][3]) {
1558 $ypos += $sizes[$dataindex][3];
1561 $ypos += $minrowsize;
1565 if ($self->{_style}{legend}{border}) {
1566 my $border_color = $self->_get_color('legend.border')
1568 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1569 color=>$border_color);
1571 $self->_remove_box($chart_box, \@box);
1576 my ($self, $img, $chart_box) = @_;
1578 my $title = $self->{_style}{title}{text};
1579 my @box = $self->_text_bbox($title, 'title')
1583 $self->_align_box(\@box, $chart_box, 'title');
1584 my %text_info = $self->_text_style('title')
1586 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
1587 $self->_remove_box($chart_box, \@box);
1592 my ($self, $box) = @_;
1594 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
1595 return $box->[3] - $box->[1];
1598 return $box->[2] - $box->[0];
1604 Returns a list of style fields that are stored as composites, and
1605 should be merged instead of just being replaced.
1610 qw(title legend text label dropshadow outline callout);
1613 sub _filter_region {
1614 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
1616 unless (ref $filter) {
1618 $filter = $self->_get_thing($name)
1621 or return $self->_error("no type for filter $name");
1624 $left > 0 or $left = 0;
1625 $top > 0 or $top = 0;
1627 # newer versions of Imager let you work on just part of an image
1628 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
1629 my $masked = $img->masked(left=>$left, top=>$top,
1630 right=>$right, bottom=>$bottom);
1631 $masked->filter(%$filter);
1634 # for older versions of Imager
1635 my $subset = $img->crop(left=>$left, top=>$top,
1636 right=>$right, bottom=>$bottom);
1637 $subset->filter(%$filter);
1638 $img->paste(left=>$left, top=>$top, img=>$subset);
1649 Imager::Graph::Pie(3), Imager(3), perl(1).
1653 Tony Cook <tony@develop-help.com>
1657 Imager::Graph is licensed under the same terms as perl itself.
1661 Addi for producing a cool imaging module. :)