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)
1349 { shape => 'circle', radius => 4 },
1350 { shape => 'square', radius => 4 },
1351 { shape => 'diamond', radius => 4 },
1352 { shape => 'triangle', radius => 4 },
1353 { shape => 'x', radius => 4 },
1354 { shape => 'plus', radius => 4 },
1356 back=>{ fountain=>'linear',
1357 xa_ratio=>0, ya_ratio=>0,
1358 xb_ratio=>1.0, yb_ratio=>1.0,
1359 segments=>Imager::Fountain->simple
1360 ( positions=>[0, 1],
1361 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1363 negative_bg=>'EEEEEE',
1365 features=>{ dropshadow=>1 },
1371 { fountain=>'radial',
1372 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1373 segments => Imager::Fountain->simple(positions=>[0, 1],
1374 colors=>[ NC('FF8080'), NC('FF0000') ]),
1376 { fountain=>'radial',
1377 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1378 segments => Imager::Fountain->simple(positions=>[0, 1],
1379 colors=>[ NC('80FF80'), NC('00FF00') ]),
1381 { fountain=>'radial',
1382 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1383 segments => Imager::Fountain->simple(positions=>[0, 1],
1384 colors=>[ NC('808080FF'), NC('0000FF') ]),
1386 { fountain=>'radial',
1387 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1388 segments => Imager::Fountain->simple(positions=>[0, 1],
1389 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
1391 { fountain=>'radial',
1392 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1393 segments => Imager::Fountain->simple(positions=>[0, 1],
1394 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
1396 { fountain=>'radial',
1397 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1398 segments => Imager::Fountain->simple(positions=>[0, 1],
1399 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1403 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1405 back=>{ fountain=>'linear',
1406 xa_ratio=>0, ya_ratio=>0,
1407 xb_ratio=>1.0, yb_ratio=>1.0,
1408 segments=>Imager::Fountain->simple
1409 ( positions=>[0, 1],
1410 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1412 negative_bg=>'EEEEEE',
1417 $styles{'ocean'} = {
1420 fountain =>'linear',
1421 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1422 segments => Imager::Fountain->simple(
1424 colors=>[ NC('FFFFFF'), NC('E6E2AF') ]),
1427 fountain =>'linear',
1428 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1429 segments => Imager::Fountain->simple(
1431 colors=>[ NC('FFFFFF'), NC('A7A37E') ]),
1434 fountain =>'linear',
1435 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1436 segments => Imager::Fountain->simple(
1438 colors=>[ NC('FFFFFF'), NC('80B4A2') ]),
1441 fountain =>'linear',
1442 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1443 segments => Imager::Fountain->simple(
1445 colors=>[ NC('FFFFFF'), NC('046380') ]),
1448 fountain =>'linear',
1449 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1450 segments => Imager::Fountain->simple(
1452 colors=>[ NC('FFFFFF'), NC('877EA7') ]),
1455 fountain =>'linear',
1456 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1457 segments => Imager::Fountain->simple(
1459 colors=>[ NC('FFFFFF'), NC('67A35E') ]),
1462 fountain =>'linear',
1463 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1464 segments => Imager::Fountain->simple(
1466 colors=>[ NC('FFFFFF'), NC('B4726F') ]),
1470 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1473 negative_bg=>'EEEEEE',
1475 features=>{ dropshadow=>1 },
1479 =item $self->_style_setup(\%opts)
1481 Uses the values from %opts to build a customized hash describing the
1482 way the graph should be drawn.
1487 my ($self, $opts) = @_;
1488 my $style_defs = $self->_style_defs;
1491 my $pre_def_style = $self->_get_style($opts);
1492 my $api_style = $self->{'custom_style'} || {};
1493 $style = $styles{$pre_def_style} if $pre_def_style;
1495 $style ||= $styles{$def_style};
1497 my @search_list = ( $style_defs, $style, $api_style, $opts);
1500 my @composite = $self->_composite();
1502 @composite{@composite} = @composite;
1504 for my $src (@search_list) {
1505 for my $key (keys %$src) {
1506 if ($composite{$key}) {
1507 $work{$key} = {} unless exists $work{$key};
1508 if (ref $src->{$key}) {
1509 # some keys have sub values, especially text
1510 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1513 # assume it's the text for a title or something
1514 $work{$key}{text} = $src->{$key};
1518 $work{$key} = $src->{$key}
1519 if defined $src->{$key}; # $opts with pmichauds new accessor handling
1524 # features are handled specially
1525 $work{features} = {};
1526 for my $src (@search_list) {
1527 if ($src->{features}) {
1528 if (ref $src->{features}) {
1529 if (ref($src->{features}) =~ /ARRAY/) {
1530 # just set those features
1531 for my $feature (@{$src->{features}}) {
1532 $work{features}{$feature} = 1;
1535 elsif (ref($src->{features}) =~ /HASH/) {
1536 if ($src->{features}{reset}) {
1537 $work{features} = {}; # only the ones the user specifies
1539 @{$work{features}}{keys %{$src->{features}}} =
1540 values(%{$src->{features}});
1544 # just set that single feature
1545 $work{features}{$src->{features}} = 1;
1550 #print Dumper(\%work);
1552 $self->{_style} = \%work;
1555 =item $self->_get_thing($name)
1557 Retrieve some general 'thing'.
1559 Supports the 'lookup(foo)' mechanism.
1561 Returns an empty list on failure.
1566 my ($self, $name, @depth) = @_;
1568 push(@depth, $name);
1570 if ($name =~ /^(\w+)\.(\w+)$/) {
1571 $what = $self->{_style}{$1}{$2};
1574 $what = $self->{_style}{$name};
1581 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1583 or return $self->_error("too many levels of recursion in lookup(@depth)");
1584 return $self->_get_thing($1, @depth);
1591 =item $self->_get_number($name)
1593 Retrieves a number from the style. The value in the style can be the
1594 number, or one of two functions:
1598 =item lookup(newname)
1600 Recursively looks up I<newname> in the style.
1602 =item scale(value1,value2)
1604 Each value can be a number or a name. Names are recursively looked up
1605 in the style and the product is returned.
1612 my ($self, $name, @depth) = @_;
1614 push(@depth, $name);
1616 if ($name =~ /^(\w+)\.(\w+)$/) {
1617 $what = $self->{_style}{$1}{$2};
1620 $what = $self->{_style}{$name};
1623 return $self->_error("$name is undef (@depth)");
1626 if ($what =~ /CODE/) {
1627 $what = $what->($self, $name);
1631 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1633 or return $self->_error("too many levels of recursion in lookup (@depth)");
1634 return $self->_get_number($1, @depth);
1636 elsif ($what =~ /^scale\(
1637 ((?:[a-z][\w.]*)|$NUM_RE)
1639 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1640 my ($left, $right) = ($1, $2);
1641 unless ($left =~ /^$NUM_RE$/) {
1643 or return $self->_error("too many levels of recursion in scale (@depth)");
1644 $left = $self->_get_number($left, @depth);
1646 unless ($right =~ /^$NUM_RE$/) {
1648 or return $self->_error("too many levels of recursion in scale (@depth)");
1649 $right = $self->_get_number($right, @depth);
1651 return $left * $right;
1659 =item $self->_get_integer($name)
1661 Retrieves an integer from the style. This is a simple wrapper around
1662 _get_number() that rounds the result to an integer.
1664 Returns an empty list on failure.
1669 my ($self, $name, @depth) = @_;
1671 my $number = $self->_get_number($name, @depth)
1674 return sprintf("%.0f", $number);
1677 =item _get_color($name)
1679 Returns a color object of the given name from the style hash.
1681 Uses Imager::Color->new to translate normal scalars into color objects.
1683 Allows the lookup(name) mechanism.
1685 Returns an empty list on failure.
1690 my ($self, $name, @depth) = @_;
1692 push(@depth, $name);
1694 if ($name =~ /^(\w+)\.(\w+)$/) {
1695 $what = $self->{_style}{$1}{$2};
1698 $what = $self->{_style}{$name};
1702 or return $self->_error("$name was undefined (@depth)");
1704 unless (ref $what) {
1705 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1706 @depth < MAX_DEPTH or
1707 return $self->_error("too many levels of recursion in lookup (@depth)");
1709 return $self->_get_color($1, @depth);
1711 $what = Imager::Color->new($what);
1717 =item _translate_fill($what, $box)
1719 Given the value of a fill, either attempts to convert it into a fill
1720 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1721 parameters }>>), or to lookup another fill that is referred to with
1722 the 'lookup(name)' mechanism.
1724 This function does the fg and bg initialization for hatched fills, and
1725 translation of *_ratio for fountain fills (using the $box parameter).
1727 Returns an empty list on failure.
1731 sub _translate_fill {
1732 my ($self, $what, $box, @depth) = @_;
1735 if (UNIVERSAL::isa($what, "Imager::Color")) {
1736 return ( color=>Imager::Color->new($what), filled=>1 );
1740 # default to normal combine mode
1741 my %work = ( combine => 'normal', %$what );
1742 if ($what->{hatch}) {
1744 $work{fg} = $self->_get_color('fg')
1748 $work{bg} = $self->_get_color('bg')
1751 return ( fill=>\%work );
1753 elsif ($what->{fountain}) {
1754 for my $key (qw(xa ya xb yb)) {
1755 if (exists $work{"${key}_ratio"}) {
1757 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1758 * ($box->[2] - $box->[0]);
1761 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1762 * ($box->[3] - $box->[1]);
1766 return ( fill=>\%work );
1769 return ( fill=> \%work );
1774 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1775 return $self->_get_fill($1, $box, @depth);
1778 # assumed to be an Imager::Color single value
1779 return ( color=>Imager::Color->new($what), filled=>1 );
1784 =item _data_fill($index, $box)
1786 Retrieves the fill parameters for a data area fill.
1791 my ($self, $index, $box) = @_;
1793 my $fills = $self->{_style}{fills};
1794 return $self->_translate_fill($fills->[$index % @$fills], $box,
1799 my ($self, $index) = @_;
1801 my $colors = $self->{'_style'}{'colors'} || [];
1802 my $fills = $self->{'_style'}{'fills'} || [];
1804 # Try to just use a fill, so non-fountain styles don't need
1805 # to have a duplicated set of fills and colors
1806 my $fill = $fills->[$index % @$fills];
1812 return $colors->[$index % @$colors] || '000000';
1817 =item _get_fill($index, $box)
1819 Retrieves fill parameters for a named fill.
1824 my ($self, $name, $box, @depth) = @_;
1826 push(@depth, $name);
1828 if ($name =~ /^(\w+)\.(\w+)$/) {
1829 $what = $self->{_style}{$1}{$2};
1832 $what = $self->{_style}{$name};
1836 or return $self->_error("no fill $name found");
1838 return $self->_translate_fill($what, $box, @depth);
1843 Builds the image object for the graph and fills it with the background
1851 my $width = $self->_get_number('width') || 256;
1852 my $height = $self->_get_number('height') || 256;
1853 my $channels = $self->{_style}{channels};
1857 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1859 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1867 if (!$self->{'_image'}) {
1868 $self->{'_image'} = $self->_make_img();
1870 return $self->{'_image'};
1873 =item _text_style($name)
1875 Returns parameters suitable for calls to Imager::Font's bounding_box()
1876 and draw() methods intended for use in defining text styles.
1878 Returns an empty list on failure.
1883 my ($self, $name) = @_;
1887 if ($self->{_style}{$name}) {
1888 %work = %{$self->{_style}{$name}};
1891 %work = %{$self->{_style}{text}};
1894 or return $self->_error("$name has no font parameter");
1896 $work{font} = $self->_get_thing("$name.font")
1897 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1898 UNIVERSAL::isa($work{font}, "Imager::Font")
1899 or return $self->_error("$name.font is not a font");
1900 if ($work{color} && !ref $work{color}) {
1901 $work{color} = $self->_get_color("$name.color")
1904 $work{size} = $self->_get_number("$name.size");
1905 $work{sizew} = $self->_get_number("$name.sizew")
1911 =item _text_bbox($text, $name)
1913 Returns a bounding box for the specified $text as styled by $name.
1915 Returns an empty list on failure.
1920 my ($self, $text, $name) = @_;
1922 my %text_info = $self->_text_style($name)
1925 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1932 my ($self, $box, $chart_box, $name) = @_;
1934 my $halign = $self->{_style}{$name}{halign}
1935 or $self->_error("no halign for $name");
1936 my $valign = $self->{_style}{$name}{valign};
1938 if ($halign eq 'right') {
1939 $box->[0] += $chart_box->[2] - $box->[2];
1941 elsif ($halign eq 'left') {
1942 $box->[0] = $chart_box->[0];
1944 elsif ($halign eq 'center' || $halign eq 'centre') {
1945 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1948 return $self->_error("invalid halign $halign for $name");
1951 if ($valign eq 'top') {
1952 $box->[1] = $chart_box->[1];
1954 elsif ($valign eq 'bottom') {
1955 $box->[1] = $chart_box->[3] - $box->[3];
1957 elsif ($valign eq 'center' || $valign eq 'centre') {
1958 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
1961 return $self->_error("invalid valign $valign for $name");
1963 $box->[2] += $box->[0];
1964 $box->[3] += $box->[1];
1968 my ($self, $chart_box, $object_box) = @_;
1972 if ($object_box->[0] - $chart_box->[0]
1973 < $chart_box->[2] - $object_box->[2]) {
1974 $areax = ($object_box->[2] - $chart_box->[0])
1975 * ($chart_box->[3] - $chart_box->[1]);
1978 $areax = ($chart_box->[2] - $object_box->[0])
1979 * ($chart_box->[3] - $chart_box->[1]);
1982 if ($object_box->[1] - $chart_box->[1]
1983 < $chart_box->[3] - $object_box->[3]) {
1984 $areay = ($object_box->[3] - $chart_box->[1])
1985 * ($chart_box->[2] - $chart_box->[0]);
1988 $areay = ($chart_box->[3] - $object_box->[1])
1989 * ($chart_box->[2] - $chart_box->[0]);
1992 if ($areay < $areax) {
1993 if ($object_box->[1] - $chart_box->[1]
1994 < $chart_box->[3] - $object_box->[3]) {
1995 $chart_box->[1] = $object_box->[3];
1998 $chart_box->[3] = $object_box->[1];
2002 if ($object_box->[0] - $chart_box->[0]
2003 < $chart_box->[2] - $object_box->[2]) {
2004 $chart_box->[0] = $object_box->[2];
2007 $chart_box->[2] = $object_box->[0];
2013 my ($self, $img, $labels, $chart_box) = @_;
2015 my $orient = $self->_get_thing('legend.orientation');
2016 defined $orient or $orient = 'vertical';
2018 if ($orient eq 'vertical') {
2019 return $self->_draw_legend_vertical($img, $labels, $chart_box);
2021 elsif ($orient eq 'horizontal') {
2022 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
2025 return $self->_error("Unknown legend.orientation $orient");
2029 sub _draw_legend_horizontal {
2030 my ($self, $img, $labels, $chart_box) = @_;
2032 defined(my $padding = $self->_get_integer('legend.padding'))
2034 my $patchsize = $self->_get_integer('legend.patchsize')
2036 defined(my $gap = $self->_get_integer('legend.patchgap'))
2039 my $minrowsize = $patchsize + $gap;
2040 my ($width, $height) = (0,0);
2041 my $row_height = $minrowsize;
2045 for my $label (@$labels) {
2046 my @text_box = $self->_text_bbox($label, 'legend')
2048 push(@sizes, \@text_box);
2049 my $entry_width = $patchsize + $gap + $text_box[2];
2051 # never re-wrap the first entry
2052 push @offsets, [ 0, $height ];
2055 if ($pos + $gap + $entry_width > $chart_box->[2]) {
2057 $height += $row_height;
2059 push @offsets, [ $pos, $height ];
2061 my $entry_right = $pos + $entry_width;
2062 $pos += $gap + $entry_width;
2063 $entry_right > $width and $width = $entry_right;
2064 if ($text_box[3] > $row_height) {
2065 $row_height = $text_box[3];
2068 $height += $row_height;
2069 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
2070 my $outsidepadding = 0;
2071 if ($self->{_style}{legend}{border}) {
2072 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2074 $box[2] += 2 * $outsidepadding;
2075 $box[3] += 2 * $outsidepadding;
2077 $self->_align_box(\@box, $chart_box, 'legend')
2079 if ($self->{_style}{legend}{fill}) {
2080 $img->box(xmin=>$box[0]+$outsidepadding,
2081 ymin=>$box[1]+$outsidepadding,
2082 xmax=>$box[2]-$outsidepadding,
2083 ymax=>$box[3]-$outsidepadding,
2084 $self->_get_fill('legend.fill', \@box));
2086 $box[0] += $outsidepadding;
2087 $box[1] += $outsidepadding;
2088 $box[2] -= $outsidepadding;
2089 $box[3] -= $outsidepadding;
2090 my %text_info = $self->_text_style('legend')
2093 if ($self->{_style}{legend}{patchborder}) {
2094 $patchborder = $self->_get_color('legend.patchborder')
2099 for my $label (@$labels) {
2100 my ($left, $top) = @{$offsets[$dataindex]};
2101 $left += $box[0] + $padding;
2102 $top += $box[1] + $padding;
2103 my $textpos = $left + $patchsize + $gap;
2104 my @patchbox = ( $left, $top,
2105 $left + $patchsize, $top + $patchsize );
2106 my @fill = $self->_data_fill($dataindex, \@patchbox)
2108 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2109 ymax=>$top + $patchsize, @fill);
2110 if ($self->{_style}{legend}{patchborder}) {
2111 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2112 ymax=>$top + $patchsize,
2113 color=>$patchborder);
2115 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
2120 if ($self->{_style}{legend}{border}) {
2121 my $border_color = $self->_get_color('legend.border')
2123 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2124 color=>$border_color);
2126 $self->_remove_box($chart_box, \@box);
2130 sub _draw_legend_vertical {
2131 my ($self, $img, $labels, $chart_box) = @_;
2133 defined(my $padding = $self->_get_integer('legend.padding'))
2135 my $patchsize = $self->_get_integer('legend.patchsize')
2137 defined(my $gap = $self->_get_integer('legend.patchgap'))
2139 my $minrowsize = $patchsize + $gap;
2140 my ($width, $height) = (0,0);
2142 for my $label (@$labels) {
2143 my @box = $self->_text_bbox($label, 'legend')
2145 push(@sizes, \@box);
2146 $width = $box[2] if $box[2] > $width;
2147 if ($minrowsize > $box[3]) {
2148 $height += $minrowsize;
2155 $width + $patchsize + $padding * 2 + $gap,
2156 $height + $padding * 2 - $gap);
2157 my $outsidepadding = 0;
2158 if ($self->{_style}{legend}{border}) {
2159 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2161 $box[2] += 2 * $outsidepadding;
2162 $box[3] += 2 * $outsidepadding;
2164 $self->_align_box(\@box, $chart_box, 'legend')
2166 if ($self->{_style}{legend}{fill}) {
2167 $img->box(xmin=>$box[0]+$outsidepadding,
2168 ymin=>$box[1]+$outsidepadding,
2169 xmax=>$box[2]-$outsidepadding,
2170 ymax=>$box[3]-$outsidepadding,
2171 $self->_get_fill('legend.fill', \@box));
2173 $box[0] += $outsidepadding;
2174 $box[1] += $outsidepadding;
2175 $box[2] -= $outsidepadding;
2176 $box[3] -= $outsidepadding;
2177 my $ypos = $box[1] + $padding;
2178 my $patchpos = $box[0]+$padding;
2179 my $textpos = $patchpos + $patchsize + $gap;
2180 my %text_info = $self->_text_style('legend')
2183 if ($self->{_style}{legend}{patchborder}) {
2184 $patchborder = $self->_get_color('legend.patchborder')
2188 for my $label (@$labels) {
2189 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
2190 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
2193 if ($self->_draw_flat_legend()) {
2194 @fill = (color => $self->_data_color($dataindex), filled => 1);
2197 @fill = $self->_data_fill($dataindex, \@patchbox)
2200 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2201 ymax=>$ypos + $patchsize, @fill);
2202 if ($self->{_style}{legend}{patchborder}) {
2203 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2204 ymax=>$ypos + $patchsize,
2205 color=>$patchborder);
2207 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
2210 my $step = $patchsize + $gap;
2211 if ($minrowsize < $sizes[$dataindex][3]) {
2212 $ypos += $sizes[$dataindex][3];
2215 $ypos += $minrowsize;
2219 if ($self->{_style}{legend}{border}) {
2220 my $border_color = $self->_get_color('legend.border')
2222 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2223 color=>$border_color);
2225 $self->_remove_box($chart_box, \@box);
2230 my ($self, $img, $chart_box) = @_;
2232 my $title = $self->{_style}{title}{text};
2233 my @box = $self->_text_bbox($title, 'title')
2237 $self->_align_box(\@box, $chart_box, 'title');
2238 my %text_info = $self->_text_style('title')
2240 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
2241 $self->_remove_box($chart_box, \@box);
2246 my ($self, $box) = @_;
2248 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
2249 return $box->[3] - $box->[1];
2252 return $box->[2] - $box->[0];
2256 sub _draw_flat_legend {
2262 Returns a list of style fields that are stored as composites, and
2263 should be merged instead of just being replaced.
2268 qw(title legend text label dropshadow outline callout);
2271 sub _filter_region {
2272 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
2274 unless (ref $filter) {
2276 $filter = $self->_get_thing($name)
2279 or return $self->_error("no type for filter $name");
2282 $left > 0 or $left = 0;
2283 $top > 0 or $top = 0;
2285 # newer versions of Imager let you work on just part of an image
2286 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
2287 my $masked = $img->masked(left=>$left, top=>$top,
2288 right=>$right, bottom=>$bottom);
2289 $masked->filter(%$filter);
2292 # for older versions of Imager
2293 my $subset = $img->crop(left=>$left, top=>$top,
2294 right=>$right, bottom=>$bottom);
2295 $subset->filter(%$filter);
2296 $img->paste(left=>$left, top=>$top, img=>$subset);
2307 Imager::Graph::Pie(3), Imager(3), perl(1).
2311 Tony Cook <tony@develop-help.com>
2315 Imager::Graph is licensed under the same terms as perl itself.
2319 Addi for producing a cool imaging module. :)