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, ...)
14 $img->write(file => 'image.png');
18 Imager::Graph provides style information to its base classes. It
19 defines the colors, text display information and fills based on both
20 built-in styles and modifications supplied by the user to the draw()
28 use vars qw($VERSION);
29 use Imager qw(:handy);
34 # the maximum recursion depth in determining a color, fill or number
35 use constant MAX_DEPTH => 10;
37 my $NUM_RE = '(?:[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]\d+?)?)';
41 This is a simple constructor. No parameters required.
49 =item set_graph_size($size)
51 Sets the size of the graph (in pixels) within the image. The size of the image defaults to 1.5 * $graph_size.
56 $_[0]->{'custom_style'}->{'size'} = $_[1];
59 =item set_image_width($width)
61 Sets the width of the image in pixels.
66 $_[0]->{'custom_style'}->{'width'} = $_[1];
69 =item set_image_height($height)
71 Sets the height of the image in pixels.
75 sub set_image_height {
76 $_[0]->{'custom_style'}->{'height'} = $_[1];
79 =item add_data_series([8, 6, 7, 5, 3, 0, 9], 'Series Name');
81 Adds a data series to the graph. For L<Imager::Graph::Pie>, only one data series can be added.
88 my $series_name = shift;
90 my $graph_data = $self->{'graph_data'} || [];
92 push @$graph_data, { data => $data_ref, series_name => $series_name };
93 if (defined $series_name) {
94 push @{$self->{'labels'}}, $series_name;
97 $self->{'graph_data'} = $graph_data;
101 sub _get_data_series {
102 my ($self, $opts) = @_;
104 # return the data supplied to draw() if any.
106 # one or multiple series?
107 my $data = $opts->{data};
108 if (@$data && ref $data->[0] && ref $data->[0] =~ /ARRAY/) {
112 return [ { data => $data } ];
116 return $self->{'graph_data'};
119 =item set_labels(['label1', 'label2' ... ])
121 Labels the specific data points. For line/bar graphs, this is the x-axis. For pie graphs, it is the label for the wedges.
126 $_[0]->{'labels'} = $_[1];
130 my ($self, $opts) = @_;
133 and return $opts->{labels};
135 return $_[0]->{'labels'}
138 =item set_title($title)
140 Sets the title of the graph. Requires setting a font.
145 $_[0]->{'custom_style'}->{'title'}->{'text'} = $_[1];
148 =item set_font($font)
150 Sets the font to use for text. Takes an L<Imager::Font> object.
155 $_[0]->{'custom_style'}->{'font'} = $_[1];
158 =item set_style($style_name)
160 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.
165 $_[0]->{'style'} = $_[1];
169 my ($self, $opts) = @_;
172 and return $opts->{style};
174 return $self->{'style'};
179 Returns an error message. Only valid if the draw() method returns false.
189 Creates a new image, draws the chart onto that image and returns it.
191 Optionally, instead of using the api methods to configure your chart,
192 you can supply a C<data> parameter in the format
193 required by that particular graph, and if your graph will use any
194 text, a C<font> parameter
196 You can also supply many different parameters which control the way
197 the graph looks. These are supplied as keyword, value pairs, where
198 the value can be a hashref containing sub values.
200 The C<style> parameter will selects a basic color set, and possibly
201 sets other related parameters. See L</"STYLES">.
203 my $font = Imager::Font->new(file => 'ImUgly.ttf');
204 my $img = $chart->draw(
208 text => "Hello, World!",
214 When referring to a single sub-value this documentation will refer to
215 'title.color' rather than 'the color element of title'.
217 Returns the graph image on success, or false on failure.
223 The currently defined styles are:
229 a light grey background with no outlines. Uses primary colors for the
234 a light red background with no outlines. Uses primary colors for the
237 Graphs drawn using this style should save well as a gif, even though
238 some graphs may perform a slight blur.
240 This was the default style, but the red was too loud.
244 designed for monochrome output, such as most laser printers, this uses
245 hatched fills for the data, and no colors. The returned image is a
246 one channel image (which can be overridden with the C<channels>
249 You can also override the colors used by all components for background
250 or drawing by supplying C<fg> and/or C<bg> parameters. ie. if you
251 supply C<<fg=>'FF0000', channels=>3>> then the hash fills and anything
252 else will be drawn in red. Another use might be to set a transparent
253 background, by supplying C<<bg=>'00000000', channels=>4>>.
255 This style outlines the legend if present and outlines the hashed fills.
259 designed as a "pretty" style this uses linear fountain fills for the
260 background and data fills, and adds a drop shadow.
262 You can override the value used for text and outlines by setting the
265 This is the default style.
269 also designed as a "pretty" style this uses radial fountain fills for
270 the data and a linear blue to green fill for the background.
276 To set or override styles, you can use the following methods:
280 =item set_image_background
284 sub set_image_background {
285 $_[0]->{'custom_style'}->{'back'} = $_[1];
293 $_[0]->{'custom_style'}->{'channels'} = $_[1];
301 $_[0]->{'custom_style'}->{'line'} = $_[1];
304 =item set_title_font_size
308 sub set_title_font_size {
309 $_[0]->{'custom_style'}->{'title'}->{'size'} = $_[1];
312 =item set_title_font_color
316 sub set_title_font_color {
317 $_[0]->{'custom_style'}->{'title'}->{'color'} = $_[1];
320 =item set_title_horizontal_align
324 sub set_title_horizontal_align {
325 $_[0]->{'custom_style'}->{'title'}->{'halign'} = $_[1];
328 =item set_title_vertical_align
332 sub set_title_vertical_align {
333 $_[0]->{'custom_style'}->{'title'}->{'valign'} = $_[1];
336 =item set_text_font_color
340 sub set_text_font_color {
341 $_[0]->{'custom_style'}->{'text'}->{'color'} = $_[1];
344 =item set_text_font_size
348 sub set_text_font_size {
349 $_[0]->{'custom_style'}->{'text'}->{'size'} = $_[1];
352 =item set_graph_background_color
356 sub set_graph_background_color {
357 $_[0]->{'custom_style'}->{'bg'} = $_[1];
360 =item set_graph_foreground_color
364 sub set_graph_foreground_color {
365 $_[0]->{'custom_style'}->{'fg'} = $_[1];
368 =item set_legend_font_color
372 sub set_legend_font_color {
373 $_[0]->{'custom_style'}->{'legend'}->{'color'} = $_[1];
376 =item set_legend_font
380 sub set_legend_font {
381 $_[0]->{'custom_style'}->{'legend'}->{'font'} = $_[1];
384 =item set_legend_font_size
388 sub set_legend_font_size {
389 $_[0]->{'custom_style'}->{'legend'}->{'size'} = $_[1];
392 =item set_legend_patch_size
396 sub set_legend_patch_size {
397 $_[0]->{'custom_style'}->{'legend'}->{'patchsize'} = $_[1];
400 =item set_legend_patch_gap
404 sub set_legend_patch_gap {
405 $_[0]->{'custom_style'}->{'legend'}->{'patchgap'} = $_[1];
408 =item set_legend_horizontal_align
412 sub set_legend_horizontal_align {
413 $_[0]->{'custom_style'}->{'legend'}->{'halign'} = $_[1];
416 =item set_legend_vertical_align
420 sub set_legend_vertical_align {
421 $_[0]->{'custom_style'}->{'legend'}->{'valign'} = $_[1];
424 =item set_legend_padding
428 sub set_legend_padding {
429 $_[0]->{'custom_style'}->{'legend'}->{'padding'} = $_[1];
432 =item set_legend_outside_padding
436 sub set_legend_outside_padding {
437 $_[0]->{'custom_style'}->{'legend'}->{'outsidepadding'} = $_[1];
440 =item set_legend_fill
444 sub set_legend_fill {
445 $_[0]->{'custom_style'}->{'legend'}->{'fill'} = $_[1];
448 =item set_legend_border
452 sub set_legend_border {
453 $_[0]->{'custom_style'}->{'legend'}->{'border'} = $_[1];
456 =item set_legend_orientation
460 sub set_legend_orientation {
461 $_[0]->{'custom_style'}->{'legend'}->{'orientation'} = $_[1];
464 =item set_callout_font_color
468 sub set_callout_font_color {
469 $_[0]->{'custom_style'}->{'callout'}->{'color'} = $_[1];
472 =item set_callout_font
476 sub set_callout_font {
477 $_[0]->{'custom_style'}->{'callout'}->{'font'} = $_[1];
480 =item set_callout_font_size
484 sub set_callout_font_size {
485 $_[0]->{'custom_style'}->{'callout'}->{'size'} = $_[1];
488 =item set_callout_line_color
492 sub set_callout_line_color {
493 $_[0]->{'custom_style'}->{'callout'}->{'line'} = $_[1];
496 =item set_callout_leader_inside_length
500 sub set_callout_leader_inside_length {
501 $_[0]->{'custom_style'}->{'callout'}->{'inside'} = $_[1];
504 =item set_callout_leader_outside_length
508 sub set_callout_leader_outside_length {
509 $_[0]->{'custom_style'}->{'callout'}->{'outside'} = $_[1];
512 =item set_callout_leader_length
516 sub set_callout_leader_length {
517 $_[0]->{'custom_style'}->{'callout'}->{'leadlen'} = $_[1];
520 =item set_callout_gap
524 sub set_callout_gap {
525 $_[0]->{'custom_style'}->{'callout'}->{'gap'} = $_[1];
528 =item set_label_font_color
532 sub set_label_font_color {
533 $_[0]->{'custom_style'}->{'label'}->{'color'} = $_[1];
541 $_[0]->{'custom_style'}->{'label'}->{'font'} = $_[1];
544 =item set_label_font_size
548 sub set_label_font_size {
549 $_[0]->{'custom_style'}->{'label'}->{'size'} = $_[1];
552 =item set_drop_shadow_fill_color
556 sub set_drop_shadow_fill_color {
557 $_[0]->{'custom_style'}->{'dropshadow'}->{'fill'} = $_[1];
560 =item set_drop_shadow_offset
564 sub set_drop_shadow_offset {
565 $_[0]->{'custom_style'}->{'dropshadow'}->{'off'} = $_[1];
568 =item set_drop_shadowXOffset
572 sub set_drop_shadowXOffset {
573 $_[0]->{'custom_style'}->{'dropshadow'}->{'offx'} = $_[1];
576 =item set_drop_shadowYOffset
580 sub set_drop_shadowYOffset {
581 $_[0]->{'custom_style'}->{'dropshadow'}->{'offy'} = $_[1];
584 =item set_drop_shadow_filter
588 sub set_drop_shadow_filter {
589 $_[0]->{'custom_style'}->{'dropshadow'}->{'filter'} = $_[1];
592 =item set_outline_color
596 sub set_outline_color {
597 $_[0]->{'custom_style'}->{'outline'}->{'line'} = $_[1];
600 =item set_data_area_fills
604 sub set_data_area_fills {
605 $_[0]->{'custom_style'}->{'fills'} = $_[1];
608 =item set_data_line_colors
612 sub set_data_line_colors {
613 $_[0]->{'custom_style'}->{'colors'} = $_[1];
620 Each graph type has a number of features. These are used to add
621 various items that are displayed in the graph area.
623 Features can be controlled by calling methods on the graph object, or
624 by passing a C<features> parameter to draw().
626 Some common features are:
633 X<legend><features, legend>
635 adds a box containing boxes filled with the data fills, with
636 the labels provided to the draw method. The legend will only be
637 displayed if both the legend feature is enabled and labels are
643 $_[0]->{'custom_style'}->{'features'}->{'legend'} = 1;
649 X<outline>X<features, outline>
651 If enabled, draw a border around the elements representing data in the
652 graph, eg. around each pie segments on a pie chart, around each bar on
658 $_[0]->{'custom_style'}->{'features'}->{'outline'} = 1;
664 X<labels>X<features, labels>
666 labels each data fill, usually by including text inside the data fill.
667 If the text does not fit in the fill, they could be displayed in some
668 other form, eg. as callouts in a pie graph.
670 For pie charts there isn't much point in enabling both the C<legend>
671 and C<labels> features.
673 For other charts, the labels label the independent variable, while the
674 legend describes the color used to plot the dependent variables.
679 $_[0]->{'custom_style'}->{'features'}->{'labels'} = 1;
682 =item show_drop_shadow()
685 X<dropshadow>X<features, dropshadow>
687 a simple drop shadow is shown behind some of the graph elements.
691 sub show_drop_shadow {
692 $_[0]->{'custom_style'}->{'features'}->{'dropshadow'} = 1;
695 =item reset_features()
697 Unsets all of the features.
699 Note: this disables all features, even those enabled by default for a
700 style. They can then be enabled by calling feature methods or by
701 supplying a C<feature> parameter to the draw() method.
706 $_[0]->{'custom_style'}->{'features'} = {};
707 $_[0]->{'custom_style'}->{'features'}->{'reset'} = 1;
712 Additionally, features can be set by passing them into the draw()
713 method, named as above:
719 if supplied as an array reference, then any element C<no>I<featurename> will
720 disable that feature, while an element I<featurename> will enable it.
724 if supplied as a scalar, it is treated as if it were a reference to
725 an array containing only that scalar.
729 if supplied as a hash reference, then a C<reset> key with a true value
730 will avoid inheriting any default features, a key I<feature> with a
731 false value will disable that feature and a key I<feature> with a true
732 value will enable that feature.
736 Each graph also has features specific to that graph.
738 =head1 COMMON PARAMETERS
740 When referring to a single sub-value this documentation will refer to
741 'title.color' rather than 'the color element of title'.
743 Normally, except for the font parameter, these are controlled by
744 styles, but these are the style parameters I'd mostly likely expect
751 the Imager font object used to draw text on the chart.
755 the background fill for the graph. Default depends on the style.
759 the base size of the graph image. Default: 256
763 the width of the graph image. Default: 1.5 * size (384)
767 the height of the graph image. Default: size (256)
771 the number of channels in the image. Default: 3 (the 'mono' style
776 the color used for drawing lines, such as outlines or callouts.
777 Default depends on the current style. Set to undef to remove the
778 outline from a style.
782 the text used for a graph title. Default: no title. Note: this is
783 the same as the title=>{ text => ... } field.
789 horizontal alignment of the title in the graph, one of 'left',
790 'center' or 'right'. Default: center
794 vertical alignment of the title, one of 'top', 'center' or 'right'.
795 Default: top. It's probably a bad idea to set this to 'center' unless
796 you have a very short title.
802 This contains basic defaults used in drawing text.
808 the default color used for all text, defaults to the fg color.
812 the base size used for text, also used to scale many graph elements.
821 In most cases you will want to use just the styles, but you may want
822 to exert more control over the way your chart looks. This section
823 describes the options you can use to control the way your chart looks.
825 Hopefully you don't need to read this.
831 The background of the graph.
837 Used to define basic background and foreground colors for the graph.
838 The bg color may be used for the background of the graph, and is used
839 as a default for the background of hatched fills. The fg is used as
840 the default for line and text colors.
844 The default font used by the graph. Normally you should supply this
845 if your graph as any text.
849 The default line color.
853 defaults for drawing text. Other textual graph elements will inherit
854 or modify these values.
860 default text color, defaults to the I<fg> color.
864 default text size. Default: 14. This is used to scale many graph
865 elements, including padding and leader sizes. Other text elements
866 will either use or scale this value.
870 default font object. Inherited from I<font>, which should have been
871 supplied by the caller.
877 If you supply a scalar value for this element, it will be stored in
880 Defines the text, font and layout information for the title.
886 The color of the title, inherited from I<text.color>.
890 The font object used for the title, inherited from I<text.font>.
894 size of the title text. Default: double I<text.size>
900 The horizontal and vertical alignment of the title.
906 defines attributes of the graph legend, if present.
916 text attributes for the labels used in the legend.
920 the width and height of the color patch in the legend. Defaults to
921 90% of the legend text size.
925 the minimum gap between patches in pixels. Defaults to 30% of the
930 the color of the border drawn around each patch. Inherited from I<line>.
936 the horizontal and vertical alignment of the legend within the graph.
937 Defaults to 'right' and 'top'.
941 the gap between the legend patches and text and the outside of its
942 box, or to the legend border, if any.
946 the gap between the border and the outside of the legend's box. This
947 is only used if the I<legend.border> attribute is defined.
951 the background fill for the legend. Default: none
955 the border color of the legend. Default: none (no border is drawn
960 The orientation of the legend. If this is C<vertical> the the patches
961 and labels are stacked on top of each other. If this is C<horizontal>
962 the patchs and labels are word wrapped across the image. Default:
967 For example to create a horizontal legend with borderless patches,
968 darker than the background, you might do:
970 my $im = $chart->draw
974 patchborder => undef,
975 orientation => 'horizontal',
976 fill => { solid => Imager::Color->new(0, 0, 0, 32), }
982 defines attributes for graph callouts, if any are present. eg. if the
983 pie graph cannot fit the label into the pie graph segement it will
984 present it as a callout.
994 the text attributes of the callout label. Inherited from I<text>.
998 the color of the callout lines. Inherited from I<line>
1004 the length of the leader on the inside and the outside of the fill,
1005 usually at some angle. Both default to the size of the callout text.
1009 the length of the horizontal portion of the leader. Default:
1014 the gap between the callout leader and the callout text. Defaults to
1015 30% of the text callout size.
1021 defines attributes for labels drawn into the data areas of a graph.
1031 The text attributes of the labels. Inherited from I<text>.
1037 the attributes of the graph's drop shadow
1043 the fill used for the drop shadow. Default: '404040' (dark gray)
1047 the offset of the drop shadow. A convenience value inherited by offx
1048 and offy. Default: 40% of I<text.size>.
1054 the horizontal and vertical offsets of the drop shadow. Both
1055 inherited from I<dropshadow.off>.
1059 the filter description passed to Imager's filter method to blur the
1060 drop shadow. Default: an 11 element convolution filter.
1066 describes the lines drawn around filled data areas, such as the
1067 segments of a pie chart.
1073 the line color of the outlines, inherited from I<line>.
1079 a reference to an array containing fills for each data item.
1081 You can mix fill types, ie. using a simple color for the first item, a
1082 hatched fill for the second and a fountain fill for the next.
1086 =head1 HOW VALUES WORK
1088 Internally rather than specifying literal color, fill, or font objects
1089 or literal sizes for each element, Imager::Graph uses a number of
1090 special values to inherit or modify values taken from other graph
1093 =head2 Specifying colors
1095 You can specify colors by either supplying an Imager::Color object, by
1096 supplying lookup of another color, or by supplying a single value that
1097 Imager::Color::new can use as an initializer. The most obvious is
1098 just a 6 or 8 digit hex value representing the red, green, blue and
1099 optionally alpha channels of the image.
1101 You can lookup another color by using the lookup() "function", for
1102 example if you give a color as "lookup(fg)" then Imager::Graph will
1103 look for the fg element in the current style (or as overridden by
1104 you.) This is used internally by Imager::Graph to set up the
1105 relationships between the colors of various elements, for example the
1106 default style information contains:
1109 color=>'lookup(fg)',
1113 color=>'lookup(text.color)',
1117 So by setting the I<fg> color, you also set the default text color,
1118 since each text element uses lookup(text.color) as its value.
1120 =head2 Specifying fills
1122 Fills can be used for the graph background color, the background color
1123 for the legend block and for the fills used for each data element.
1125 You can specify a fill as a L<color value|Specifying colors> or as a
1126 general fill, see L<Imager::Fill> for details.
1128 You don't need (or usually want) to call Imager::Fill::new yourself,
1129 since the various fill functions will call it for you, and
1130 Imager::Graph provides some hooks to make them more useful.
1136 with hatched fills, if you don't supply a 'fg' or 'bg' parameter,
1137 Imager::Graph will supply the current graph fg and bg colors.
1141 with fountain fill, you can supply the xa_ratio, ya_ratio, xb_ratio
1142 and yb_ratio parameters, and they will be scaled in the fill area to
1143 define the fountain fills xa, ya, xb and yb parameters.
1147 As with colors, you can use lookup(name) or lookup(name1.name2) to
1148 have one element to inherit the fill of another.
1150 Imager::Graph defaults the fill combine value to C<'normal'>. This
1151 doesn't apply to simple color fills.
1153 =head2 Specifying numbers
1155 You can specify various numbers, usually representing the size of
1156 something, commonly text, but sometimes the length of a line or the
1159 You can use the same lookup mechanism as with colors and fills, but
1160 you can also scale values. For example, 'scale(0.5,text.size)' will
1161 return half the size of the normal text size.
1163 As with colors, this is used internally to scale graph elements based
1164 on the base text size. If you change the base text size then other
1165 graph elements will scale as well.
1167 =head2 Specifying other elements
1169 Other elements, such as fonts, or parameters for a filter, can also
1170 use the lookup(name) mechanism.
1172 =head1 INTERNAL METHODS
1174 Only useful if you need to fix bugs, add features or create a new
1183 back=> 'lookup(bg)',
1184 line=> 'lookup(fg)',
1187 color => 'lookup(fg)',
1188 font => 'lookup(font)',
1193 color => 'lookup(text.color)',
1194 font => 'lookup(text.font)',
1197 size => 'scale(text.size,2.0)',
1198 aa => 'lookup(text.aa)',
1201 color => 'lookup(text.color)',
1202 font => 'lookup(text.font)',
1203 aa => 'lookup(text.aa)',
1204 size => 'lookup(text.size)',
1205 patchsize => 'scale(legend.size,0.9)',
1206 patchgap => 'scale(legend.patchsize,0.3)',
1207 patchborder => 'lookup(line)',
1210 padding => 'scale(legend.size,0.3)',
1211 outsidepadding => 'scale(legend.padding,0.4)',
1214 color => 'lookup(text.color)',
1215 font => 'lookup(text.font)',
1216 size => 'lookup(text.size)',
1217 line => 'lookup(line)',
1218 inside => 'lookup(callout.size)',
1219 outside => 'lookup(callout.size)',
1220 leadlen => 'scale(0.8,callout.size)',
1221 gap => 'scale(callout.size,0.3)',
1222 aa => 'lookup(text.aa)',
1223 lineaa => 'lookup(lineaa)',
1226 font => 'lookup(text.font)',
1227 size => 'lookup(text.size)',
1228 color => 'lookup(text.color)',
1229 hpad => 'lookup(label.pad)',
1230 vpad => 'lookup(label.pad)',
1231 pad => 'scale(label.size,0.2)',
1232 pcformat => sub { sprintf "%s (%.0f%%)", $_[0], $_[1] },
1233 pconlyformat => sub { sprintf "%.1f%%", $_[0] },
1234 aa => 'lookup(text.aa)',
1235 lineaa => 'lookup(lineaa)',
1238 fill => { solid => Imager::Color->new(0, 0, 0, 96) },
1239 off => 'scale(0.4,text.size)',
1240 offx => 'lookup(dropshadow.off)',
1241 offy => 'lookup(dropshadow.off)',
1242 filter => { type=>'conv',
1243 # this needs a fairly heavy blur
1244 coef=>[0.1, 0.2, 0.4, 0.6, 0.7, 0.9, 1.2,
1245 0.9, 0.7, 0.6, 0.4, 0.2, 0.1 ] },
1247 # controls the outline of graph elements representing data, eg. pie
1248 # slices, bars or columns
1250 line =>'lookup(line)',
1251 lineaa => 'lookup(lineaa)',
1253 # controls the outline and background of the data area of the chart
1256 fill => "lookup(bg)",
1257 outline => "lookup(fg)",
1260 width=>'scale(1.5,size)',
1261 height=>'lookup(size)',
1263 # yes, the handling of fill and line AA is inconsistent, lack of
1264 # forethought, unfortunately
1268 lineaa => 'lookup(aa)',
1271 =item _error($message)
1273 Sets the error field of the object and returns an empty list or undef,
1274 depending on context. Should be used for error handling, since it may
1275 provide some user hooks at some point.
1277 The intended usage is:
1280 or return $self->_error("error description");
1282 You should almost always return the result of _error() or return
1283 immediately afterwards.
1288 my ($self, $error) = @_;
1290 $self->{_errstr} = $error;
1298 Returns the style defaults, such as the relationships between line
1299 color and text color.
1301 Intended to be over-ridden by base classes to provide graph specific
1310 # Let's make the default something that looks really good, so folks will be interested enough to customize the style.
1311 my $def_style = 'fount_lin';
1319 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1322 negative_bg=>'EEEEEE',
1326 #patchborder=>'000000'
1333 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1336 negative_bg=>'EEEEEE',
1340 patchborder=>'000000'
1347 { hatch=>'slash2' },
1348 { hatch=>'slosh2' },
1349 { hatch=>'vline2' },
1350 { hatch=>'hline2' },
1351 { hatch=>'cross2' },
1353 { hatch=>'stipple3' },
1354 { hatch=>'stipple2' },
1359 negative_bg=>'EEEEEE',
1360 features=>{ outline=>1 },
1370 { fountain=>'linear',
1371 xa_ratio=>0.13, ya_ratio=>0.13, xb_ratio=>0.87, yb_ratio=>0.87,
1372 segments => Imager::Fountain->simple(positions=>[0, 1],
1373 colors=>[ NC('FFC0C0'), NC('FF0000') ]),
1375 { fountain=>'linear',
1376 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1377 segments => Imager::Fountain->simple(positions=>[0, 1],
1378 colors=>[ NC('C0FFC0'), NC('00FF00') ]),
1380 { fountain=>'linear',
1381 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1382 segments => Imager::Fountain->simple(positions=>[0, 1],
1383 colors=>[ NC('C0C0FF'), NC('0000FF') ]),
1385 { fountain=>'linear',
1386 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1387 segments => Imager::Fountain->simple(positions=>[0, 1],
1388 colors=>[ NC('FFFFC0'), NC('FFFF00') ]),
1390 { fountain=>'linear',
1391 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1392 segments => Imager::Fountain->simple(positions=>[0, 1],
1393 colors=>[ NC('C0FFFF'), NC('00FFFF') ]),
1395 { fountain=>'linear',
1396 xa_ratio=>0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1397 segments => Imager::Fountain->simple(positions=>[0, 1],
1398 colors=>[ NC('FFC0FF'), NC('FF00FF') ]),
1402 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1405 { shape => 'circle', radius => 4 },
1406 { shape => 'square', radius => 4 },
1407 { shape => 'diamond', radius => 4 },
1408 { shape => 'triangle', radius => 4 },
1409 { shape => 'x', radius => 4 },
1410 { shape => 'plus', radius => 4 },
1412 back=>{ fountain=>'linear',
1413 xa_ratio=>0, ya_ratio=>0,
1414 xb_ratio=>1.0, yb_ratio=>1.0,
1415 segments=>Imager::Fountain->simple
1416 ( positions=>[0, 1],
1417 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1419 negative_bg=>'EEEEEE',
1421 features=>{ dropshadow=>1 },
1427 { fountain=>'radial',
1428 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1429 segments => Imager::Fountain->simple(positions=>[0, 1],
1430 colors=>[ NC('FF8080'), NC('FF0000') ]),
1432 { fountain=>'radial',
1433 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1434 segments => Imager::Fountain->simple(positions=>[0, 1],
1435 colors=>[ NC('80FF80'), NC('00FF00') ]),
1437 { fountain=>'radial',
1438 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1439 segments => Imager::Fountain->simple(positions=>[0, 1],
1440 colors=>[ NC('808080FF'), NC('0000FF') ]),
1442 { fountain=>'radial',
1443 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1444 segments => Imager::Fountain->simple(positions=>[0, 1],
1445 colors=>[ NC('FFFF80'), NC('FFFF00') ]),
1447 { fountain=>'radial',
1448 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1449 segments => Imager::Fountain->simple(positions=>[0, 1],
1450 colors=>[ NC('80FFFF'), NC('00FFFF') ]),
1452 { fountain=>'radial',
1453 xa_ratio=>0.5, ya_ratio=>0.5, xb_ratio=>1.0, yb_ratio=>0.5,
1454 segments => Imager::Fountain->simple(positions=>[0, 1],
1455 colors=>[ NC('FF80FF'), NC('FF00FF') ]),
1459 qw(FF0000 00FF00 0000FF C0C000 00C0C0 FF00FF)
1461 back=>{ fountain=>'linear',
1462 xa_ratio=>0, ya_ratio=>0,
1463 xb_ratio=>1.0, yb_ratio=>1.0,
1464 segments=>Imager::Fountain->simple
1465 ( positions=>[0, 1],
1466 colors=>[ NC('6060FF'), NC('60FF60') ]) },
1468 negative_bg=>'EEEEEE',
1473 $styles{'ocean'} = {
1476 fountain =>'linear',
1477 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1478 segments => Imager::Fountain->simple(
1480 colors=>[ NC('EFEDCF'), NC('E6E2AF') ]),
1483 fountain =>'linear',
1484 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1485 segments => Imager::Fountain->simple(
1487 colors=>[ NC('DCD7AB'), NC('A7A37E') ]),
1490 fountain =>'linear',
1491 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1492 segments => Imager::Fountain->simple(
1494 colors=>[ NC('B2E5D4'), NC('80B4A2') ]),
1497 fountain =>'linear',
1498 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1499 segments => Imager::Fountain->simple(
1501 colors=>[ NC('7aaab9'), NC('046380') ]),
1504 fountain =>'linear',
1505 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1506 segments => Imager::Fountain->simple(
1508 colors=>[ NC('c3b8e9'), NC('877EA7') ]),
1511 fountain =>'linear',
1512 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1513 segments => Imager::Fountain->simple(
1515 colors=>[ NC('A3DF9A'), NC('67A35E') ]),
1518 fountain =>'linear',
1519 xa_ratio => 0, ya_ratio=>0, xb_ratio=>1.0, yb_ratio=>1.0,
1520 segments => Imager::Fountain->simple(
1522 colors=>[ NC('E19C98'), NC('B4726F') ]),
1526 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1529 negative_bg=>'EEEEEE',
1531 features=>{ dropshadow=>1 },
1535 $styles{'ocean_flat'} = {
1538 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1541 qw(E6E2AF A7A37E 80B4A2 046380 877EA7 67A35E B4726F)
1544 negative_bg=>'EEEEEE',
1546 features=>{ dropshadow=>1 },
1551 =item $self->_style_setup(\%opts)
1553 Uses the values from %opts, the custom style set by methods, the style
1554 set by the style parameter or the set_style() method and the built in
1555 chart defaults to build a working style.
1557 The working style features member is also populated with the active
1558 features for the chart.
1560 The working style is stored in the C<_style> member of $self.
1565 my ($self, $opts) = @_;
1566 my $style_defs = $self->_style_defs;
1569 my $pre_def_style = $self->_get_style($opts);
1570 my $api_style = $self->{'custom_style'} || {};
1571 $style = $styles{$pre_def_style} if $pre_def_style;
1573 $style ||= $styles{$def_style};
1575 my @search_list = ( $style_defs, $style, $api_style, $opts);
1578 my @composite = $self->_composite();
1580 @composite{@composite} = @composite;
1582 for my $src (@search_list) {
1583 for my $key (keys %$src) {
1584 if ($composite{$key}) {
1585 $work{$key} = {} unless exists $work{$key};
1586 if (ref $src->{$key}) {
1587 # some keys have sub values, especially text
1588 @{$work{$key}}{keys %{$src->{$key}}} = values %{$src->{$key}};
1591 # assume it's the text for a title or something
1592 $work{$key}{text} = $src->{$key};
1596 $work{$key} = $src->{$key}
1597 if defined $src->{$key}; # $opts with pmichauds new accessor handling
1602 # features are handled specially
1604 $work{features} = \%features;
1605 for my $src (@search_list) {
1606 if ($src->{features}) {
1607 if (ref $src->{features}) {
1608 if (ref($src->{features}) =~ /ARRAY/) {
1609 # just set those features
1610 for my $feature (@{$src->{features}}) {
1611 if ($feature =~ /^no(.+)$/) {
1612 delete $features{$1};
1615 $features{$feature} = 1;
1619 elsif (ref($src->{features}) =~ /HASH/) {
1620 if ($src->{features}{reset}) {
1621 $work{features} = {}; # only the ones the user specifies
1623 @{$work{features}}{keys %{$src->{features}}} =
1624 values(%{$src->{features}});
1628 # just set that single feature
1629 if ($src->{features} =~ /^no(.+)$/) {
1630 delete $features{$1};
1633 $features{$src->{features}} = 1;
1639 $self->{_style} = \%work;
1642 =item $self->_get_thing($name)
1644 Retrieve some general 'thing'.
1646 Supports the 'lookup(foo)' mechanism.
1648 Returns an empty list on failure.
1653 my ($self, $name, @depth) = @_;
1655 push(@depth, $name);
1657 if ($name =~ /^(\w+)\.(\w+)$/) {
1658 $what = $self->{_style}{$1}{$2};
1661 $what = $self->{_style}{$name};
1668 elsif ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1670 or return $self->_error("too many levels of recursion in lookup(@depth)");
1671 return $self->_get_thing($1, @depth);
1678 =item $self->_get_number($name)
1680 Retrieves a number from the style. The value in the style can be the
1681 number, or one of two functions:
1685 =item lookup(newname)
1687 Recursively looks up I<newname> in the style.
1689 =item scale(value1,value2)
1691 Each value can be a number or a name. Names are recursively looked up
1692 in the style and the product is returned.
1699 my ($self, $name, @depth) = @_;
1701 push(@depth, $name);
1703 if ($name =~ /^(\w+)\.(\w+)$/) {
1704 $what = $self->{_style}{$1}{$2};
1707 $what = $self->{_style}{$name};
1710 return $self->_error("$name is undef (@depth)");
1713 if ($what =~ /CODE/) {
1714 $what = $what->($self, $name);
1718 if ($what =~ /^lookup\(([\w.]+)\)$/) {
1720 or return $self->_error("too many levels of recursion in lookup (@depth)");
1721 return $self->_get_number($1, @depth);
1723 elsif ($what =~ /^scale\(
1724 ((?:[a-z][\w.]*)|$NUM_RE)
1726 ((?:[a-z][\w.]*)|$NUM_RE)\)$/x) {
1727 my ($left, $right) = ($1, $2);
1728 unless ($left =~ /^$NUM_RE$/) {
1730 or return $self->_error("too many levels of recursion in scale (@depth)");
1731 $left = $self->_get_number($left, @depth);
1733 unless ($right =~ /^$NUM_RE$/) {
1735 or return $self->_error("too many levels of recursion in scale (@depth)");
1736 $right = $self->_get_number($right, @depth);
1738 return $left * $right;
1746 =item $self->_get_integer($name)
1748 Retrieves an integer from the style. This is a simple wrapper around
1749 _get_number() that rounds the result to an integer.
1751 Returns an empty list on failure.
1756 my ($self, $name, @depth) = @_;
1758 my $number = $self->_get_number($name, @depth)
1761 return sprintf("%.0f", $number);
1764 =item _get_color($name)
1766 Returns a color object of the given name from the style hash.
1768 Uses Imager::Color->new to translate normal scalars into color objects.
1770 Allows the lookup(name) mechanism.
1772 Returns an empty list on failure.
1777 my ($self, $name, @depth) = @_;
1779 push(@depth, $name);
1781 if ($name =~ /^(\w+)\.(\w+)$/) {
1782 $what = $self->{_style}{$1}{$2};
1785 $what = $self->{_style}{$name};
1789 or return $self->_error("$name was undefined (@depth)");
1791 unless (ref $what) {
1792 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1793 @depth < MAX_DEPTH or
1794 return $self->_error("too many levels of recursion in lookup (@depth)");
1796 return $self->_get_color($1, @depth);
1798 $what = Imager::Color->new($what);
1804 =item _translate_fill($what, $box)
1806 Given the value of a fill, either attempts to convert it into a fill
1807 list (one of C<<color=>$color_value, filled=>1>> or C<<fill=>{ fill
1808 parameters }>>), or to lookup another fill that is referred to with
1809 the 'lookup(name)' mechanism.
1811 This function does the fg and bg initialization for hatched fills, and
1812 translation of *_ratio for fountain fills (using the $box parameter).
1814 Returns an empty list on failure.
1818 sub _translate_fill {
1819 my ($self, $what, $box, @depth) = @_;
1822 if (UNIVERSAL::isa($what, "Imager::Color")) {
1823 return ( color=>Imager::Color->new($what), filled=>1 );
1827 # default to normal combine mode
1828 my %work = ( combine => 'normal', %$what );
1829 if ($what->{hatch}) {
1831 $work{fg} = $self->_get_color('fg')
1835 $work{bg} = $self->_get_color('bg')
1838 return ( fill=>\%work );
1840 elsif ($what->{fountain}) {
1841 for my $key (qw(xa ya xb yb)) {
1842 if (exists $work{"${key}_ratio"}) {
1844 $work{$key} = $box->[0] + $work{"${key}_ratio"}
1845 * ($box->[2] - $box->[0]);
1848 $work{$key} = $box->[1] + $work{"${key}_ratio"}
1849 * ($box->[3] - $box->[1]);
1853 return ( fill=>\%work );
1856 return ( fill=> \%work );
1861 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1862 return $self->_get_fill($1, $box, @depth);
1865 # assumed to be an Imager::Color single value
1866 return ( color=>Imager::Color->new($what), filled=>1 );
1871 =item _data_fill($index, $box)
1873 Retrieves the fill parameters for a data area fill.
1878 my ($self, $index, $box) = @_;
1880 my $fills = $self->{_style}{fills};
1881 return $self->_translate_fill($fills->[$index % @$fills], $box,
1886 my ($self, $index) = @_;
1888 my $colors = $self->{'_style'}{'colors'} || [];
1889 my $fills = $self->{'_style'}{'fills'} || [];
1891 # Try to just use a fill, so non-fountain styles don't need
1892 # to have a duplicated set of fills and colors
1893 my $fill = $fills->[$index % @$fills];
1899 return $colors->[$index % @$colors] || '000000';
1904 =item _get_fill($name, $box)
1906 Retrieves fill parameters for a named fill.
1911 my ($self, $name, $box, @depth) = @_;
1913 push(@depth, $name);
1915 if ($name =~ /^(\w+)\.(\w+)$/) {
1916 $what = $self->{_style}{$1}{$2};
1919 $what = $self->{_style}{$name};
1923 or return $self->_error("no fill $name found");
1925 return $self->_translate_fill($what, $box, @depth);
1928 =item _get_line($name)
1930 Return color (and possibly other) parameters for drawing a line with
1936 my ($self, $name, @depth) = @_;
1938 push (@depth, $name);
1940 if ($name =~ /^(\w+)\.(\w+)$/) {
1941 $what = $self->{_style}{$1}{$2};
1944 $what = $self->{_style}{$name};
1948 or return $self->_error("no line style $name found");
1951 if (eval { $what->isa("Imager::Color") }) {
1954 if (ref $what eq "HASH") {
1955 # allow each kep to be looked up
1958 if ($work{color} =~ /^lookup\((.*)\)$/) {
1959 $work{color} = $self->_get_color($1, @depth);
1961 for my $key (keys %work) {
1962 $key eq "color" and next;
1964 if ($work{$key} =~ /^lookup\((.*)\)$/) {
1965 $work{$key} = $self->_get_thing($1);
1971 return ( color => Imager::Color->new(@$what) );
1974 if ($what =~ /^lookup\((\w+(?:\.\w+)?)\)$/) {
1976 or return $self->_error("too many levels of recursion in lookup (@depth)");
1977 return $self->_get_line($1, @depth);
1980 # presumably a text color
1981 my $color = Imager::Color->new($what)
1982 or return $self->_error("Could not translate $what as a color: ".Imager->errstr);
1984 return ( color => $color );
1991 Builds the image object for the graph and fills it with the background
1999 my $width = $self->_get_number('width') || 256;
2000 my $height = $self->_get_number('height') || 256;
2001 my $channels = $self->{_style}{channels};
2005 my $img = Imager->new(xsize=>$width, ysize=>$height, channels=>$channels)
2006 or return $self->_error("Error creating image: " . Imager->errstr);
2008 $img->box($self->_get_fill('back', [ 0, 0, $width-1, $height-1]));
2010 $self->{_image} = $img;
2018 return $self->{'_image'};
2021 =item _text_style($name)
2023 Returns parameters suitable for calls to Imager::Font's bounding_box()
2024 and draw() methods intended for use in defining text styles.
2026 Returns an empty list on failure.
2028 Returns the following attributes: font, color, size, aa, sizew
2034 my ($self, $name) = @_;
2038 if ($self->{_style}{$name}) {
2039 %work = %{$self->{_style}{$name}};
2042 %work = %{$self->{_style}{text}};
2045 or return $self->_error("$name has no font parameter");
2047 $work{font} = $self->_get_thing("$name.font")
2048 or return $self->_error("No $name.font defined, either set $name.font or font to a font");
2049 UNIVERSAL::isa($work{font}, "Imager::Font")
2050 or return $self->_error("$name.font is not a font");
2051 if ($work{color} && !ref $work{color}) {
2052 $work{color} = $self->_get_color("$name.color")
2055 $work{size} = $self->_get_number("$name.size");
2056 $work{sizew} = $self->_get_number("$name.sizew")
2058 $work{aa} = $self->_get_number("$name.aa");
2063 =item _text_bbox($text, $name)
2065 Returns a bounding box for the specified $text as styled by $name.
2067 Returns an empty list on failure.
2072 my ($self, $text, $name) = @_;
2074 my %text_info = $self->_text_style($name)
2077 my @bbox = $text_info{font}->bounding_box(%text_info, string=>$text,
2083 =item _line_style($name)
2085 Return parameters suitable for calls to Imager's line(), polyline(),
2088 For now this returns only color and aa parameters, but future releases
2089 of Imager may support extra parameters.
2094 my ($self, $name) = @_;
2097 $line{color} = $self->_get_color("$name.line")
2099 $line{aa} = $self->_get_number("$name.lineaa");
2100 defined $line{aa} or $line{aa} = $self->_get_number("aa");
2106 my ($self, $box, $chart_box, $name) = @_;
2108 my $halign = $self->{_style}{$name}{halign}
2109 or $self->_error("no halign for $name");
2110 my $valign = $self->{_style}{$name}{valign};
2112 if ($halign eq 'right') {
2113 $box->[0] += $chart_box->[2] - $box->[2];
2115 elsif ($halign eq 'left') {
2116 $box->[0] = $chart_box->[0];
2118 elsif ($halign eq 'center' || $halign eq 'centre') {
2119 $box->[0] = ($chart_box->[0] + $chart_box->[2] - $box->[2])/2;
2122 return $self->_error("invalid halign $halign for $name");
2125 if ($valign eq 'top') {
2126 $box->[1] = $chart_box->[1];
2128 elsif ($valign eq 'bottom') {
2129 $box->[1] = $chart_box->[3] - $box->[3];
2131 elsif ($valign eq 'center' || $valign eq 'centre') {
2132 $box->[1] = ($chart_box->[1] + $chart_box->[3] - $box->[3])/2;
2135 return $self->_error("invalid valign $valign for $name");
2137 $box->[2] += $box->[0];
2138 $box->[3] += $box->[1];
2142 my ($self, $chart_box, $object_box) = @_;
2146 if ($object_box->[0] - $chart_box->[0]
2147 < $chart_box->[2] - $object_box->[2]) {
2148 $areax = ($object_box->[2] - $chart_box->[0])
2149 * ($chart_box->[3] - $chart_box->[1]);
2152 $areax = ($chart_box->[2] - $object_box->[0])
2153 * ($chart_box->[3] - $chart_box->[1]);
2156 if ($object_box->[1] - $chart_box->[1]
2157 < $chart_box->[3] - $object_box->[3]) {
2158 $areay = ($object_box->[3] - $chart_box->[1])
2159 * ($chart_box->[2] - $chart_box->[0]);
2162 $areay = ($chart_box->[3] - $object_box->[1])
2163 * ($chart_box->[2] - $chart_box->[0]);
2166 if ($areay < $areax) {
2167 if ($object_box->[1] - $chart_box->[1]
2168 < $chart_box->[3] - $object_box->[3]) {
2169 $chart_box->[1] = $object_box->[3];
2172 $chart_box->[3] = $object_box->[1];
2176 if ($object_box->[0] - $chart_box->[0]
2177 < $chart_box->[2] - $object_box->[2]) {
2178 $chart_box->[0] = $object_box->[2];
2181 $chart_box->[2] = $object_box->[0];
2187 my ($self, $img, $labels, $chart_box) = @_;
2189 my $orient = $self->_get_thing('legend.orientation');
2190 defined $orient or $orient = 'vertical';
2192 if ($orient eq 'vertical') {
2193 return $self->_draw_legend_vertical($img, $labels, $chart_box);
2195 elsif ($orient eq 'horizontal') {
2196 return $self->_draw_legend_horizontal($img, $labels, $chart_box);
2199 return $self->_error("Unknown legend.orientation $orient");
2203 sub _draw_legend_horizontal {
2204 my ($self, $img, $labels, $chart_box) = @_;
2206 defined(my $padding = $self->_get_integer('legend.padding'))
2208 my $patchsize = $self->_get_integer('legend.patchsize')
2210 defined(my $gap = $self->_get_integer('legend.patchgap'))
2213 my $minrowsize = $patchsize + $gap;
2214 my ($width, $height) = (0,0);
2215 my $row_height = $minrowsize;
2219 for my $label (@$labels) {
2220 my @text_box = $self->_text_bbox($label, 'legend')
2222 push(@sizes, \@text_box);
2223 my $entry_width = $patchsize + $gap + $text_box[2];
2225 # never re-wrap the first entry
2226 push @offsets, [ 0, $height ];
2229 if ($pos + $gap + $entry_width > $chart_box->[2]) {
2231 $height += $row_height;
2233 push @offsets, [ $pos, $height ];
2235 my $entry_right = $pos + $entry_width;
2236 $pos += $gap + $entry_width;
2237 $entry_right > $width and $width = $entry_right;
2238 if ($text_box[3] > $row_height) {
2239 $row_height = $text_box[3];
2242 $height += $row_height;
2243 my @box = ( 0, 0, $width + $padding * 2, $height + $padding * 2 );
2244 my $outsidepadding = 0;
2245 if ($self->{_style}{legend}{border}) {
2246 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2248 $box[2] += 2 * $outsidepadding;
2249 $box[3] += 2 * $outsidepadding;
2251 $self->_align_box(\@box, $chart_box, 'legend')
2253 if ($self->{_style}{legend}{fill}) {
2254 $img->box(xmin=>$box[0]+$outsidepadding,
2255 ymin=>$box[1]+$outsidepadding,
2256 xmax=>$box[2]-$outsidepadding,
2257 ymax=>$box[3]-$outsidepadding,
2258 $self->_get_fill('legend.fill', \@box));
2260 $box[0] += $outsidepadding;
2261 $box[1] += $outsidepadding;
2262 $box[2] -= $outsidepadding;
2263 $box[3] -= $outsidepadding;
2264 my %text_info = $self->_text_style('legend')
2267 if ($self->{_style}{legend}{patchborder}) {
2268 $patchborder = $self->_get_color('legend.patchborder')
2273 for my $label (@$labels) {
2274 my ($left, $top) = @{$offsets[$dataindex]};
2275 $left += $box[0] + $padding;
2276 $top += $box[1] + $padding;
2277 my $textpos = $left + $patchsize + $gap;
2278 my @patchbox = ( $left, $top,
2279 $left + $patchsize, $top + $patchsize );
2280 my @fill = $self->_data_fill($dataindex, \@patchbox)
2282 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2283 ymax=>$top + $patchsize, @fill);
2284 if ($self->{_style}{legend}{patchborder}) {
2285 $img->box(xmin=>$left, ymin=>$top, xmax=>$left + $patchsize,
2286 ymax=>$top + $patchsize,
2287 color=>$patchborder);
2289 $img->string(%text_info, x=>$textpos, 'y'=>$top + $patchsize,
2294 if ($self->{_style}{legend}{border}) {
2295 my $border_color = $self->_get_color('legend.border')
2297 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2298 color=>$border_color);
2300 $self->_remove_box($chart_box, \@box);
2304 sub _draw_legend_vertical {
2305 my ($self, $img, $labels, $chart_box) = @_;
2307 defined(my $padding = $self->_get_integer('legend.padding'))
2309 my $patchsize = $self->_get_integer('legend.patchsize')
2311 defined(my $gap = $self->_get_integer('legend.patchgap'))
2313 my $minrowsize = $patchsize + $gap;
2314 my ($width, $height) = (0,0);
2316 for my $label (@$labels) {
2317 my @box = $self->_text_bbox($label, 'legend')
2319 push(@sizes, \@box);
2320 $width = $box[2] if $box[2] > $width;
2321 if ($minrowsize > $box[3]) {
2322 $height += $minrowsize;
2329 $width + $patchsize + $padding * 2 + $gap,
2330 $height + $padding * 2 - $gap);
2331 my $outsidepadding = 0;
2332 if ($self->{_style}{legend}{border}) {
2333 defined($outsidepadding = $self->_get_integer('legend.outsidepadding'))
2335 $box[2] += 2 * $outsidepadding;
2336 $box[3] += 2 * $outsidepadding;
2338 $self->_align_box(\@box, $chart_box, 'legend')
2340 if ($self->{_style}{legend}{fill}) {
2341 $img->box(xmin=>$box[0]+$outsidepadding,
2342 ymin=>$box[1]+$outsidepadding,
2343 xmax=>$box[2]-$outsidepadding,
2344 ymax=>$box[3]-$outsidepadding,
2345 $self->_get_fill('legend.fill', \@box));
2347 $box[0] += $outsidepadding;
2348 $box[1] += $outsidepadding;
2349 $box[2] -= $outsidepadding;
2350 $box[3] -= $outsidepadding;
2351 my $ypos = $box[1] + $padding;
2352 my $patchpos = $box[0]+$padding;
2353 my $textpos = $patchpos + $patchsize + $gap;
2354 my %text_info = $self->_text_style('legend')
2357 if ($self->{_style}{legend}{patchborder}) {
2358 $patchborder = $self->_get_color('legend.patchborder')
2362 for my $label (@$labels) {
2363 my @patchbox = ( $patchpos - $patchsize/2, $ypos - $patchsize/2,
2364 $patchpos + $patchsize * 3 / 2, $ypos + $patchsize*3/2 );
2367 if ($self->_draw_flat_legend()) {
2368 @fill = (color => $self->_data_color($dataindex), filled => 1);
2371 @fill = $self->_data_fill($dataindex, \@patchbox)
2374 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2375 ymax=>$ypos + $patchsize, @fill);
2376 if ($self->{_style}{legend}{patchborder}) {
2377 $img->box(xmin=>$patchpos, ymin=>$ypos, xmax=>$patchpos + $patchsize,
2378 ymax=>$ypos + $patchsize,
2379 color=>$patchborder);
2381 $img->string(%text_info, x=>$textpos, 'y'=>$ypos + $patchsize,
2384 my $step = $patchsize + $gap;
2385 if ($minrowsize < $sizes[$dataindex][3]) {
2386 $ypos += $sizes[$dataindex][3];
2389 $ypos += $minrowsize;
2393 if ($self->{_style}{legend}{border}) {
2394 my $border_color = $self->_get_color('legend.border')
2396 $img->box(xmin=>$box[0], ymin=>$box[1], xmax=>$box[2], ymax=>$box[3],
2397 color=>$border_color);
2399 $self->_remove_box($chart_box, \@box);
2404 my ($self, $img, $chart_box) = @_;
2406 my $title = $self->{_style}{title}{text};
2407 my @box = $self->_text_bbox($title, 'title')
2411 $self->_align_box(\@box, $chart_box, 'title');
2412 my %text_info = $self->_text_style('title')
2414 $img->string(%text_info, x=>$box[0], 'y'=>$box[3] + $yoff, text=>$title);
2415 $self->_remove_box($chart_box, \@box);
2420 my ($self, $box) = @_;
2422 if ($box->[2] - $box->[0] > $box->[3] - $box->[1]) {
2423 return $box->[3] - $box->[1];
2426 return $box->[2] - $box->[0];
2430 sub _draw_flat_legend {
2436 Returns a list of style fields that are stored as composites, and
2437 should be merged instead of just being replaced.
2442 qw(title legend text label dropshadow outline callout graph);
2445 sub _filter_region {
2446 my ($self, $img, $left, $top, $right, $bottom, $filter) = @_;
2448 unless (ref $filter) {
2450 $filter = $self->_get_thing($name)
2453 or return $self->_error("no type for filter $name");
2456 $left > 0 or $left = 0;
2457 $top > 0 or $top = 0;
2459 my $masked = $img->masked(left=>$left, top=>$top,
2460 right=>$right, bottom=>$bottom);
2461 $masked->filter(%$filter);
2464 =item _line(x1 => $x1, y1 => $y1, ..., style => $style)
2466 Wrapper for line drawing, implements styles Imager doesn't.
2468 Currently styles are limited to horizontal and vertical lines.
2473 my ($self, %opts) = @_;
2475 my $img = delete $opts{img}
2476 or die "No img supplied to _line()";
2477 my $style = delete $opts{style} || "solid";
2479 if ($style eq "solid" || ($opts{x1} != $opts{x2} && $opts{y1} != $opts{y2})) {
2480 return $img->line(%opts);
2482 elsif ($style eq 'dashed' || $style eq 'dotted') {
2483 my ($x1, $y1, $x2, $y2) = delete @opts{qw/x1 y1 x2 y2/};
2484 # the line is vertical or horizontal, so swapping doesn't hurt
2485 $x1 > $x2 and ($x1, $x2) = ($x2, $x1);
2486 $y1 > $y2 and ($y1, $y2) = ($y2, $y1);
2487 my ($stepx, $stepy) = ( 0, 0 );
2488 my $step_size = $style eq "dashed" ? 8 : 2;
2489 my ($counter, $count_end);
2491 $stepy = $step_size;
2492 ($counter, $count_end) = ($y1, $y2);
2495 $stepx = $step_size;
2496 ($counter, $count_end) = ($x1, $x2);
2498 my ($x, $y) = ($x1, $y1);
2499 while ($counter < $count_end) {
2500 if ($style eq "dotted") {
2501 $img->setpixel(x => $x, y => $y, color => $opts{color});
2504 my $xe = $stepx ? $x + $stepx / 2 - 1 : $x;
2505 $xe > $x2 and $xe = $x2;
2506 my $ye = $stepy ? $y + $stepy / 2 - 1 : $y;
2507 $ye > $y2 and $ye = $y2;
2508 $img->line(x1 => $x, y1 => $y, x2 => $xe, y2 => $ye, %opts);
2510 $counter += $step_size;
2518 $self->_error("Unknown line style $style");
2523 =item _box(xmin ..., style => $style)
2525 A wrapper for drawing styled box outlines.
2530 my ($self, %opts) = @_;
2532 my $style = delete $opts{style} || "solid";
2533 my $img = delete $opts{img}
2534 or die "No img supplied to _box";
2536 if ($style eq "solid") {
2537 return $img->box(%opts);
2540 my $box = delete $opts{box};
2541 # replicate Imager's defaults
2542 my %work_opts = ( xmin => 0, ymin => 0, xmax => $img->getwidth() - 1, ymax => $img->getheight() -1, %opts, style => $style, img => $img );
2543 my ($xmin, $ymin, $xmax, $ymax) = delete @work_opts{qw/xmin ymin xmax ymax/};
2545 ($xmin, $ymin, $xmax, $ymax) = @$box;
2547 $xmin > $xmax and ($xmin, $xmax) = ($xmax, $xmin);
2548 $ymin > $ymax and ($ymin, $ymax) = ($ymax, $ymin);
2550 if ($xmax - $xmin > 1) {
2551 $self->_line(x1 => $xmin+1, y1 => $ymin, x2 => $xmax-1, y2 => $ymin, %work_opts);
2552 $self->_line(x1 => $xmin+1, y1 => $ymax, x2 => $xmax-1, y2 => $ymax, %work_opts);
2554 $self->_line(x1 => $xmin, y1 => $ymin, x2 => $xmin, y2 => $ymax, %work_opts);
2555 return $self->_line(x1 => $xmax, y1 => $ymin, x2 => $xmax, y2 => $ymax, %work_opts);
2559 =item _feature_enabled($feature_name)
2561 Check if the given feature is enabled in the work style.
2565 sub _feature_enabled {
2566 my ($self, $name) = @_;
2568 return $self->{_style}{features}{$name};
2578 Imager::Graph::Pie(3), Imager(3), perl(1).
2582 Tony Cook <tony@develop-help.com>
2586 Imager::Graph is licensed under the same terms as perl itself.
2590 Addi for producing a cool imaging module. :)