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 => 'ImUgly.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)',
1156 color => 'lookup(fg)',
1157 font => 'lookup(font)',
1162 color => 'lookup(text.color)',
1163 font => 'lookup(text.font)',
1166 size => 'scale(text.size,2.0)',
1167 aa => 'lookup(text.aa)',
1170 color => 'lookup(text.color)',
1171 font => 'lookup(text.font)',
1172 aa => 'lookup(text.aa)',
1173 size => 'lookup(text.size)',
1174 patchsize => 'scale(legend.size,0.9)',
1175 patchgap => 'scale(legend.patchsize,0.3)',
1176 patchborder => 'lookup(line)',
1179 padding => 'scale(legend.size,0.3)',
1180 outsidepadding => 'scale(legend.padding,0.4)',
1183 color => 'lookup(text.color)',
1184 font => 'lookup(text.font)',
1185 size => 'lookup(text.size)',
1186 line => 'lookup(line)',
1187 inside => 'lookup(callout.size)',
1188 outside => 'lookup(callout.size)',
1189 leadlen => 'scale(0.8,callout.size)',
1190 gap => 'scale(callout.size,0.3)',
1191 aa => 'lookup(text.aa)',
1192 lineaa => 'lookup(lineaa)',
1195 font => 'lookup(text.font)',
1196 size => 'lookup(text.size)',
1197 color => 'lookup(text.color)',
1198 hpad => 'lookup(label.pad)',
1199 vpad => 'lookup(label.pad)',
1200 pad => 'scale(label.size,0.2)',
1201 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
1202 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
1203 aa => 'lookup(text.aa)',
1204 lineaa => 'lookup(lineaa)',
1207 fill => { solid => Imager::Color->new(0, 0, 0, 96) },
1208 off => 'scale(0.4,text.size)',
1209 offx => 'lookup(dropshadow.off)',
1210 offy => 'lookup(dropshadow.off)',
1211 filter => { type=>'conv',
1212 # this needs a fairly heavy blur
1213 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
1214 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
1217 line =>'lookup(line)',
1218 lineaa => 'lookup(lineaa)',
1221 width=>'scale(1.5,size)',
1222 height=>'lookup(size)',
1224 # yes, the handling of fill and line AA is inconsistent, lack of
1225 # forethought, unfortunately
1229 lineaa => 'lookup(aa)',
1232 =item _error($message)
1234 Sets the error field of the object and returns an empty list or undef,
1235 depending on context. Should be used for error handling, since it may
1236 provide some user hooks at some point.
1238 The intended usage is:
1241 or return $self->_error("error description");
1243 You should almost always return the result of _error() or return
1244 immediately afterwards.
1249 my ($self, $error) = @_;
1251 $self->{_errstr} = $error;
1259 Returns the style defaults, such as the relationships between line
1260 color and text color.
1262 Intended to be over-ridden by base classes to provide graph specific
1271 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
1272 my $def_style = 'fount_lin';
1280 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1283 negative_bg=>'EEEEEE',
1287 #patchborder=>'000000'
1294 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1297 negative_bg=>'EEEEEE',
1301 patchborder=>'000000'
1308 { hatch=>'slash2' },
1309 { hatch=>'slosh2' },
1310 { hatch=>'vline2' },
1311 { hatch=>'hline2' },
1312 { hatch=>'cross2' },
1314 { hatch=>'stipple3' },
1315 { hatch=>'stipple2' },
1320 negative_bg=>'EEEEEE',
1321 features=>{ outline=>1 },
1331 { fountain=>'linear',
1332 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
1333 segments => Imager::Fountain->simple(positions=>[0, 1],
1334 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
1336 { fountain=>'linear',
1337 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1338 segments => Imager::Fountain->simple(positions=>[0, 1],
1339 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
1341 { fountain=>'linear',
1342 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1343 segments => Imager::Fountain->simple(positions=>[0, 1],
1344 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
1346 { fountain=>'linear',
1347 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1348 segments => Imager::Fountain->simple(positions=>[0, 1],
1349 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
1351 { fountain=>'linear',
1352 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1353 segments => Imager::Fountain->simple(positions=>[0, 1],
1354 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
1356 { fountain=>'linear',
1357 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1358 segments => Imager::Fountain->simple(positions=>[0, 1],
1359 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
1363 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1366 { shape => 'circle', radius => 4 },
1367 { shape => 'square', radius => 4 },
1368 { shape => 'diamond', radius => 4 },
1369 { shape => 'triangle', radius => 4 },
1370 { shape => 'x', radius => 4 },
1371 { shape => 'plus', radius => 4 },
1373 back=>{ fountain=>'linear',
1374 xa_ratio=>0, ya_ratio=>0,
1375 xb_ratio=>1.0, yb_ratio=>1.0,
1376 segments=>Imager::Fountain->simple
1377 ( positions=>[0, 1],
1378 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1380 negative_bg=>'EEEEEE',
1382 features=>{ dropshadow=>1 },
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('FF8080'), NC('FF0000') ]),
1393 { fountain=>'radial',
1394 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1395 segments => Imager::Fountain->simple(positions=>[0, 1],
1396 colors=>[ NC('80FF80'), NC('00FF00') ]),
1398 { fountain=>'radial',
1399 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1400 segments => Imager::Fountain->simple(positions=>[0, 1],
1401 colors=>[ NC('808080FF'), NC('0000FF') ]),
1403 { fountain=>'radial',
1404 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1405 segments => Imager::Fountain->simple(positions=>[0, 1],
1406 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
1408 { fountain=>'radial',
1409 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1410 segments => Imager::Fountain->simple(positions=>[0, 1],
1411 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
1413 { fountain=>'radial',
1414 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1415 segments => Imager::Fountain->simple(positions=>[0, 1],
1416 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1420 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1422 back=>{ fountain=>'linear',
1423 xa_ratio=>0, ya_ratio=>0,
1424 xb_ratio=>1.0, yb_ratio=>1.0,
1425 segments=>Imager::Fountain->simple
1426 ( positions=>[0, 1],
1427 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1429 negative_bg=>'EEEEEE',
1434 $styles{'ocean'} = {
1437 fountain =>'linear',
1438 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1439 segments => Imager::Fountain->simple(
1441 colors=>[ NC('FFFFFF'), NC('E6E2AF') ]),
1444 fountain =>'linear',
1445 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1446 segments => Imager::Fountain->simple(
1448 colors=>[ NC('FFFFFF'), NC('A7A37E') ]),
1451 fountain =>'linear',
1452 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1453 segments => Imager::Fountain->simple(
1455 colors=>[ NC('FFFFFF'), NC('80B4A2') ]),
1458 fountain =>'linear',
1459 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1460 segments => Imager::Fountain->simple(
1462 colors=>[ NC('FFFFFF'), NC('046380') ]),
1465 fountain =>'linear',
1466 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1467 segments => Imager::Fountain->simple(
1469 colors=>[ NC('FFFFFF'), NC('877EA7') ]),
1472 fountain =>'linear',
1473 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1474 segments => Imager::Fountain->simple(
1476 colors=>[ NC('FFFFFF'), NC('67A35E') ]),
1479 fountain =>'linear',
1480 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1481 segments => Imager::Fountain->simple(
1483 colors=>[ NC('FFFFFF'), NC('B4726F') ]),
1487 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1490 negative_bg=>'EEEEEE',
1492 features=>{ dropshadow=>1 },
1496 =item $self->_style_setup(\%opts)
1498 Uses the values from %opts to build a customized hash describing the
1499 way the graph should be drawn.
1504 my ($self, $opts) = @_;
1505 my $style_defs = $self->_style_defs;
1508 my $pre_def_style = $self->_get_style($opts);
1509 my $api_style = $self->{'custom_style'} || {};
1510 $style = $styles{$pre_def_style} if $pre_def_style;
1512 $style ||= $styles{$def_style};
1514 my @search_list = ( $style_defs, $style, $api_style, $opts);
1517 my @composite = $self->_composite();
1519 @composite{@composite} = @composite;
1521 for my $src (@search_list) {
1522 for my $key (keys %$src) {
1523 if ($composite{$key}) {
1524 $work{$key} = {} unless exists $work{$key};
1525 if (ref $src->{$key}) {
1526 # some keys have sub values, especially text
1527 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1530 # assume it's the text for a title or something
1531 $work{$key}{text} = $src->{$key};
1535 $work{$key} = $src->{$key}
1536 if defined $src->{$key}; # $opts with pmichauds new accessor handling
1541 # features are handled specially
1542 $work{features} = {};
1543 for my $src (@search_list) {
1544 if ($src->{features}) {
1545 if (ref $src->{features}) {
1546 if (ref($src->{features}) =~ /ARRAY/) {
1547 # just set those features
1548 for my $feature (@{$src->{features}}) {
1549 $work{features}{$feature} = 1;
1552 elsif (ref($src->{features}) =~ /HASH/) {
1553 if ($src->{features}{reset}) {
1554 $work{features} = {}; # only the ones the user specifies
1556 @{$work{features}}{keys %{$src->{features}}} =
1557 values(%{$src->{features}});
1561 # just set that single feature
1562 $work{features}{$src->{features}} = 1;
1567 #print Dumper(\%work);
1569 $self->{_style} = \%work;
1572 =item $self->_get_thing($name)
1574 Retrieve some general 'thing'.
1576 Supports the 'lookup(foo)' mechanism.
1578 Returns an empty list on failure.
1583 my ($self, $name, @depth) = @_;
1585 push(@depth, $name);
1587 if ($name =~ /^(\w+)\.(\w+)$/) {
1588 $what = $self->{_style}{$1}{$2};
1591 $what = $self->{_style}{$name};
1598 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1600 or return $self->_error("too many levels of recursion in lookup(@depth)");
1601 return $self->_get_thing($1, @depth);
1608 =item $self->_get_number($name)
1610 Retrieves a number from the style. The value in the style can be the
1611 number, or one of two functions:
1615 =item lookup(newname)
1617 Recursively looks up I<newname> in the style.
1619 =item scale(value1,value2)
1621 Each value can be a number or a name. Names are recursively looked up
1622 in the style and the product is returned.
1629 my ($self, $name, @depth) = @_;
1631 push(@depth, $name);
1633 if ($name =~ /^(\w+)\.(\w+)$/) {
1634 $what = $self->{_style}{$1}{$2};
1637 $what = $self->{_style}{$name};
1640 return $self->_error("$name is undef (@depth)");
1643 if ($what =~ /CODE/) {
1644 $what = $what->($self, $name);
1648 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1650 or return $self->_error("too many levels of recursion in lookup (@depth)");
1651 return $self->_get_number($1, @depth);
1653 elsif ($what =~ /^scale\(
1654 ((?:[a-z][\w.]*)|$NUM_RE)
1656 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1657 my ($left, $right) = ($1, $2);
1658 unless ($left =~ /^$NUM_RE$/) {
1660 or return $self->_error("too many levels of recursion in scale (@depth)");
1661 $left = $self->_get_number($left, @depth);
1663 unless ($right =~ /^$NUM_RE$/) {
1665 or return $self->_error("too many levels of recursion in scale (@depth)");
1666 $right = $self->_get_number($right, @depth);
1668 return $left * $right;
1676 =item $self->_get_integer($name)
1678 Retrieves an integer from the style. This is a simple wrapper around
1679 _get_number() that rounds the result to an integer.
1681 Returns an empty list on failure.
1686 my ($self, $name, @depth) = @_;
1688 my $number = $self->_get_number($name, @depth)
1691 return sprintf("%.0f", $number);
1694 =item _get_color($name)
1696 Returns a color object of the given name from the style hash.
1698 Uses Imager::Color->new to translate normal scalars into color objects.
1700 Allows the lookup(name) mechanism.
1702 Returns an empty list on failure.
1707 my ($self, $name, @depth) = @_;
1709 push(@depth, $name);
1711 if ($name =~ /^(\w+)\.(\w+)$/) {
1712 $what = $self->{_style}{$1}{$2};
1715 $what = $self->{_style}{$name};
1719 or return $self->_error("$name was undefined (@depth)");
1721 unless (ref $what) {
1722 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1723 @depth < MAX_DEPTH or
1724 return $self->_error("too many levels of recursion in lookup (@depth)");
1726 return $self->_get_color($1, @depth);
1728 $what = Imager::Color->new($what);
1734 =item _translate_fill($what, $box)
1736 Given the value of a fill, either attempts to convert it into a fill
1737 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1738 parameters }>>), or to lookup another fill that is referred to with
1739 the 'lookup(name)' mechanism.
1741 This function does the fg and bg initialization for hatched fills, and
1742 translation of *_ratio for fountain fills (using the $box parameter).
1744 Returns an empty list on failure.
1748 sub _translate_fill {
1749 my ($self, $what, $box, @depth) = @_;
1752 if (UNIVERSAL::isa($what, "Imager::Color")) {
1753 return ( color=>Imager::Color->new($what), filled=>1 );
1757 # default to normal combine mode
1758 my %work = ( combine => 'normal', %$what );
1759 if ($what->{hatch}) {
1761 $work{fg} = $self->_get_color('fg')
1765 $work{bg} = $self->_get_color('bg')
1768 return ( fill=>\%work );
1770 elsif ($what->{fountain}) {
1771 for my $key (qw(xa ya xb yb)) {
1772 if (exists $work{"${key}_ratio"}) {
1774 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1775 * ($box->[2] - $box->[0]);
1778 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1779 * ($box->[3] - $box->[1]);
1783 return ( fill=>\%work );
1786 return ( fill=> \%work );
1791 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1792 return $self->_get_fill($1, $box, @depth);
1795 # assumed to be an Imager::Color single value
1796 return ( color=>Imager::Color->new($what), filled=>1 );
1801 =item _data_fill($index, $box)
1803 Retrieves the fill parameters for a data area fill.
1808 my ($self, $index, $box) = @_;
1810 my $fills = $self->{_style}{fills};
1811 return $self->_translate_fill($fills->[$index % @$fills], $box,
1816 my ($self, $index) = @_;
1818 my $colors = $self->{'_style'}{'colors'} || [];
1819 my $fills = $self->{'_style'}{'fills'} || [];
1821 # Try to just use a fill, so non-fountain styles don't need
1822 # to have a duplicated set of fills and colors
1823 my $fill = $fills->[$index % @$fills];
1829 return $colors->[$index % @$colors] || '000000';
1834 =item _get_fill($index, $box)
1836 Retrieves fill parameters for a named fill.
1841 my ($self, $name, $box, @depth) = @_;
1843 push(@depth, $name);
1845 if ($name =~ /^(\w+)\.(\w+)$/) {
1846 $what = $self->{_style}{$1}{$2};
1849 $what = $self->{_style}{$name};
1853 or return $self->_error("no fill $name found");
1855 return $self->_translate_fill($what, $box, @depth);
1860 Builds the image object for the graph and fills it with the background
1868 my $width = $self->_get_number('width') || 256;
1869 my $height = $self->_get_number('height') || 256;
1870 my $channels = $self->{_style}{channels};
1874 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels);
1876 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
1884 if (!$self->{'_image'}) {
1885 $self->{'_image'} = $self->_make_img();
1887 return $self->{'_image'};
1890 =item _text_style($name)
1892 Returns parameters suitable for calls to Imager::Font's bounding_box()
1893 and draw() methods intended for use in defining text styles.
1895 Returns an empty list on failure.
1897 Returns the following attributes: font, color, size, aa, sizew
1903 my ($self, $name) = @_;
1907 if ($self->{_style}{$name}) {
1908 %work = %{$self->{_style}{$name}};
1911 %work = %{$self->{_style}{text}};
1914 or return $self->_error("$name has no font parameter");
1916 $work{font} = $self->_get_thing("$name.font")
1917 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
1918 UNIVERSAL::isa($work{font}, "Imager::Font")
1919 or return $self->_error("$name.font is not a font");
1920 if ($work{color} && !ref $work{color}) {
1921 $work{color} = $self->_get_color("$name.color")
1924 $work{size} = $self->_get_number("$name.size");
1925 $work{sizew} = $self->_get_number("$name.sizew")
1927 $work{aa} = $self->_get_number("$name.aa");
1932 =item _text_bbox($text, $name)
1934 Returns a bounding box for the specified $text as styled by $name.
1936 Returns an empty list on failure.
1941 my ($self, $text, $name) = @_;
1943 my %text_info = $self->_text_style($name)
1946 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
1952 =item _line_style($name)
1954 Return parameters suitable for calls to Imager's line(), polyline(),
1957 For now this returns only color and aa parameters, but future releases
1958 of Imager may support extra parameters.
1963 my ($self, $name) = @_;
1966 $line{color} = $self->_get_color("$name.line")
1968 $line{aa} = $self->_get_number("$name.lineaa");
1969 defined $line{aa} or $line{aa} = $self->_get_number("aa");
1975 my ($self, $box, $chart_box, $name) = @_;
1977 my $halign = $self->{_style}{$name}{halign}
1978 or $self->_error("no halign for $name");
1979 my $valign = $self->{_style}{$name}{valign};
1981 if ($halign eq 'right') {
1982 $box->[0] += $chart_box->[2] - $box->[2];
1984 elsif ($halign eq 'left') {
1985 $box->[0] = $chart_box->[0];
1987 elsif ($halign eq 'center' || $halign eq 'centre') {
1988 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
1991 return $self->_error("invalid halign $halign for $name");
1994 if ($valign eq 'top') {
1995 $box->[1] = $chart_box->[1];
1997 elsif ($valign eq 'bottom') {
1998 $box->[1] = $chart_box->[3] - $box->[3];
2000 elsif ($valign eq 'center' || $valign eq 'centre') {
2001 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
2004 return $self->_error("invalid valign $valign for $name");
2006 $box->[2] += $box->[0];
2007 $box->[3] += $box->[1];
2011 my ($self, $chart_box, $object_box) = @_;
2015 if ($object_box->[0] - $chart_box->[0]
2016 < $chart_box->[2] - $object_box->[2]) {
2017 $areax = ($object_box->[2] - $chart_box->[0])
2018 * ($chart_box->[3] - $chart_box->[1]);
2021 $areax = ($chart_box->[2] - $object_box->[0])
2022 * ($chart_box->[3] - $chart_box->[1]);
2025 if ($object_box->[1] - $chart_box->[1]
2026 < $chart_box->[3] - $object_box->[3]) {
2027 $areay = ($object_box->[3] - $chart_box->[1])
2028 * ($chart_box->[2] - $chart_box->[0]);
2031 $areay = ($chart_box->[3] - $object_box->[1])
2032 * ($chart_box->[2] - $chart_box->[0]);
2035 if ($areay < $areax) {
2036 if ($object_box->[1] - $chart_box->[1]
2037 < $chart_box->[3] - $object_box->[3]) {
2038 $chart_box->[1] = $object_box->[3];
2041 $chart_box->[3] = $object_box->[1];
2045 if ($object_box->[0] - $chart_box->[0]
2046 < $chart_box->[2] - $object_box->[2]) {
2047 $chart_box->[0] = $object_box->[2];
2050 $chart_box->[2] = $object_box->[0];
2056 my ($self, $img, $labels, $chart_box) = @_;
2058 my $orient = $self->_get_thing('legend.orientation');
2059 defined $orient or $orient = 'vertical';
2061 if ($orient eq 'vertical') {
2062 return $self->_draw_legend_vertical($img, $labels, $chart_box);
2064 elsif ($orient eq 'horizontal') {
2065 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
2068 return $self->_error("Unknown legend.orientation $orient");
2072 sub _draw_legend_horizontal {
2073 my ($self, $img, $labels, $chart_box) = @_;
2075 defined(my $padding = $self->_get_integer('legend.padding'))
2077 my $patchsize = $self->_get_integer('legend.patchsize')
2079 defined(my $gap = $self->_get_integer('legend.patchgap'))
2082 my $minrowsize = $patchsize + $gap;
2083 my ($width, $height) = (0,0);
2084 my $row_height = $minrowsize;
2088 for my $label (@$labels) {
2089 my @text_box = $self->_text_bbox($label, 'legend')
2091 push(@sizes, \@text_box);
2092 my $entry_width = $patchsize + $gap + $text_box[2];
2094 # never re-wrap the first entry
2095 push @offsets, [ 0, $height ];
2098 if ($pos + $gap + $entry_width > $chart_box->[2]) {
2100 $height += $row_height;
2102 push @offsets, [ $pos, $height ];
2104 my $entry_right = $pos + $entry_width;
2105 $pos += $gap + $entry_width;
2106 $entry_right > $width and $width = $entry_right;
2107 if ($text_box[3] > $row_height) {
2108 $row_height = $text_box[3];
2111 $height += $row_height;
2112 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
2113 my $outsidepadding = 0;
2114 if ($self->{_style}{legend}{border}) {
2115 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2117 $box[2] += 2 * $outsidepadding;
2118 $box[3] += 2 * $outsidepadding;
2120 $self->_align_box(\@box, $chart_box, 'legend')
2122 if ($self->{_style}{legend}{fill}) {
2123 $img->box(xmin=>$box[0]+$outsidepadding,
2124 ymin=>$box[1]+$outsidepadding,
2125 xmax=>$box[2]-$outsidepadding,
2126 ymax=>$box[3]-$outsidepadding,
2127 $self->_get_fill('legend.fill', \@box));
2129 $box[0] += $outsidepadding;
2130 $box[1] += $outsidepadding;
2131 $box[2] -= $outsidepadding;
2132 $box[3] -= $outsidepadding;
2133 my %text_info = $self->_text_style('legend')
2136 if ($self->{_style}{legend}{patchborder}) {
2137 $patchborder = $self->_get_color('legend.patchborder')
2142 for my $label (@$labels) {
2143 my ($left, $top) = @{$offsets[$dataindex]};
2144 $left += $box[0] + $padding;
2145 $top += $box[1] + $padding;
2146 my $textpos = $left + $patchsize + $gap;
2147 my @patchbox = ( $left, $top,
2148 $left + $patchsize, $top + $patchsize );
2149 my @fill = $self->_data_fill($dataindex, \@patchbox)
2151 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2152 ymax=>$top + $patchsize, @fill);
2153 if ($self->{_style}{legend}{patchborder}) {
2154 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2155 ymax=>$top + $patchsize,
2156 color=>$patchborder);
2158 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
2163 if ($self->{_style}{legend}{border}) {
2164 my $border_color = $self->_get_color('legend.border')
2166 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2167 color=>$border_color);
2169 $self->_remove_box($chart_box, \@box);
2173 sub _draw_legend_vertical {
2174 my ($self, $img, $labels, $chart_box) = @_;
2176 defined(my $padding = $self->_get_integer('legend.padding'))
2178 my $patchsize = $self->_get_integer('legend.patchsize')
2180 defined(my $gap = $self->_get_integer('legend.patchgap'))
2182 my $minrowsize = $patchsize + $gap;
2183 my ($width, $height) = (0,0);
2185 for my $label (@$labels) {
2186 my @box = $self->_text_bbox($label, 'legend')
2188 push(@sizes, \@box);
2189 $width = $box[2] if $box[2] > $width;
2190 if ($minrowsize > $box[3]) {
2191 $height += $minrowsize;
2198 $width + $patchsize + $padding * 2 + $gap,
2199 $height + $padding * 2 - $gap);
2200 my $outsidepadding = 0;
2201 if ($self->{_style}{legend}{border}) {
2202 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2204 $box[2] += 2 * $outsidepadding;
2205 $box[3] += 2 * $outsidepadding;
2207 $self->_align_box(\@box, $chart_box, 'legend')
2209 if ($self->{_style}{legend}{fill}) {
2210 $img->box(xmin=>$box[0]+$outsidepadding,
2211 ymin=>$box[1]+$outsidepadding,
2212 xmax=>$box[2]-$outsidepadding,
2213 ymax=>$box[3]-$outsidepadding,
2214 $self->_get_fill('legend.fill', \@box));
2216 $box[0] += $outsidepadding;
2217 $box[1] += $outsidepadding;
2218 $box[2] -= $outsidepadding;
2219 $box[3] -= $outsidepadding;
2220 my $ypos = $box[1] + $padding;
2221 my $patchpos = $box[0]+$padding;
2222 my $textpos = $patchpos + $patchsize + $gap;
2223 my %text_info = $self->_text_style('legend')
2226 if ($self->{_style}{legend}{patchborder}) {
2227 $patchborder = $self->_get_color('legend.patchborder')
2231 for my $label (@$labels) {
2232 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
2233 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
2236 if ($self->_draw_flat_legend()) {
2237 @fill = (color => $self->_data_color($dataindex), filled => 1);
2240 @fill = $self->_data_fill($dataindex, \@patchbox)
2243 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2244 ymax=>$ypos + $patchsize, @fill);
2245 if ($self->{_style}{legend}{patchborder}) {
2246 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2247 ymax=>$ypos + $patchsize,
2248 color=>$patchborder);
2250 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
2253 my $step = $patchsize + $gap;
2254 if ($minrowsize < $sizes[$dataindex][3]) {
2255 $ypos += $sizes[$dataindex][3];
2258 $ypos += $minrowsize;
2262 if ($self->{_style}{legend}{border}) {
2263 my $border_color = $self->_get_color('legend.border')
2265 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2266 color=>$border_color);
2268 $self->_remove_box($chart_box, \@box);
2273 my ($self, $img, $chart_box) = @_;
2275 my $title = $self->{_style}{title}{text};
2276 my @box = $self->_text_bbox($title, 'title')
2280 $self->_align_box(\@box, $chart_box, 'title');
2281 my %text_info = $self->_text_style('title')
2283 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
2284 $self->_remove_box($chart_box, \@box);
2289 my ($self, $box) = @_;
2291 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
2292 return $box->[3] - $box->[1];
2295 return $box->[2] - $box->[0];
2299 sub _draw_flat_legend {
2305 Returns a list of style fields that are stored as composites, and
2306 should be merged instead of just being replaced.
2311 qw(title legend text label dropshadow outline callout);
2314 sub _filter_region {
2315 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
2317 unless (ref $filter) {
2319 $filter = $self->_get_thing($name)
2322 or return $self->_error("no type for filter $name");
2325 $left > 0 or $left = 0;
2326 $top > 0 or $top = 0;
2328 # newer versions of Imager let you work on just part of an image
2329 if ($img->can('masked') && !$self->{_style}{features}{_debugblur}) {
2330 my $masked = $img->masked(left=>$left, top=>$top,
2331 right=>$right, bottom=>$bottom);
2332 $masked->filter(%$filter);
2335 # for older versions of Imager
2336 my $subset = $img->crop(left=>$left, top=>$top,
2337 right=>$right, bottom=>$bottom);
2338 $subset->filter(%$filter);
2339 $img->paste(left=>$left, top=>$top, img=>$subset);
2350 Imager::Graph::Pie(3), Imager(3), perl(1).
2354 Tony Cook <tony@develop-help.com>
2358 Imager::Graph is licensed under the same terms as perl itself.
2362 Addi for producing a cool imaging module. :)