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.
48 =item setGraphSize($size)
50 Sets the size of the graph (in pixels) within the image. The size of the image defaults to 1.5 * $graph_size.
55 $_[0]->{'graph_size'} = $_[1];
59 return $_[0]->{'graph_size'};
62 =item setImageWidth($width)
64 Sets the width of the image in pixels.
69 $_[0]->{'image_width'} = $_[1];
73 return $_[0]->{'image_width'};
76 =item setImageHeight($height)
78 Sets the height of the image in pixels.
83 $_[0]->{'image_height'} = $_[1];
87 return $_[0]->{'image_height'};
90 =item addDataSeries([8, 6, 7, 5, 3, 0, 9], 'Series Name');
92 Adds a data series to the graph. For L<Imager::Graph::Pie>, only one data series can be added.
99 my $series_name = shift;
101 my $graph_data = $self->{'graph_data'} || [];
103 push @$graph_data, { data => $data_ref, series_name => $series_name };
105 $self->{'graph_data'} = $graph_data;
110 my ($self, $opts) = @_;
112 # return the data supplied to draw() if any.
114 # one or multiple series?
115 my $data = $opts->{data};
116 if (@$data && ref $data->[0] && ref $data->[0] =~ /ARRAY/) {
120 return [ { data => $data } ];
124 return $self->{'graph_data'};
127 =item setLabels(['label1', 'label2' ... ])
129 Labels the specific data points. For line/bar graphs, this is the x-axis. For pie graphs, it is the label for the wedges.
134 $_[0]->{'labels'} = $_[1];
138 my ($self, $opts) = @_;
141 and return $opts->{labels};
143 return $_[0]->{'labels'}
146 =item setTitle($title)
148 Sets the title of the graph. Requires setting a font.
153 $_[0]->{'image_title'} = $_[1];
157 return $_[0]->{'image_title'};
160 =item setFont(Imager::Font->new())
162 Sets the font to use for text. Takes an L<Imager::Font> object.
167 $_[0]->{'font'} = $_[1];
171 return $_[0]->{'font'};
174 =item setStyle($style_name)
176 Sets the style to be used for the graph. Imager::Graph comes with several pre-defined styles: fount_lin (default), fount_rad, mono, primary_red, and primary.
181 $_[0]->{'style'} = $_[1];
185 my ($self, $opts) = @_;
188 and return $opts->{style};
190 return $self->{'style'};
195 Returns an error message. Only value if the draw() method returns false.
205 Creates a new image, draws the chart onto that image and returns it.
207 Typically you will need to supply a C<data> parameter in the format
208 required by that particular graph, and if your graph will use any
209 text, a C<font> parameter
211 You can also supply many different parameters which control the way
212 the graph looks. These are supplied as keyword, value pairs, where
213 the value can be a hashref containing sub values.
215 The C<style> parameter will selects a basic color set, and possibly
216 sets other related parameters. See L</"STYLES">.
218 my $font = Imager::Font->new(file => 'ImUgly.ttf');
219 my $img = $chart->draw(
223 text => "Hello, World!",
229 When referring to a single sub-value this documentation will refer to
230 'title.color' rather than 'the color element of title'.
232 Returns the graph image on success, or false on failure.
238 The currently defined styles are:
244 a light grey background with no outlines. Uses primary colors for the
249 a light red background with no outlines. Uses primary colors for the
252 Graphs drawn using this style should save well as a gif, even though
253 some graphs may perform a slight blur.
255 This was the default style, but the red was too loud.
259 designed for monochrome output, such as most laser printers, this uses
260 hatched fills for the data, and no colors. The returned image is a
261 one channel image (which can be overridden with the C<channels>
264 You can also override the colors used by all components for background
265 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
266 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
267 else will be drawn in red. Another use might be to set a transparent
268 background, by supplying C<<bg=>'00000000', channels=>4>>.
270 This style outlines the legend if present and outlines the hashed fills.
274 designed as a "pretty" style this uses linear fountain fills for the
275 background and data fills, and adds a drop shadow.
277 You can override the value used for text and outlines by setting the
280 This is the default style.
284 also designed as a "pretty" style this uses radial fountain fills for
285 the data and a linear blue to green fill for the background.
291 Each graph type has a number of features. These are used to add
292 various items that are displayed in the graph area. Some common
299 adds a box containing boxes filled with the data filess, with
300 the labels provided to the draw method. The legend will only be
301 displayed if both the legend feature is enabled and labels are
306 labels each data fill, usually by including text inside the data fill.
307 If the text does not fit in the fill, they could be displayed in some
308 other form, eg. as callouts in a pie graph. There usually isn't much
309 point in including both labels and a legend.
313 a simple drop shadow is shown behind some of the graph elements.
317 Each graph also has features specific to that graph.
319 =head1 COMMON PARAMETERS
321 When referring to a single sub-value this documentation will refer to
322 'title.color' rather than 'the color element of title'.
324 Normally, except for the font parameter, these are controlled by
325 styles, but these are the style parameters I'd mostly likely expect
332 the Imager font object used to draw text on the chart.
336 the background fill for the graph. Default depends on the style.
340 the base size of the graph image. Default: 256
344 the width of the graph image. Default: 1.5 * size (384)
348 the height of the graph image. Default: size (256)
352 the number of channels in the image. Default: 3 (the 'mono' style
357 the color used for drawing lines, such as outlines or callouts.
358 Default depends on the current style. Set to undef to remove the
359 outline from a style.
363 the text used for a graph title. Default: no title. Note: this is
364 the same as the title=>{ text => ... } field.
370 horizontal alignment of the title in the graph, one of 'left',
371 'center' or 'right'. Default: center
375 vertical alignment of the title, one of 'top', 'center' or 'right'.
376 Default: top. It's probably a bad idea to set this to 'center' unless
377 you have a very short title.
383 This contains basic defaults used in drawing text.
389 the default color used for all text, defaults to the fg color.
393 the base size used for text, also used to scale many graph elements.
402 In most cases you will want to use just the styles, but you may want
403 to exert more control over the way your chart looks. This section
404 describes the options you can use to control the way your chart looks.
406 Hopefully you don't need to read this.
412 The background of the graph.
418 Used to define basic background and foreground colors for the graph.
419 The bg color may be used for the background of the graph, and is used
420 as a default for the background of hatcheed fills. The fg is used as
421 the default for line and text colors.
425 The default font used by the graph. Normally you should supply this
426 if your graph as any text.
430 The default line color.
434 defaults for drawing text. Other textual graph elements will inherit
435 or modify these values.
441 default text color, defaults to the I<fg> color.
445 default text size. Default: 14. This is used to scale many graph
446 elements, including padding and leader sizes. Other text elements
447 will either use or scale this value.
451 default font object. Inherited from I<font>, which should have been
452 supplied by the caller.
458 If you supply a scalar value for this element, it will be stored in
461 Defines the text, font and layout information for the title.
467 The color of the title, inherited from I<text.color>.
471 The font object used for the title, inherited from I<text.font>.
475 size of the title text. Default: double I<text.size>
481 The horizontal and vertical alignment of the title.
487 defines attributes of the graph legend, if present.
497 text attributes for the labels used in the legend.
501 the width and height of the color patch in the legend. Defaults to
502 90% of the legend text size.
506 the minimum gap between patches in pixels. Defaults to 30% of the
511 the color of the border drawn around each patch. Inherited from I<line>.
517 the horizontal and vertical alignment of the legend within the graph.
518 Defaults to 'right' and 'top'.
522 the gap between the legend patches and text and the outside of it's
523 box, or to the legend border, if any.
527 the gap between the border and the outside of the legend's box. This
528 is only used if the I<legend.border> attribute is defined.
532 the background fill for the legend. Default: none
536 the border color of the legend. Default: none (no border is drawn
541 The orientation of the legend. If this is C<vertical> the the patches
542 and labels are stacked on top of each other. If this is C<horizontal>
543 the patchs and labels are word wrapped across the image. Default:
548 For example to create a horizontal legend with borderless patches,
549 darker than the background, you might do:
551 my $im = $chart->draw
555 patchborder => undef,
556 orientation => 'horizontal',
557 fill => { solid => Imager::Color->new(0, 0, 0, 32), }
563 defines attributes for graph callouts, if any are present. eg. if the
564 pie graph cannot fit the label into the pie graph segement it will
565 present it as a callout.
575 the text attributes of the callout label. Inherited from I<text>.
579 the color of the callout lines. Inherited from I<line>
585 the length of the leader on the inside and the outside of the fill,
586 usually at some angle. Both default to the size of the callout text.
590 the length of the horizontal portion of the leader. Default:
595 the gap between the callout leader and the callout text. Defaults to
596 30% of the text callout size.
602 defines attributes for labels drawn into the data areas of a graph.
612 The text attributes of the labels. Inherited from I<text>.
618 the attributes of the graph's drop shadow
624 the fill used for the drop shadow. Default: '404040' (dark gray)
628 the offset of the drop shadow. A convenience value inherited by offx
629 and offy. Default: 40% of I<text.size>.
635 the horizontal and vertical offsets of the drop shadow. Both
636 inherited from I<dropshadow.off>.
640 the filter description passed to Imager's filter method to blur the
641 drop shadow. Default: an 11 element convolution filter.
647 describes the lines drawn around filled data areas, such as the
648 segments of a pie chart.
654 the line color of the outlines, inherited from I<line>.
660 a reference to an array containing fills for each data item.
662 You can mix fill types, ie. using a simple color for the first item, a
663 hatched fill for the second and a fountain fill for the next.
667 =head1 HOW VALUES WORK
669 Internally rather than specifying literal color, fill, or font objects
670 or literal sizes for each element, Imager::Graph uses a number of
671 special values to inherit or modify values taken from other graph
674 =head2 Specifying colors
676 You can specify colors by either supplying an Imager::Color object, by
677 supplying lookup of another color, or by supplying a single value that
678 Imager::Color::new can use as an initializer. The most obvious is
679 just a 6 or 8 digit hex value representing the red, green, blue and
680 optionally alpha channels of the image.
682 You can lookup another color by using the lookup() "function", for
683 example if you give a color as "lookup(fg)" then Imager::Graph will
684 look for the fg element in the current style (or as overridden by
685 you.) This is used internally by Imager::Graph to set up the
686 relationships between the colors of various elements, for example the
687 default style information contains:
694 color=>'lookup(text.color)',
698 So by setting the I<fg> color, you also set the default text color,
699 since each text element uses lookup(text.color) as its value.
701 =head2 Specifying fills
703 Fills can be used for the graph background color, the background color
704 for the legend block and for the fills used for each data element.
706 You can specify a fill as a L<color value|Specifying colors> or as a
707 general fill, see L<Imager::Fill> for details.
709 You don't need (or usually want) to call Imager::Fill::new yourself,
710 since the various fill functions will call it for you, and
711 Imager::Graph provides some hooks to make them more useful.
717 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
718 Imager::Graph will supply the current graph fg and bg colors.
722 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
723 and yb_ratio parameters, and they will be scaled in the fill area to
724 define the fountain fills xa, ya, xb and yb parameters.
728 As with colors, you can use lookup(name) or lookup(name1.name2) to
729 have one element to inherit the fill of another.
731 Imager::Graph defaults the fill combine value to C<'normal'>. This
732 doesn't apply to simple color fills.
734 =head2 Specifying numbers
736 You can specify various numbers, usually representing the size of
737 something, commonly text, but sometimes the length of a line or the
740 You can use the same lookup mechanism as with colors and fills, but
741 you can also scale values. For example, 'scale(0.5,text.size)' will
742 return half the size of the normal text size.
744 As with colors, this is used internally to scale graph elements based
745 on the base text size. If you change the base text size then other
746 graph elements will scale as well.
748 =head2 Specifying other elements
750 Other elements, such as fonts, or parameters for a filter, can also
751 use the lookup(name) mechanism.
753 =head1 INTERNAL METHODS
755 Only useful if you need to fix bugs, add features or create a new
767 color => 'lookup(fg)',
768 font => 'lookup(font)',
772 color => 'lookup(text.color)',
773 font => 'lookup(text.font)',
776 size => 'scale(text.size,2.0)',
779 color => 'lookup(text.color)',
780 font => 'lookup(text.font)',
781 size => 'lookup(text.size)',
782 patchsize => 'scale(legend.size,0.9)',
783 patchgap => 'scale(legend.patchsize,0.3)',
784 patchborder => 'lookup(line)',
787 padding => 'scale(legend.size,0.3)',
788 outsidepadding => 'scale(legend.padding,0.4)',
791 color => 'lookup(text.color)',
792 font => 'lookup(text.font)',
793 size => 'lookup(text.size)',
794 line => 'lookup(line)',
795 inside => 'lookup(callout.size)',
796 outside => 'lookup(callout.size)',
797 leadlen => 'scale(0.8,callout.size)',
798 gap => 'scale(callout.size,0.3)',
801 font => 'lookup(text.font)',
802 size => 'lookup(text.size)',
803 color => 'lookup(text.color)',
804 hpad => 'lookup(label.pad)',
805 vpad => 'lookup(label.pad)',
806 pad => 'scale(label.size,0.2)',
807 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
808 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
811 fill => { solid => Imager::Color->new(0, 0, 0, 96) },
812 off => 'scale(0.4,text.size)',
813 offx => 'lookup(dropshadow.off)',
814 offy => 'lookup(dropshadow.off)',
815 filter => { type=>'conv',
816 # this needs a fairly heavy blur
817 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
818 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
821 line =>'lookup(line)',
824 width=>'scale(1.5,size)',
825 height=>'lookup(size)',
828 =item _error($message)
830 Sets the error field of the object and returns an empty list or undef,
831 depending on context. Should be used for error handling, since it may
832 provide some user hooks at some point.
834 The intended usage is:
837 or return $self->_error("error description");
839 You should almost always return the result of _error() or return
840 immediately afterwards.
845 my ($self, $error) = @_;
847 $self->{_errstr} = $error;
855 Returns the style defaults, such as the relationships between line
856 color and text color.
858 Intended to be over-ridden by base classes to provide graph specific
867 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
868 my $def_style = 'fount_lin';
876 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
882 #patchborder=>'000000'
889 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
895 patchborder=>'000000'
908 { hatch=>'stipple3' },
909 { hatch=>'stipple2' },
914 features=>{ outline=>1 },
923 { fountain=>'linear',
924 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
925 segments => Imager::Fountain->simple(positions=>[0, 1],
926 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
928 { fountain=>'linear',
929 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
930 segments => Imager::Fountain->simple(positions=>[0, 1],
931 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
933 { fountain=>'linear',
934 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
935 segments => Imager::Fountain->simple(positions=>[0, 1],
936 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
938 { fountain=>'linear',
939 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
940 segments => Imager::Fountain->simple(positions=>[0, 1],
941 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
943 { fountain=>'linear',
944 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
945 segments => Imager::Fountain->simple(positions=>[0, 1],
946 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
948 { fountain=>'linear',
949 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
950 segments => Imager::Fountain->simple(positions=>[0, 1],
951 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
955 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
957 back=>{ fountain=>'linear',
958 xa_ratio=>0, ya_ratio=>0,
959 xb_ratio=>1.0, yb_ratio=>1.0,
960 segments=>Imager::Fountain->simple
962 colors=>[ NC('6060FF'), NC('60FF60') ]) },
965 features=>{ dropshadow=>1 },
971 { fountain=>'radial',
972 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
973 segments => Imager::Fountain->simple(positions=>[0, 1],
974 colors=>[ NC('FF8080'), NC('FF0000') ]),
976 { fountain=>'radial',
977 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
978 segments => Imager::Fountain->simple(positions=>[0, 1],
979 colors=>[ NC('80FF80'), NC('00FF00') ]),
981 { fountain=>'radial',
982 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
983 segments => Imager::Fountain->simple(positions=>[0, 1],
984 colors=>[ NC('808080FF'), NC('0000FF') ]),
986 { fountain=>'radial',
987 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
988 segments => Imager::Fountain->simple(positions=>[0, 1],
989 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
991 { fountain=>'radial',
992 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
993 segments => Imager::Fountain->simple(positions=>[0, 1],
994 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
996 { fountain=>'radial',
997 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
998 segments => Imager::Fountain->simple(positions=>[0, 1],
999 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1003 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1005 back=>{ fountain=>'linear',
1006 xa_ratio=>0, ya_ratio=>0,
1007 xb_ratio=>1.0, yb_ratio=>1.0,
1008 segments=>Imager::Fountain->simple
1009 ( positions=>[0, 1],
1010 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1016 =item $self->_style_setup(\%opts)
1018 Uses the values from %opts to build a customized hash describing the
1019 way the graph should be drawn.
1024 my ($self, $opts) = @_;
1025 my $style_defs = $self->_style_defs;
1028 # fill in values from api calls
1029 $opts->{'size'} = $opts->{'size'} || $self->_getGraphSize();
1030 $opts->{'width'} = $opts->{'width'} || $self->_getImageWidth();
1031 $opts->{'height'} = $opts->{'height'} || $self->_getImageHeight();
1032 $opts->{'font'} = $opts->{'font'} || $self->_getFont();
1033 $opts->{'title'} = $opts->{'title'};
1034 if (!$opts->{'title'} && $self->_getTitle()) {
1035 $opts->{'title'} = { text => $self->_getTitle() };
1038 my $pre_def_style = $self->_getStyle($opts);
1039 $style = $styles{$pre_def_style} if $pre_def_style;
1041 $style ||= $styles{$def_style};
1043 my @search_list = ( $style_defs, $style, $opts);
1046 my @composite = $self->_composite();
1048 @composite{@composite} = @composite;
1050 for my $src (@search_list) {
1051 for my $key (keys %$src) {
1052 if ($composite{$key}) {
1053 $work{$key} = {} unless exists $work{$key};
1054 if (ref $src->{$key}) {
1055 # some keys have sub values, especially text
1056 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1059 # assume it's the text for a title or something
1060 $work{$key}{text} = $src->{$key};
1064 $work{$key} = $src->{$key}
1065 if defined $src->{$key}; # $opts with pmichauds new accessor handling
1070 # features are handled specially
1071 $work{features} = {};
1072 for my $src (@search_list) {
1073 if ($src->{features}) {
1074 if (ref $src->{features}) {
1075 if (ref($src->{features}) =~ /ARRAY/) {
1076 # just set those features
1077 for my $feature (@{$src->{features}}) {
1078 $work{features}{$feature} = 1;
1081 elsif (ref($src->{features}) =~ /HASH/) {
1082 if ($src->{features}{reset}) {
1083 $work{features} = {}; # only the ones the user specifies
1085 @{$work{features}}{keys %{$src->{features}}} =
1086 values(%{$src->{features}});
1090 # just set that single feature
1091 $work{features}{$src->{features}} = 1;
1096 #print Dumper(\%work);
1098 $self->{_style} = \%work;
1101 =item $self->_get_thing($name)
1103 Retrieve some general 'thing'.
1105 Supports the 'lookup(foo)' mechanism.
1107 Returns an empty list on failure.
1112 my ($self, $name, @depth) = @_;
1114 push(@depth, $name);
1116 if ($name =~ /^(\w+)\.(\w+)$/) {
1117 $what = $self->{_style}{$1}{$2};
1120 $what = $self->{_style}{$name};
1127 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1129 or return $self->_error("too many levels of recursion in lookup(@depth)");
1130 return $self->_get_thing($1, @depth);
1137 =item $self->_get_number($name)
1139 Retrieves a number from the style. The value in the style can be the
1140 number, or one of two functions:
1144 =item lookup(newname)
1146 Recursively looks up I<newname> in the style.
1148 =item scale(value1,value2)
1150 Each value can be a number or a name. Names are recursively looked up
1151 in the style and the product is returned.
1158 my ($self, $name, @depth) = @_;
1160 push(@depth, $name);
1162 if ($name =~ /^(\w+)\.(\w+)$/) {
1163 $what = $self->{_style}{$1}{$2};
1166 $what = $self->{_style}{$name};
1169 return $self->_error("$name is undef (@depth)");
1172 if ($what =~ /CODE/) {
1173 $what = $what->($self, $name);
1177 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1179 or return $self->_error("too many levels of recursion in lookup (@depth)");
1180 return $self->_get_number($1, @depth);
1182 elsif ($what =~ /^scale\(
1183 ((?:[a-z][\w.]*)|$NUM_RE)
1185 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1186 my ($left, $right) = ($1, $2);
1187 unless ($left =~ /^$NUM_RE$/) {
1189 or return $self->_error("too many levels of recursion in scale (@depth)");
1190 $left = $self->_get_number($left, @depth);
1192 unless ($right =~ /^$NUM_RE$/) {
1194 or return $self->_error("too many levels of recursion in scale (@depth)");
1195 $right = $self->_get_number($right, @depth);
1197 return $left * $right;
1205 =item $self->_get_integer($name)
1207 Retrieves an integer from the style. This is a simple wrapper around
1208 _get_number() that rounds the result to an integer.
1210 Returns an empty list on failure.
1215 my ($self, $name, @depth) = @_;
1217 my $number = $self->_get_number($name, @depth)
1220 return sprintf("%.0f", $number);
1223 =item _get_color($name)
1225 Returns a color object of the given name from the style hash.
1227 Uses Imager::Color->new to translate normal scalars into color objects.
1229 Allows the lookup(name) mechanism.
1231 Returns an empty list on failure.
1236 my ($self, $name, @depth) = @_;
1238 push(@depth, $name);
1240 if ($name =~ /^(\w+)\.(\w+)$/) {
1241 $what = $self->{_style}{$1}{$2};
1244 $what = $self->{_style}{$name};
1248 or return $self->_error("$name was undefined (@depth)");
1250 unless (ref $what) {
1251 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1252 @depth < MAX_DEPTH or
1253 return $self->_error("too many levels of recursion in lookup (@depth)");
1255 return $self->_get_color($1, @depth);
1257 $what = Imager::Color->new($what);
1263 =item _translate_fill($what, $box)
1265 Given the value of a fill, either attempts to convert it into a fill
1266 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1267 parameters }>>), or to lookup another fill that is referred to with
1268 the 'lookup(name)' mechanism.
1270 This function does the fg and bg initialization for hatched fills, and
1271 translation of *_ratio for fountain fills (using the $box parameter).
1273 Returns an empty list on failure.
1277 sub _translate_fill {
1278 my ($self, $what, $box, @depth) = @_;
1281 if (UNIVERSAL::isa($what, "Imager::Color")) {
1282 return ( color=>Imager::Color->new($what), filled=>1 );
1286 # default to normal combine mode
1287 my %work = ( combine => 'normal', %$what );
1288 if ($what->{hatch}) {
1290 $work{fg} = $self->_get_color('fg')
1294 $work{bg} = $self->_get_color('bg')
1297 return ( fill=>\%work );
1299 elsif ($what->{fountain}) {
1300 for my $key (qw(xa ya xb yb)) {
1301 if (exists $work{"${key}_ratio"}) {
1303 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1304 * ($box->[2] - $box->[0]);
1307 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1308 * ($box->[3] - $box->[1]);
1312 return ( fill=>\%work );
1315 return ( fill=> \%work );
1320 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1321 return $self->_get_fill($1, $box, @depth);
1324 # assumed to be an Imager::Color single value
1325 return ( color=>Imager::Color->new($what), filled=>1 );
1330 =item _data_fill($index, $box)
1332 Retrieves the fill parameters for a data area fill.
1337 my ($self, $index, $box) = @_;
1339 my $fills = $self->{_style}{fills};
1340 return $self->_translate_fill($fills->[$index % @$fills], $box,
1345 my ($self, $index) = @_;
1347 my $colors = $self->{'_style'}{'colors'} || [];
1348 my $fills = $self->{'_style'}{'fills'} || [];
1350 # Try to just use a fill, so non-fountain styles don't need
1351 # to have a duplicated set of fills and colors
1352 my $fill = $fills->[$index % @$fills];
1358 return $colors->[$index % @$colors] || '000000';
1363 =item _get_fill($index, $box)
1365 Retrieves fill parameters for a named fill.
1370 my ($self, $name, $box, @depth) = @_;
1372 push(@depth, $name);
1374 if ($name =~ /^(\w+)\.(\w+)$/) {
1375 $what = $self->{_style}{$1}{$2};
1378 $what = $self->{_style}{$name};
1382 or return $self->_error("no fill $name found");
1384 return $self->_translate_fill($what, $box, @depth);
1389 Builds the image object for the graph and fills it with the background
1397 my $width = $self->_get_number('width') || 256;
1398 my $height = $self->_get_number('height') || 256;
1399 my $channels = $self->{_style}{channels};
1403 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1405 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1410 =item _text_style($name)
1412 Returns parameters suitable for calls to Imager::Font's bounding_box()
1413 and draw() methods intended for use in defining text styles.
1415 Returns an empty list on failure.
1420 my ($self, $name) = @_;
1424 if ($self->{_style}{$name}) {
1425 %work = %{$self->{_style}{$name}};
1428 %work = %{$self->{_style}{text}};
1431 or return $self->_error("$name has no font parameter");
1433 $work{font} = $self->_get_thing("$name.font")
1434 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1435 UNIVERSAL::isa($work{font}, "Imager::Font")
1436 or return $self->_error("$name.font is not a font");
1437 if ($work{color} && !ref $work{color}) {
1438 $work{color} = $self->_get_color("$name.color")
1441 $work{size} = $self->_get_number("$name.size");
1442 $work{sizew} = $self->_get_number("$name.sizew")
1448 =item _text_bbox($text, $name)
1450 Returns a bounding box for the specified $text as styled by $name.
1452 Returns an empty list on failure.
1457 my ($self, $text, $name) = @_;
1459 my %text_info = $self->_text_style($name)
1462 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1469 my ($self, $box, $chart_box, $name) = @_;
1471 my $halign = $self->{_style}{$name}{halign}
1472 or $self->_error("no halign for $name");
1473 my $valign = $self->{_style}{$name}{valign};
1475 if ($halign eq 'right') {
1476 $box->[0] += $chart_box->[2] - $box->[2];
1478 elsif ($halign eq 'left') {
1479 $box->[0] = $chart_box->[0];
1481 elsif ($halign eq 'center' || $halign eq 'centre') {
1482 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1485 return $self->_error("invalid halign $halign for $name");
1488 if ($valign eq 'top') {
1489 $box->[1] = $chart_box->[1];
1491 elsif ($valign eq 'bottom') {
1492 $box->[1] = $chart_box->[3] - $box->[3];
1494 elsif ($valign eq 'center' || $valign eq 'centre') {
1495 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1498 return $self->_error("invalid valign $valign for $name");
1500 $box->[2] += $box->[0];
1501 $box->[3] += $box->[1];
1505 my ($self, $chart_box, $object_box) = @_;
1509 if ($object_box->[0] - $chart_box->[0]
1510 < $chart_box->[2] - $object_box->[2]) {
1511 $areax = ($object_box->[2] - $chart_box->[0])
1512 * ($chart_box->[3] - $chart_box->[1]);
1515 $areax = ($chart_box->[2] - $object_box->[0])
1516 * ($chart_box->[3] - $chart_box->[1]);
1519 if ($object_box->[1] - $chart_box->[1]
1520 < $chart_box->[3] - $object_box->[3]) {
1521 $areay = ($object_box->[3] - $chart_box->[1])
1522 * ($chart_box->[2] - $chart_box->[0]);
1525 $areay = ($chart_box->[3] - $object_box->[1])
1526 * ($chart_box->[2] - $chart_box->[0]);
1529 if ($areay < $areax) {
1530 if ($object_box->[1] - $chart_box->[1]
1531 < $chart_box->[3] - $object_box->[3]) {
1532 $chart_box->[1] = $object_box->[3];
1535 $chart_box->[3] = $object_box->[1];
1539 if ($object_box->[0] - $chart_box->[0]
1540 < $chart_box->[2] - $object_box->[2]) {
1541 $chart_box->[0] = $object_box->[2];
1544 $chart_box->[2] = $object_box->[0];
1550 my ($self, $img, $labels, $chart_box) = @_;
1552 my $orient = $self->_get_thing('legend.orientation');
1553 defined $orient or $orient = 'vertical';
1555 if ($orient eq 'vertical') {
1556 return $self->_draw_legend_vertical($img, $labels, $chart_box);
1558 elsif ($orient eq 'horizontal') {
1559 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
1562 return $self->_error("Unknown legend.orientation $orient");
1566 sub _draw_legend_horizontal {
1567 my ($self, $img, $labels, $chart_box) = @_;
1569 defined(my $padding = $self->_get_integer('legend.padding'))
1571 my $patchsize = $self->_get_integer('legend.patchsize')
1573 defined(my $gap = $self->_get_integer('legend.patchgap'))
1576 my $minrowsize = $patchsize + $gap;
1577 my ($width, $height) = (0,0);
1578 my $row_height = $minrowsize;
1582 for my $label (@$labels) {
1583 my @text_box = $self->_text_bbox($label, 'legend')
1585 push(@sizes, \@text_box);
1586 my $entry_width = $patchsize + $gap + $text_box[2];
1588 # never re-wrap the first entry
1589 push @offsets, [ 0, $height ];
1592 if ($pos + $gap + $entry_width > $chart_box->[2]) {
1594 $height += $row_height;
1596 push @offsets, [ $pos, $height ];
1598 my $entry_right = $pos + $entry_width;
1599 $pos += $gap + $entry_width;
1600 $entry_right > $width and $width = $entry_right;
1601 if ($text_box[3] > $row_height) {
1602 $row_height = $text_box[3];
1605 $height += $row_height;
1606 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
1607 my $outsidepadding = 0;
1608 if ($self->{_style}{legend}{border}) {
1609 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1611 $box[2] += 2 * $outsidepadding;
1612 $box[3] += 2 * $outsidepadding;
1614 $self->_align_box(\@box, $chart_box, 'legend')
1616 if ($self->{_style}{legend}{fill}) {
1617 $img->box(xmin=>$box[0]+$outsidepadding,
1618 ymin=>$box[1]+$outsidepadding,
1619 xmax=>$box[2]-$outsidepadding,
1620 ymax=>$box[3]-$outsidepadding,
1621 $self->_get_fill('legend.fill', \@box));
1623 $box[0] += $outsidepadding;
1624 $box[1] += $outsidepadding;
1625 $box[2] -= $outsidepadding;
1626 $box[3] -= $outsidepadding;
1627 my %text_info = $self->_text_style('legend')
1630 if ($self->{_style}{legend}{patchborder}) {
1631 $patchborder = $self->_get_color('legend.patchborder')
1636 for my $label (@$labels) {
1637 my ($left, $top) = @{$offsets[$dataindex]};
1638 $left += $box[0] + $padding;
1639 $top += $box[1] + $padding;
1640 my $textpos = $left + $patchsize + $gap;
1641 my @patchbox = ( $left, $top,
1642 $left + $patchsize, $top + $patchsize );
1643 my @fill = $self->_data_fill($dataindex, \@patchbox)
1645 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1646 ymax=>$top + $patchsize, @fill);
1647 if ($self->{_style}{legend}{patchborder}) {
1648 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
1649 ymax=>$top + $patchsize,
1650 color=>$patchborder);
1652 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
1657 if ($self->{_style}{legend}{border}) {
1658 my $border_color = $self->_get_color('legend.border')
1660 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1661 color=>$border_color);
1663 $self->_remove_box($chart_box, \@box);
1667 sub _draw_legend_vertical {
1668 my ($self, $img, $labels, $chart_box) = @_;
1670 defined(my $padding = $self->_get_integer('legend.padding'))
1672 my $patchsize = $self->_get_integer('legend.patchsize')
1674 defined(my $gap = $self->_get_integer('legend.patchgap'))
1676 my $minrowsize = $patchsize + $gap;
1677 my ($width, $height) = (0,0);
1679 for my $label (@$labels) {
1680 my @box = $self->_text_bbox($label, 'legend')
1682 push(@sizes, \@box);
1683 $width = $box[2] if $box[2] > $width;
1684 if ($minrowsize > $box[3]) {
1685 $height += $minrowsize;
1692 $width + $patchsize + $padding * 2 + $gap,
1693 $height + $padding * 2 - $gap);
1694 my $outsidepadding = 0;
1695 if ($self->{_style}{legend}{border}) {
1696 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
1698 $box[2] += 2 * $outsidepadding;
1699 $box[3] += 2 * $outsidepadding;
1701 $self->_align_box(\@box, $chart_box, 'legend')
1703 if ($self->{_style}{legend}{fill}) {
1704 $img->box(xmin=>$box[0]+$outsidepadding,
1705 ymin=>$box[1]+$outsidepadding,
1706 xmax=>$box[2]-$outsidepadding,
1707 ymax=>$box[3]-$outsidepadding,
1708 $self->_get_fill('legend.fill', \@box));
1710 $box[0] += $outsidepadding;
1711 $box[1] += $outsidepadding;
1712 $box[2] -= $outsidepadding;
1713 $box[3] -= $outsidepadding;
1714 my $ypos = $box[1] + $padding;
1715 my $patchpos = $box[0]+$padding;
1716 my $textpos = $patchpos + $patchsize + $gap;
1717 my %text_info = $self->_text_style('legend')
1720 if ($self->{_style}{legend}{patchborder}) {
1721 $patchborder = $self->_get_color('legend.patchborder')
1725 for my $label (@$labels) {
1726 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
1727 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
1728 my @fill = $self->_data_fill($dataindex, \@patchbox)
1730 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1731 ymax=>$ypos + $patchsize, @fill);
1732 if ($self->{_style}{legend}{patchborder}) {
1733 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
1734 ymax=>$ypos + $patchsize,
1735 color=>$patchborder);
1737 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
1740 my $step = $patchsize + $gap;
1741 if ($minrowsize < $sizes[$dataindex][3]) {
1742 $ypos += $sizes[$dataindex][3];
1745 $ypos += $minrowsize;
1749 if ($self->{_style}{legend}{border}) {
1750 my $border_color = $self->_get_color('legend.border')
1752 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
1753 color=>$border_color);
1755 $self->_remove_box($chart_box, \@box);
1760 my ($self, $img, $chart_box) = @_;
1762 my $title = $self->{_style}{title}{text};
1763 my @box = $self->_text_bbox($title, 'title')
1767 $self->_align_box(\@box, $chart_box, 'title');
1768 my %text_info = $self->_text_style('title')
1770 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
1771 $self->_remove_box($chart_box, \@box);
1776 my ($self, $box) = @_;
1778 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
1779 return $box->[3] - $box->[1];
1782 return $box->[2] - $box->[0];
1788 Returns a list of style fields that are stored as composites, and
1789 should be merged instead of just being replaced.
1794 qw(title legend text label dropshadow outline callout);
1797 sub _filter_region {
1798 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
1800 unless (ref $filter) {
1802 $filter = $self->_get_thing($name)
1805 or return $self->_error("no type for filter $name");
1808 $left > 0 or $left = 0;
1809 $top > 0 or $top = 0;
1811 # newer versions of Imager let you work on just part of an image
1812 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
1813 my $masked = $img->masked(left=>$left, top=>$top,
1814 right=>$right, bottom=>$bottom);
1815 $masked->filter(%$filter);
1818 # for older versions of Imager
1819 my $subset = $img->crop(left=>$left, top=>$top,
1820 right=>$right, bottom=>$bottom);
1821 $subset->filter(%$filter);
1822 $img->paste(left=>$left, top=>$top, img=>$subset);
1833 Imager::Graph::Pie(3), Imager(3), perl(1).
1837 Tony Cook <tony@develop-help.com>
1841 Imager::Graph is licensed under the same terms as perl itself.
1845 Addi for producing a cool imaging module. :)