6 Imager::Graph - Perl extension for producing Graphs using the Imager library.
10 use Imager::Graph::Sub_class;
11 my $chart = Imager::Graph::Sub_class->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 set_graph_size($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]->{'custom_style'}->{'size'} = $_[1];
58 =item set_image_width($width)
60 Sets the width of the image in pixels.
65 $_[0]->{'custom_style'}->{'width'} = $_[1];
68 =item set_image_height($height)
70 Sets the height of the image in pixels.
74 sub set_image_height {
75 $_[0]->{'custom_style'}->{'height'} = $_[1];
78 =item add_data_series([8, 6, 7, 5, 3, 0, 9], 'Series Name');
80 Adds a data series to the graph. For L<Imager::Graph::Pie>, only one data series can be added.
87 my $series_name = shift;
89 my $graph_data = $self->{'graph_data'} || [];
91 push @$graph_data, { data => $data_ref, series_name => $series_name };
93 $self->{'graph_data'} = $graph_data;
97 sub _get_data_series {
98 my ($self, $opts) = @_;
100 # return the data supplied to draw() if any.
102 # one or multiple series?
103 my $data = $opts->{data};
104 if (@$data && ref $data->[0] && ref $data->[0] =~ /ARRAY/) {
108 return [ { data => $data } ];
112 return $self->{'graph_data'};
115 =item set_labels(['label1', 'label2' ... ])
117 Labels the specific data points. For line/bar graphs, this is the x-axis. For pie graphs, it is the label for the wedges.
122 $_[0]->{'labels'} = $_[1];
126 my ($self, $opts) = @_;
129 and return $opts->{labels};
131 return $_[0]->{'labels'}
134 =item set_title($title)
136 Sets the title of the graph. Requires setting a font.
141 $_[0]->{'custom_style'}->{'title'}->{'text'} = $_[1];
144 =item set_font($font)
146 Sets the font to use for text. Takes an L<Imager::Font> object.
151 $_[0]->{'custom_style'}->{'font'} = $_[1];
154 =item set_style($style_name)
156 Sets the style to be used for the graph. Imager::Graph comes with several pre-defined styles: fount_lin (default), fount_rad, mono, primary_red, and primary.
161 $_[0]->{'style'} = $_[1];
165 my ($self, $opts) = @_;
168 and return $opts->{style};
170 return $self->{'style'};
175 Returns an error message. Only value if the draw() method returns false.
185 Creates a new image, draws the chart onto that image and returns it.
187 Optionally, instead of using the api methods to configure your chart,
188 you can supply a C<data> parameter in the format
189 required by that particular graph, and if your graph will use any
190 text, a C<font> parameter
192 You can also supply many different parameters which control the way
193 the graph looks. These are supplied as keyword, value pairs, where
194 the value can be a hashref containing sub values.
196 The C<style> parameter will selects a basic color set, and possibly
197 sets other related parameters. See L</"STYLES">.
199 my $font = Imager::Font->new(file => 'Im_ugly.ttf');
200 my $img = $chart->draw(
204 text => "Hello, World!",
210 When referring to a single sub-value this documentation will refer to
211 'title.color' rather than 'the color element of title'.
213 Returns the graph image on success, or false on failure.
219 The currently defined styles are:
225 a light grey background with no outlines. Uses primary colors for the
230 a light red background with no outlines. Uses primary colors for the
233 Graphs drawn using this style should save well as a gif, even though
234 some graphs may perform a slight blur.
236 This was the default style, but the red was too loud.
240 designed for monochrome output, such as most laser printers, this uses
241 hatched fills for the data, and no colors. The returned image is a
242 one channel image (which can be overridden with the C<channels>
245 You can also override the colors used by all components for background
246 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
247 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
248 else will be drawn in red. Another use might be to set a transparent
249 background, by supplying C<<bg=>'00000000', channels=>4>>.
251 This style outlines the legend if present and outlines the hashed fills.
255 designed as a "pretty" style this uses linear fountain fills for the
256 background and data fills, and adds a drop shadow.
258 You can override the value used for text and outlines by setting the
261 This is the default style.
265 also designed as a "pretty" style this uses radial fountain fills for
266 the data and a linear blue to green fill for the background.
272 To set or override styles, you can use the following methods:
276 =item set_image_background
280 sub set_image_background {
281 $_[0]->{'custom_style'}->{'back'} = $_[1];
289 $_[0]->{'custom_style'}->{'channels'} = $_[1];
297 $_[0]->{'custom_style'}->{'line'} = $_[1];
300 =item set_title_font_size
304 sub set_title_font_size {
305 $_[0]->{'custom_style'}->{'title'}->{'size'} = $_[1];
308 =item set_title_font_color
312 sub set_title_font_color {
313 $_[0]->{'custom_style'}->{'title'}->{'color'} = $_[1];
316 =item set_title_horizontal_align
320 sub set_title_horizontal_align {
321 $_[0]->{'custom_style'}->{'title'}->{'halign'} = $_[1];
324 =item set_title_vertical_align
328 sub set_title_vertical_align {
329 $_[0]->{'custom_style'}->{'title'}->{'valign'} = $_[1];
332 =item set_text_font_color
336 sub set_text_font_color {
337 $_[0]->{'custom_style'}->{'text'}->{'color'} = $_[1];
340 =item set_text_font_size
344 sub set_text_font_size {
345 $_[0]->{'custom_style'}->{'text'}->{'size'} = $_[1];
348 =item set_graph_background_color
352 sub set_graph_background_color {
353 $_[0]->{'custom_style'}->{'bg'} = $_[1];
356 =item set_graph_foreground_color
360 sub set_graph_foreground_color {
361 $_[0]->{'custom_style'}->{'fg'} = $_[1];
364 =item set_legend_font_color
368 sub set_legend_font_color {
369 $_[0]->{'custom_style'}->{'legend'}->{'color'} = $_[1];
372 =item set_legend_font
376 sub set_legend_font {
377 $_[0]->{'custom_style'}->{'legend'}->{'font'} = $_[1];
380 =item set_legend_font_size
384 sub set_legend_font_size {
385 $_[0]->{'custom_style'}->{'legend'}->{'size'} = $_[1];
388 =item set_legend_patch_size
392 sub set_legend_patch_size {
393 $_[0]->{'custom_style'}->{'legend'}->{'patchsize'} = $_[1];
396 =item set_legend_patch_gap
400 sub set_legend_patch_gap {
401 $_[0]->{'custom_style'}->{'legend'}->{'patchgap'} = $_[1];
404 =item set_legend_horizontal_align
408 sub set_legend_horizontal_align {
409 $_[0]->{'custom_style'}->{'legend'}->{'halign'} = $_[1];
412 =item set_legend_vertical_align
416 sub set_legend_vertical_align {
417 $_[0]->{'custom_style'}->{'legend'}->{'valign'} = $_[1];
420 =item set_legend_padding
424 sub set_legend_padding {
425 $_[0]->{'custom_style'}->{'legend'}->{'padding'} = $_[1];
428 =item set_legend_outside_padding
432 sub set_legend_outside_padding {
433 $_[0]->{'custom_style'}->{'legend'}->{'outsidepadding'} = $_[1];
436 =item set_legend_fill
440 sub set_legend_fill {
441 $_[0]->{'custom_style'}->{'legend'}->{'fill'} = $_[1];
444 =item set_legend_border
448 sub set_legend_border {
449 $_[0]->{'custom_style'}->{'legend'}->{'border'} = $_[1];
452 =item set_legend_orientation
456 sub set_legend_orientation {
457 $_[0]->{'custom_style'}->{'legend'}->{'orientation'} = $_[1];
460 =item set_callout_font_color
464 sub set_callout_font_color {
465 $_[0]->{'custom_style'}->{'callout'}->{'color'} = $_[1];
468 =item set_callout_font
472 sub set_callout_font {
473 $_[0]->{'custom_style'}->{'callout'}->{'font'} = $_[1];
476 =item set_callout_font_size
480 sub set_callout_font_size {
481 $_[0]->{'custom_style'}->{'callout'}->{'size'} = $_[1];
484 =item set_callout_line_color
488 sub set_callout_line_color {
489 $_[0]->{'custom_style'}->{'callout'}->{'line'} = $_[1];
492 =item set_callout_leader_inside_length
496 sub set_callout_leader_inside_length {
497 $_[0]->{'custom_style'}->{'callout'}->{'inside'} = $_[1];
500 =item set_callout_leader_outside_length
504 sub set_callout_leader_outside_length {
505 $_[0]->{'custom_style'}->{'callout'}->{'outside'} = $_[1];
508 =item set_callout_leader_length
512 sub set_callout_leader_length {
513 $_[0]->{'custom_style'}->{'callout'}->{'leadlen'} = $_[1];
516 =item set_callout_gap
520 sub set_callout_gap {
521 $_[0]->{'custom_style'}->{'callout'}->{'gap'} = $_[1];
524 =item set_label_font_color
528 sub set_label_font_color {
529 $_[0]->{'custom_style'}->{'label'}->{'color'} = $_[1];
537 $_[0]->{'custom_style'}->{'label'}->{'font'} = $_[1];
540 =item set_label_font_size
544 sub set_label_font_size {
545 $_[0]->{'custom_style'}->{'label'}->{'size'} = $_[1];
548 =item set_drop_shadow_fill_color
552 sub set_drop_shadow_fill_color {
553 $_[0]->{'custom_style'}->{'dropshadow'}->{'fill'} = $_[1];
556 =item set_drop_shadow_offset
560 sub set_drop_shadow_offset {
561 $_[0]->{'custom_style'}->{'dropshadow'}->{'off'} = $_[1];
564 =item set_drop_shadowXOffset
568 sub set_drop_shadowXOffset {
569 $_[0]->{'custom_style'}->{'dropshadow'}->{'offx'} = $_[1];
572 =item set_drop_shadowYOffset
576 sub set_drop_shadowYOffset {
577 $_[0]->{'custom_style'}->{'dropshadow'}->{'offy'} = $_[1];
580 =item set_drop_shadow_filter
584 sub set_drop_shadow_filter {
585 $_[0]->{'custom_style'}->{'dropshadow'}->{'filter'} = $_[1];
588 =item set_outline_color
592 sub set_outline_color {
593 $_[0]->{'custom_style'}->{'outline'}->{'line'} = $_[1];
596 =item set_data_area_fills
600 sub set_data_area_fills {
601 $_[0]->{'custom_style'}->{'fills'} = $_[1];
604 =item set_data_line_colors
608 sub set_data_line_colors {
609 $_[0]->{'custom_style'}->{'colors'} = $_[1];
616 Each graph type has a number of features. These are used to add
617 various items that are displayed in the graph area. Some common
624 adds a box containing boxes filled with the data filess, with
625 the labels provided to the draw method. The legend will only be
626 displayed if both the legend feature is enabled and labels are
632 $_[0]->{'custom_style'}->{'features'}->{'legend'} = 1;
637 draws a border around the data areas.
642 $_[0]->{'custom_style'}->{'features'}->{'outline'} = 1;
647 labels each data fill, usually by including text inside the data fill.
648 If the text does not fit in the fill, they could be displayed in some
649 other form, eg. as callouts in a pie graph. There usually isn't much
650 point in including both labels and a legend.
655 $_[0]->{'custom_style'}->{'features'}->{'labels'} = 1;
658 =item show_drop_shadow()
660 a simple drop shadow is shown behind some of the graph elements.
664 sub show_drop_shadow {
665 $_[0]->{'custom_style'}->{'features'}->{'dropshadow'} = 1;
668 =item reset_features()
670 Unsets all of the features
675 $_[0]->{'custom_style'}->{'features'} = {};
676 $_[0]->{'custom_style'}->{'features'}->{'reset'} = 1;
681 Additionally, features can be set by passing them into the draw() method:
687 adds a box containing boxes filled with the data filess, with
688 the labels provided to the draw method. The legend will only be
689 displayed if both the legend feature is enabled and labels are
694 labels each data fill, usually by including text inside the data fill.
695 If the text does not fit in the fill, they could be displayed in some
696 other form, eg. as callouts in a pie graph. There usually isn't much
697 point in including both labels and a legend.
701 a simple drop shadow is shown behind some of the graph elements.
705 Each graph also has features specific to that graph.
707 =head1 COMMON PARAMETERS
709 When referring to a single sub-value this documentation will refer to
710 'title.color' rather than 'the color element of title'.
712 Normally, except for the font parameter, these are controlled by
713 styles, but these are the style parameters I'd mostly likely expect
720 the Imager font object used to draw text on the chart.
724 the background fill for the graph. Default depends on the style.
728 the base size of the graph image. Default: 256
732 the width of the graph image. Default: 1.5 * size (384)
736 the height of the graph image. Default: size (256)
740 the number of channels in the image. Default: 3 (the 'mono' style
745 the color used for drawing lines, such as outlines or callouts.
746 Default depends on the current style. Set to undef to remove the
747 outline from a style.
751 the text used for a graph title. Default: no title. Note: this is
752 the same as the title=>{ text => ... } field.
758 horizontal alignment of the title in the graph, one of 'left',
759 'center' or 'right'. Default: center
763 vertical alignment of the title, one of 'top', 'center' or 'right'.
764 Default: top. It's probably a bad idea to set this to 'center' unless
765 you have a very short title.
771 This contains basic defaults used in drawing text.
777 the default color used for all text, defaults to the fg color.
781 the base size used for text, also used to scale many graph elements.
790 In most cases you will want to use just the styles, but you may want
791 to exert more control over the way your chart looks. This section
792 describes the options you can use to control the way your chart looks.
794 Hopefully you don't need to read this.
800 The background of the graph.
806 Used to define basic background and foreground colors for the graph.
807 The bg color may be used for the background of the graph, and is used
808 as a default for the background of hatcheed fills. The fg is used as
809 the default for line and text colors.
813 The default font used by the graph. Normally you should supply this
814 if your graph as any text.
818 The default line color.
822 defaults for drawing text. Other textual graph elements will inherit
823 or modify these values.
829 default text color, defaults to the I<fg> color.
833 default text size. Default: 14. This is used to scale many graph
834 elements, including padding and leader sizes. Other text elements
835 will either use or scale this value.
839 default font object. Inherited from I<font>, which should have been
840 supplied by the caller.
846 If you supply a scalar value for this element, it will be stored in
849 Defines the text, font and layout information for the title.
855 The color of the title, inherited from I<text.color>.
859 The font object used for the title, inherited from I<text.font>.
863 size of the title text. Default: double I<text.size>
869 The horizontal and vertical alignment of the title.
875 defines attributes of the graph legend, if present.
885 text attributes for the labels used in the legend.
889 the width and height of the color patch in the legend. Defaults to
890 90% of the legend text size.
894 the minimum gap between patches in pixels. Defaults to 30% of the
899 the color of the border drawn around each patch. Inherited from I<line>.
905 the horizontal and vertical alignment of the legend within the graph.
906 Defaults to 'right' and 'top'.
910 the gap between the legend patches and text and the outside of it's
911 box, or to the legend border, if any.
915 the gap between the border and the outside of the legend's box. This
916 is only used if the I<legend.border> attribute is defined.
920 the background fill for the legend. Default: none
924 the border color of the legend. Default: none (no border is drawn
929 The orientation of the legend. If this is C<vertical> the the patches
930 and labels are stacked on top of each other. If this is C<horizontal>
931 the patchs and labels are word wrapped across the image. Default:
936 For example to create a horizontal legend with borderless patches,
937 darker than the background, you might do:
939 my $im = $chart->draw
943 patchborder => undef,
944 orientation => 'horizontal',
945 fill => { solid => Imager::Color->new(0, 0, 0, 32), }
951 defines attributes for graph callouts, if any are present. eg. if the
952 pie graph cannot fit the label into the pie graph segement it will
953 present it as a callout.
963 the text attributes of the callout label. Inherited from I<text>.
967 the color of the callout lines. Inherited from I<line>
973 the length of the leader on the inside and the outside of the fill,
974 usually at some angle. Both default to the size of the callout text.
978 the length of the horizontal portion of the leader. Default:
983 the gap between the callout leader and the callout text. Defaults to
984 30% of the text callout size.
990 defines attributes for labels drawn into the data areas of a graph.
1000 The text attributes of the labels. Inherited from I<text>.
1006 the attributes of the graph's drop shadow
1012 the fill used for the drop shadow. Default: '404040' (dark gray)
1016 the offset of the drop shadow. A convenience value inherited by offx
1017 and offy. Default: 40% of I<text.size>.
1023 the horizontal and vertical offsets of the drop shadow. Both
1024 inherited from I<dropshadow.off>.
1028 the filter description passed to Imager's filter method to blur the
1029 drop shadow. Default: an 11 element convolution filter.
1035 describes the lines drawn around filled data areas, such as the
1036 segments of a pie chart.
1042 the line color of the outlines, inherited from I<line>.
1048 a reference to an array containing fills for each data item.
1050 You can mix fill types, ie. using a simple color for the first item, a
1051 hatched fill for the second and a fountain fill for the next.
1055 =head1 HOW VALUES WORK
1057 Internally rather than specifying literal color, fill, or font objects
1058 or literal sizes for each element, Imager::Graph uses a number of
1059 special values to inherit or modify values taken from other graph
1062 =head2 Specifying colors
1064 You can specify colors by either supplying an Imager::Color object, by
1065 supplying lookup of another color, or by supplying a single value that
1066 Imager::Color::new can use as an initializer. The most obvious is
1067 just a 6 or 8 digit hex value representing the red, green, blue and
1068 optionally alpha channels of the image.
1070 You can lookup another color by using the lookup() "function", for
1071 example if you give a color as "lookup(fg)" then Imager::Graph will
1072 look for the fg element in the current style (or as overridden by
1073 you.) This is used internally by Imager::Graph to set up the
1074 relationships between the colors of various elements, for example the
1075 default style information contains:
1078 color=>'lookup(fg)',
1082 color=>'lookup(text.color)',
1086 So by setting the I<fg> color, you also set the default text color,
1087 since each text element uses lookup(text.color) as its value.
1089 =head2 Specifying fills
1091 Fills can be used for the graph background color, the background color
1092 for the legend block and for the fills used for each data element.
1094 You can specify a fill as a L<color value|Specifying colors> or as a
1095 general fill, see L<Imager::Fill> for details.
1097 You don't need (or usually want) to call Imager::Fill::new yourself,
1098 since the various fill functions will call it for you, and
1099 Imager::Graph provides some hooks to make them more useful.
1105 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
1106 Imager::Graph will supply the current graph fg and bg colors.
1110 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
1111 and yb_ratio parameters, and they will be scaled in the fill area to
1112 define the fountain fills xa, ya, xb and yb parameters.
1116 As with colors, you can use lookup(name) or lookup(name1.name2) to
1117 have one element to inherit the fill of another.
1119 Imager::Graph defaults the fill combine value to C<'normal'>. This
1120 doesn't apply to simple color fills.
1122 =head2 Specifying numbers
1124 You can specify various numbers, usually representing the size of
1125 something, commonly text, but sometimes the length of a line or the
1128 You can use the same lookup mechanism as with colors and fills, but
1129 you can also scale values. For example, 'scale(0.5,text.size)' will
1130 return half the size of the normal text size.
1132 As with colors, this is used internally to scale graph elements based
1133 on the base text size. If you change the base text size then other
1134 graph elements will scale as well.
1136 =head2 Specifying other elements
1138 Other elements, such as fonts, or parameters for a filter, can also
1139 use the lookup(name) mechanism.
1141 =head1 INTERNAL METHODS
1143 Only useful if you need to fix bugs, add features or create a new
1152 back=> 'lookup(bg)',
1153 line=> 'lookup(fg)',
1155 color => 'lookup(fg)',
1156 font => 'lookup(font)',
1160 color => 'lookup(text.color)',
1161 font => 'lookup(text.font)',
1164 size => 'scale(text.size,2.0)',
1167 color => 'lookup(text.color)',
1168 font => 'lookup(text.font)',
1169 size => 'lookup(text.size)',
1170 patchsize => 'scale(legend.size,0.9)',
1171 patchgap => 'scale(legend.patchsize,0.3)',
1172 patchborder => 'lookup(line)',
1175 padding => 'scale(legend.size,0.3)',
1176 outsidepadding => 'scale(legend.padding,0.4)',
1179 color => 'lookup(text.color)',
1180 font => 'lookup(text.font)',
1181 size => 'lookup(text.size)',
1182 line => 'lookup(line)',
1183 inside => 'lookup(callout.size)',
1184 outside => 'lookup(callout.size)',
1185 leadlen => 'scale(0.8,callout.size)',
1186 gap => 'scale(callout.size,0.3)',
1189 font => 'lookup(text.font)',
1190 size => 'lookup(text.size)',
1191 color => 'lookup(text.color)',
1192 hpad => 'lookup(label.pad)',
1193 vpad => 'lookup(label.pad)',
1194 pad => 'scale(label.size,0.2)',
1195 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
1196 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
1199 fill => { solid => Imager::Color->new(0, 0, 0, 96) },
1200 off => 'scale(0.4,text.size)',
1201 offx => 'lookup(dropshadow.off)',
1202 offy => 'lookup(dropshadow.off)',
1203 filter => { type=>'conv',
1204 # this needs a fairly heavy blur
1205 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
1206 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
1209 line =>'lookup(line)',
1212 width=>'scale(1.5,size)',
1213 height=>'lookup(size)',
1216 =item _error($message)
1218 Sets the error field of the object and returns an empty list or undef,
1219 depending on context. Should be used for error handling, since it may
1220 provide some user hooks at some point.
1222 The intended usage is:
1225 or return $self->_error("error description");
1227 You should almost always return the result of _error() or return
1228 immediately afterwards.
1233 my ($self, $error) = @_;
1235 $self->{_errstr} = $error;
1243 Returns the style defaults, such as the relationships between line
1244 color and text color.
1246 Intended to be over-ridden by base classes to provide graph specific
1255 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
1256 my $def_style = 'fount_lin';
1264 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1267 negative_bg=>'EEEEEE',
1271 #patchborder=>'000000'
1278 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1281 negative_bg=>'EEEEEE',
1285 patchborder=>'000000'
1292 { hatch=>'slash2' },
1293 { hatch=>'slosh2' },
1294 { hatch=>'vline2' },
1295 { hatch=>'hline2' },
1296 { hatch=>'cross2' },
1298 { hatch=>'stipple3' },
1299 { hatch=>'stipple2' },
1304 negative_bg=>'EEEEEE',
1305 features=>{ outline=>1 },
1314 { fountain=>'linear',
1315 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
1316 segments => Imager::Fountain->simple(positions=>[0, 1],
1317 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
1319 { fountain=>'linear',
1320 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1321 segments => Imager::Fountain->simple(positions=>[0, 1],
1322 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
1324 { fountain=>'linear',
1325 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1326 segments => Imager::Fountain->simple(positions=>[0, 1],
1327 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
1329 { fountain=>'linear',
1330 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1331 segments => Imager::Fountain->simple(positions=>[0, 1],
1332 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
1334 { fountain=>'linear',
1335 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1336 segments => Imager::Fountain->simple(positions=>[0, 1],
1337 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
1339 { fountain=>'linear',
1340 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1341 segments => Imager::Fountain->simple(positions=>[0, 1],
1342 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
1346 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1348 back=>{ fountain=>'linear',
1349 xa_ratio=>0, ya_ratio=>0,
1350 xb_ratio=>1.0, yb_ratio=>1.0,
1351 segments=>Imager::Fountain->simple
1352 ( positions=>[0, 1],
1353 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1355 negative_bg=>'EEEEEE',
1357 features=>{ dropshadow=>1 },
1363 { fountain=>'radial',
1364 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1365 segments => Imager::Fountain->simple(positions=>[0, 1],
1366 colors=>[ NC('FF8080'), NC('FF0000') ]),
1368 { fountain=>'radial',
1369 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1370 segments => Imager::Fountain->simple(positions=>[0, 1],
1371 colors=>[ NC('80FF80'), NC('00FF00') ]),
1373 { fountain=>'radial',
1374 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1375 segments => Imager::Fountain->simple(positions=>[0, 1],
1376 colors=>[ NC('808080FF'), NC('0000FF') ]),
1378 { fountain=>'radial',
1379 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1380 segments => Imager::Fountain->simple(positions=>[0, 1],
1381 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
1383 { fountain=>'radial',
1384 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1385 segments => Imager::Fountain->simple(positions=>[0, 1],
1386 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
1388 { fountain=>'radial',
1389 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1390 segments => Imager::Fountain->simple(positions=>[0, 1],
1391 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1395 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1397 back=>{ fountain=>'linear',
1398 xa_ratio=>0, ya_ratio=>0,
1399 xb_ratio=>1.0, yb_ratio=>1.0,
1400 segments=>Imager::Fountain->simple
1401 ( positions=>[0, 1],
1402 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1404 negative_bg=>'EEEEEE',
1409 $styles{'ocean'} = {
1412 fountain =>'linear',
1413 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1414 segments => Imager::Fountain->simple(
1416 colors=>[ NC('FFFFFF'), NC('E6E2AF') ]),
1419 fountain =>'linear',
1420 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1421 segments => Imager::Fountain->simple(
1423 colors=>[ NC('FFFFFF'), NC('A7A37E') ]),
1426 fountain =>'linear',
1427 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1428 segments => Imager::Fountain->simple(
1430 colors=>[ NC('FFFFFF'), NC('80B4A2') ]),
1433 fountain =>'linear',
1434 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1435 segments => Imager::Fountain->simple(
1437 colors=>[ NC('FFFFFF'), NC('046380') ]),
1440 fountain =>'linear',
1441 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1442 segments => Imager::Fountain->simple(
1444 colors=>[ NC('FFFFFF'), NC('877EA7') ]),
1447 fountain =>'linear',
1448 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1449 segments => Imager::Fountain->simple(
1451 colors=>[ NC('FFFFFF'), NC('67A35E') ]),
1454 fountain =>'linear',
1455 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1456 segments => Imager::Fountain->simple(
1458 colors=>[ NC('FFFFFF'), NC('B4726F') ]),
1462 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1465 negative_bg=>'EEEEEE',
1467 features=>{ dropshadow=>1 },
1471 =item $self->_style_setup(\%opts)
1473 Uses the values from %opts to build a customized hash describing the
1474 way the graph should be drawn.
1479 my ($self, $opts) = @_;
1480 my $style_defs = $self->_style_defs;
1483 my $pre_def_style = $self->_get_style($opts);
1484 my $api_style = $self->{'custom_style'} || {};
1485 $style = $styles{$pre_def_style} if $pre_def_style;
1487 $style ||= $styles{$def_style};
1489 my @search_list = ( $style_defs, $style, $api_style, $opts);
1492 my @composite = $self->_composite();
1494 @composite{@composite} = @composite;
1496 for my $src (@search_list) {
1497 for my $key (keys %$src) {
1498 if ($composite{$key}) {
1499 $work{$key} = {} unless exists $work{$key};
1500 if (ref $src->{$key}) {
1501 # some keys have sub values, especially text
1502 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1505 # assume it's the text for a title or something
1506 $work{$key}{text} = $src->{$key};
1510 $work{$key} = $src->{$key}
1511 if defined $src->{$key}; # $opts with pmichauds new accessor handling
1516 # features are handled specially
1517 $work{features} = {};
1518 for my $src (@search_list) {
1519 if ($src->{features}) {
1520 if (ref $src->{features}) {
1521 if (ref($src->{features}) =~ /ARRAY/) {
1522 # just set those features
1523 for my $feature (@{$src->{features}}) {
1524 $work{features}{$feature} = 1;
1527 elsif (ref($src->{features}) =~ /HASH/) {
1528 if ($src->{features}{reset}) {
1529 $work{features} = {}; # only the ones the user specifies
1531 @{$work{features}}{keys %{$src->{features}}} =
1532 values(%{$src->{features}});
1536 # just set that single feature
1537 $work{features}{$src->{features}} = 1;
1542 #print Dumper(\%work);
1544 $self->{_style} = \%work;
1547 =item $self->_get_thing($name)
1549 Retrieve some general 'thing'.
1551 Supports the 'lookup(foo)' mechanism.
1553 Returns an empty list on failure.
1558 my ($self, $name, @depth) = @_;
1560 push(@depth, $name);
1562 if ($name =~ /^(\w+)\.(\w+)$/) {
1563 $what = $self->{_style}{$1}{$2};
1566 $what = $self->{_style}{$name};
1573 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1575 or return $self->_error("too many levels of recursion in lookup(@depth)");
1576 return $self->_get_thing($1, @depth);
1583 =item $self->_get_number($name)
1585 Retrieves a number from the style. The value in the style can be the
1586 number, or one of two functions:
1590 =item lookup(newname)
1592 Recursively looks up I<newname> in the style.
1594 =item scale(value1,value2)
1596 Each value can be a number or a name. Names are recursively looked up
1597 in the style and the product is returned.
1604 my ($self, $name, @depth) = @_;
1606 push(@depth, $name);
1608 if ($name =~ /^(\w+)\.(\w+)$/) {
1609 $what = $self->{_style}{$1}{$2};
1612 $what = $self->{_style}{$name};
1615 return $self->_error("$name is undef (@depth)");
1618 if ($what =~ /CODE/) {
1619 $what = $what->($self, $name);
1623 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1625 or return $self->_error("too many levels of recursion in lookup (@depth)");
1626 return $self->_get_number($1, @depth);
1628 elsif ($what =~ /^scale\(
1629 ((?:[a-z][\w.]*)|$NUM_RE)
1631 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1632 my ($left, $right) = ($1, $2);
1633 unless ($left =~ /^$NUM_RE$/) {
1635 or return $self->_error("too many levels of recursion in scale (@depth)");
1636 $left = $self->_get_number($left, @depth);
1638 unless ($right =~ /^$NUM_RE$/) {
1640 or return $self->_error("too many levels of recursion in scale (@depth)");
1641 $right = $self->_get_number($right, @depth);
1643 return $left * $right;
1651 =item $self->_get_integer($name)
1653 Retrieves an integer from the style. This is a simple wrapper around
1654 _get_number() that rounds the result to an integer.
1656 Returns an empty list on failure.
1661 my ($self, $name, @depth) = @_;
1663 my $number = $self->_get_number($name, @depth)
1666 return sprintf("%.0f", $number);
1669 =item _get_color($name)
1671 Returns a color object of the given name from the style hash.
1673 Uses Imager::Color->new to translate normal scalars into color objects.
1675 Allows the lookup(name) mechanism.
1677 Returns an empty list on failure.
1682 my ($self, $name, @depth) = @_;
1684 push(@depth, $name);
1686 if ($name =~ /^(\w+)\.(\w+)$/) {
1687 $what = $self->{_style}{$1}{$2};
1690 $what = $self->{_style}{$name};
1694 or return $self->_error("$name was undefined (@depth)");
1696 unless (ref $what) {
1697 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1698 @depth < MAX_DEPTH or
1699 return $self->_error("too many levels of recursion in lookup (@depth)");
1701 return $self->_get_color($1, @depth);
1703 $what = Imager::Color->new($what);
1709 =item _translate_fill($what, $box)
1711 Given the value of a fill, either attempts to convert it into a fill
1712 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1713 parameters }>>), or to lookup another fill that is referred to with
1714 the 'lookup(name)' mechanism.
1716 This function does the fg and bg initialization for hatched fills, and
1717 translation of *_ratio for fountain fills (using the $box parameter).
1719 Returns an empty list on failure.
1723 sub _translate_fill {
1724 my ($self, $what, $box, @depth) = @_;
1727 if (UNIVERSAL::isa($what, "Imager::Color")) {
1728 return ( color=>Imager::Color->new($what), filled=>1 );
1732 # default to normal combine mode
1733 my %work = ( combine => 'normal', %$what );
1734 if ($what->{hatch}) {
1736 $work{fg} = $self->_get_color('fg')
1740 $work{bg} = $self->_get_color('bg')
1743 return ( fill=>\%work );
1745 elsif ($what->{fountain}) {
1746 for my $key (qw(xa ya xb yb)) {
1747 if (exists $work{"${key}_ratio"}) {
1749 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1750 * ($box->[2] - $box->[0]);
1753 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1754 * ($box->[3] - $box->[1]);
1758 return ( fill=>\%work );
1761 return ( fill=> \%work );
1766 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1767 return $self->_get_fill($1, $box, @depth);
1770 # assumed to be an Imager::Color single value
1771 return ( color=>Imager::Color->new($what), filled=>1 );
1776 =item _data_fill($index, $box)
1778 Retrieves the fill parameters for a data area fill.
1783 my ($self, $index, $box) = @_;
1785 my $fills = $self->{_style}{fills};
1786 return $self->_translate_fill($fills->[$index % @$fills], $box,
1791 my ($self, $index) = @_;
1793 my $colors = $self->{'_style'}{'colors'} || [];
1794 my $fills = $self->{'_style'}{'fills'} || [];
1796 # Try to just use a fill, so non-fountain styles don't need
1797 # to have a duplicated set of fills and colors
1798 my $fill = $fills->[$index % @$fills];
1804 return $colors->[$index % @$colors] || '000000';
1809 =item _get_fill($index, $box)
1811 Retrieves fill parameters for a named fill.
1816 my ($self, $name, $box, @depth) = @_;
1818 push(@depth, $name);
1820 if ($name =~ /^(\w+)\.(\w+)$/) {
1821 $what = $self->{_style}{$1}{$2};
1824 $what = $self->{_style}{$name};
1828 or return $self->_error("no fill $name found");
1830 return $self->_translate_fill($what, $box, @depth);
1835 Builds the image object for the graph and fills it with the background
1843 my $width = $self->_get_number('width') || 256;
1844 my $height = $self->_get_number('height') || 256;
1845 my $channels = $self->{_style}{channels};
1849 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1851 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1859 if (!$self->{'_image'}) {
1860 $self->{'_image'} = $self->_make_img();
1862 return $self->{'_image'};
1865 =item _text_style($name)
1867 Returns parameters suitable for calls to Imager::Font's bounding_box()
1868 and draw() methods intended for use in defining text styles.
1870 Returns an empty list on failure.
1875 my ($self, $name) = @_;
1879 if ($self->{_style}{$name}) {
1880 %work = %{$self->{_style}{$name}};
1883 %work = %{$self->{_style}{text}};
1886 or return $self->_error("$name has no font parameter");
1888 $work{font} = $self->_get_thing("$name.font")
1889 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1890 UNIVERSAL::isa($work{font}, "Imager::Font")
1891 or return $self->_error("$name.font is not a font");
1892 if ($work{color} && !ref $work{color}) {
1893 $work{color} = $self->_get_color("$name.color")
1896 $work{size} = $self->_get_number("$name.size");
1897 $work{sizew} = $self->_get_number("$name.sizew")
1903 =item _text_bbox($text, $name)
1905 Returns a bounding box for the specified $text as styled by $name.
1907 Returns an empty list on failure.
1912 my ($self, $text, $name) = @_;
1914 my %text_info = $self->_text_style($name)
1917 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1924 my ($self, $box, $chart_box, $name) = @_;
1926 my $halign = $self->{_style}{$name}{halign}
1927 or $self->_error("no halign for $name");
1928 my $valign = $self->{_style}{$name}{valign};
1930 if ($halign eq 'right') {
1931 $box->[0] += $chart_box->[2] - $box->[2];
1933 elsif ($halign eq 'left') {
1934 $box->[0] = $chart_box->[0];
1936 elsif ($halign eq 'center' || $halign eq 'centre') {
1937 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1940 return $self->_error("invalid halign $halign for $name");
1943 if ($valign eq 'top') {
1944 $box->[1] = $chart_box->[1];
1946 elsif ($valign eq 'bottom') {
1947 $box->[1] = $chart_box->[3] - $box->[3];
1949 elsif ($valign eq 'center' || $valign eq 'centre') {
1950 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1953 return $self->_error("invalid valign $valign for $name");
1955 $box->[2] += $box->[0];
1956 $box->[3] += $box->[1];
1960 my ($self, $chart_box, $object_box) = @_;
1964 if ($object_box->[0] - $chart_box->[0]
1965 < $chart_box->[2] - $object_box->[2]) {
1966 $areax = ($object_box->[2] - $chart_box->[0])
1967 * ($chart_box->[3] - $chart_box->[1]);
1970 $areax = ($chart_box->[2] - $object_box->[0])
1971 * ($chart_box->[3] - $chart_box->[1]);
1974 if ($object_box->[1] - $chart_box->[1]
1975 < $chart_box->[3] - $object_box->[3]) {
1976 $areay = ($object_box->[3] - $chart_box->[1])
1977 * ($chart_box->[2] - $chart_box->[0]);
1980 $areay = ($chart_box->[3] - $object_box->[1])
1981 * ($chart_box->[2] - $chart_box->[0]);
1984 if ($areay < $areax) {
1985 if ($object_box->[1] - $chart_box->[1]
1986 < $chart_box->[3] - $object_box->[3]) {
1987 $chart_box->[1] = $object_box->[3];
1990 $chart_box->[3] = $object_box->[1];
1994 if ($object_box->[0] - $chart_box->[0]
1995 < $chart_box->[2] - $object_box->[2]) {
1996 $chart_box->[0] = $object_box->[2];
1999 $chart_box->[2] = $object_box->[0];
2005 my ($self, $img, $labels, $chart_box) = @_;
2007 my $orient = $self->_get_thing('legend.orientation');
2008 defined $orient or $orient = 'vertical';
2010 if ($orient eq 'vertical') {
2011 return $self->_draw_legend_vertical($img, $labels, $chart_box);
2013 elsif ($orient eq 'horizontal') {
2014 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
2017 return $self->_error("Unknown legend.orientation $orient");
2021 sub _draw_legend_horizontal {
2022 my ($self, $img, $labels, $chart_box) = @_;
2024 defined(my $padding = $self->_get_integer('legend.padding'))
2026 my $patchsize = $self->_get_integer('legend.patchsize')
2028 defined(my $gap = $self->_get_integer('legend.patchgap'))
2031 my $minrowsize = $patchsize + $gap;
2032 my ($width, $height) = (0,0);
2033 my $row_height = $minrowsize;
2037 for my $label (@$labels) {
2038 my @text_box = $self->_text_bbox($label, 'legend')
2040 push(@sizes, \@text_box);
2041 my $entry_width = $patchsize + $gap + $text_box[2];
2043 # never re-wrap the first entry
2044 push @offsets, [ 0, $height ];
2047 if ($pos + $gap + $entry_width > $chart_box->[2]) {
2049 $height += $row_height;
2051 push @offsets, [ $pos, $height ];
2053 my $entry_right = $pos + $entry_width;
2054 $pos += $gap + $entry_width;
2055 $entry_right > $width and $width = $entry_right;
2056 if ($text_box[3] > $row_height) {
2057 $row_height = $text_box[3];
2060 $height += $row_height;
2061 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
2062 my $outsidepadding = 0;
2063 if ($self->{_style}{legend}{border}) {
2064 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2066 $box[2] += 2 * $outsidepadding;
2067 $box[3] += 2 * $outsidepadding;
2069 $self->_align_box(\@box, $chart_box, 'legend')
2071 if ($self->{_style}{legend}{fill}) {
2072 $img->box(xmin=>$box[0]+$outsidepadding,
2073 ymin=>$box[1]+$outsidepadding,
2074 xmax=>$box[2]-$outsidepadding,
2075 ymax=>$box[3]-$outsidepadding,
2076 $self->_get_fill('legend.fill', \@box));
2078 $box[0] += $outsidepadding;
2079 $box[1] += $outsidepadding;
2080 $box[2] -= $outsidepadding;
2081 $box[3] -= $outsidepadding;
2082 my %text_info = $self->_text_style('legend')
2085 if ($self->{_style}{legend}{patchborder}) {
2086 $patchborder = $self->_get_color('legend.patchborder')
2091 for my $label (@$labels) {
2092 my ($left, $top) = @{$offsets[$dataindex]};
2093 $left += $box[0] + $padding;
2094 $top += $box[1] + $padding;
2095 my $textpos = $left + $patchsize + $gap;
2096 my @patchbox = ( $left, $top,
2097 $left + $patchsize, $top + $patchsize );
2098 my @fill = $self->_data_fill($dataindex, \@patchbox)
2100 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2101 ymax=>$top + $patchsize, @fill);
2102 if ($self->{_style}{legend}{patchborder}) {
2103 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2104 ymax=>$top + $patchsize,
2105 color=>$patchborder);
2107 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
2112 if ($self->{_style}{legend}{border}) {
2113 my $border_color = $self->_get_color('legend.border')
2115 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2116 color=>$border_color);
2118 $self->_remove_box($chart_box, \@box);
2122 sub _draw_legend_vertical {
2123 my ($self, $img, $labels, $chart_box) = @_;
2125 defined(my $padding = $self->_get_integer('legend.padding'))
2127 my $patchsize = $self->_get_integer('legend.patchsize')
2129 defined(my $gap = $self->_get_integer('legend.patchgap'))
2131 my $minrowsize = $patchsize + $gap;
2132 my ($width, $height) = (0,0);
2134 for my $label (@$labels) {
2135 my @box = $self->_text_bbox($label, 'legend')
2137 push(@sizes, \@box);
2138 $width = $box[2] if $box[2] > $width;
2139 if ($minrowsize > $box[3]) {
2140 $height += $minrowsize;
2147 $width + $patchsize + $padding * 2 + $gap,
2148 $height + $padding * 2 - $gap);
2149 my $outsidepadding = 0;
2150 if ($self->{_style}{legend}{border}) {
2151 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2153 $box[2] += 2 * $outsidepadding;
2154 $box[3] += 2 * $outsidepadding;
2156 $self->_align_box(\@box, $chart_box, 'legend')
2158 if ($self->{_style}{legend}{fill}) {
2159 $img->box(xmin=>$box[0]+$outsidepadding,
2160 ymin=>$box[1]+$outsidepadding,
2161 xmax=>$box[2]-$outsidepadding,
2162 ymax=>$box[3]-$outsidepadding,
2163 $self->_get_fill('legend.fill', \@box));
2165 $box[0] += $outsidepadding;
2166 $box[1] += $outsidepadding;
2167 $box[2] -= $outsidepadding;
2168 $box[3] -= $outsidepadding;
2169 my $ypos = $box[1] + $padding;
2170 my $patchpos = $box[0]+$padding;
2171 my $textpos = $patchpos + $patchsize + $gap;
2172 my %text_info = $self->_text_style('legend')
2175 if ($self->{_style}{legend}{patchborder}) {
2176 $patchborder = $self->_get_color('legend.patchborder')
2180 for my $label (@$labels) {
2181 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
2182 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
2185 if ($self->_draw_flat_legend()) {
2186 @fill = (color => $self->_data_color($dataindex), filled => 1);
2189 @fill = $self->_data_fill($dataindex, \@patchbox)
2192 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2193 ymax=>$ypos + $patchsize, @fill);
2194 if ($self->{_style}{legend}{patchborder}) {
2195 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2196 ymax=>$ypos + $patchsize,
2197 color=>$patchborder);
2199 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
2202 my $step = $patchsize + $gap;
2203 if ($minrowsize < $sizes[$dataindex][3]) {
2204 $ypos += $sizes[$dataindex][3];
2207 $ypos += $minrowsize;
2211 if ($self->{_style}{legend}{border}) {
2212 my $border_color = $self->_get_color('legend.border')
2214 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2215 color=>$border_color);
2217 $self->_remove_box($chart_box, \@box);
2222 my ($self, $img, $chart_box) = @_;
2224 my $title = $self->{_style}{title}{text};
2225 my @box = $self->_text_bbox($title, 'title')
2229 $self->_align_box(\@box, $chart_box, 'title');
2230 my %text_info = $self->_text_style('title')
2232 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
2233 $self->_remove_box($chart_box, \@box);
2238 my ($self, $box) = @_;
2240 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
2241 return $box->[3] - $box->[1];
2244 return $box->[2] - $box->[0];
2248 sub _draw_flat_legend {
2254 Returns a list of style fields that are stored as composites, and
2255 should be merged instead of just being replaced.
2260 qw(title legend text label dropshadow outline callout);
2263 sub _filter_region {
2264 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
2266 unless (ref $filter) {
2268 $filter = $self->_get_thing($name)
2271 or return $self->_error("no type for filter $name");
2274 $left > 0 or $left = 0;
2275 $top > 0 or $top = 0;
2277 # newer versions of Imager let you work on just part of an image
2278 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
2279 my $masked = $img->masked(left=>$left, top=>$top,
2280 right=>$right, bottom=>$bottom);
2281 $masked->filter(%$filter);
2284 # for older versions of Imager
2285 my $subset = $img->crop(left=>$left, top=>$top,
2286 right=>$right, bottom=>$bottom);
2287 $subset->filter(%$filter);
2288 $img->paste(left=>$left, top=>$top, img=>$subset);
2299 Imager::Graph::Pie(3), Imager(3), perl(1).
2303 Tony Cook <tony@develop-help.com>
2307 Imager::Graph is licensed under the same terms as perl itself.
2311 Addi for producing a cool imaging module. :)