File Coverage

blib/lib/Excel/Writer/XLSX/Chart.pm
Criterion Covered Total %
statement 1887 1964 96.0
branch 592 668 88.6
condition 120 157 76.4
subroutine 217 218 99.5
pod 18 20 90.0
total 2834 3027 93.6


line stmt bran cond sub pod time code
1             package Excel::Writer::XLSX::Chart;
2              
3             ###############################################################################
4             #
5             # Chart - A class for writing Excel Charts.
6             #
7             #
8             # Used in conjunction with Excel::Writer::XLSX.
9             #
10             # Copyright 2000-2019, John McNamara, jmcnamara@cpan.org
11             #
12             # Documentation after __END__
13             #
14              
15             # perltidy with the following options: -mbl=2 -pt=0 -nola
16              
17 1040     1040   18077 use 5.008002;
  1040         3704  
18 1040     1040   5614 use strict;
  1040         2157  
  1040         20341  
19 1040     1040   5059 use warnings;
  1040         2057  
  1040         23024  
20 1040     1040   5175 use Carp;
  1040         2118  
  1040         50841  
21 1040     1040   6382 use Excel::Writer::XLSX::Format;
  1040         2111  
  1040         30300  
22 1040     1040   5831 use Excel::Writer::XLSX::Package::XMLwriter;
  1040         2097  
  1040         38963  
23 1040         18868244 use Excel::Writer::XLSX::Utility qw(xl_cell_to_rowcol
24             xl_rowcol_to_cell
25             xl_col_to_name xl_range
26             xl_range_formula
27 1040     1040   5726 quote_sheetname );
  1040         2136  
28              
29             our @ISA = qw(Excel::Writer::XLSX::Package::XMLwriter);
30             our $VERSION = '1.03';
31              
32              
33             ###############################################################################
34             #
35             # factory()
36             #
37             # Factory method for returning chart objects based on their class type.
38             #
39             sub factory {
40              
41 405     405 0 1139 my $current_class = shift;
42 405         974 my $chart_subclass = shift;
43              
44 405         1823 $chart_subclass = ucfirst lc $chart_subclass;
45              
46 405         1491 my $module = "Excel::Writer::XLSX::Chart::" . $chart_subclass;
47              
48 405         29604 eval "require $module";
49              
50             # TODO. Need to re-raise this error from Workbook::add_chart().
51 405 50       2581 die "Chart type '$chart_subclass' not supported in add_chart()\n" if $@;
52              
53 405         1186 my $fh = undef;
54 405         3296 return $module->new( $fh, @_ );
55             }
56              
57              
58             ###############################################################################
59             #
60             # new()
61             #
62             # Default constructor for sub-classes.
63             #
64             sub new {
65              
66 491     491 0 62407 my $class = shift;
67 491         1044 my $fh = shift;
68 491         2667 my $self = Excel::Writer::XLSX::Package::XMLwriter->new( $fh );
69              
70 491         2297 $self->{_subtype} = shift;
71 491         1787 $self->{_sheet_type} = 0x0200;
72 491         1199 $self->{_orientation} = 0x0;
73 491         1317 $self->{_series} = [];
74 491         1353 $self->{_embedded} = 0;
75 491         1262 $self->{_id} = -1;
76 491         1588 $self->{_series_index} = 0;
77 491         1160 $self->{_style_id} = 2;
78 491         1200 $self->{_axis_ids} = [];
79 491         1250 $self->{_axis2_ids} = [];
80 491         1195 $self->{_cat_has_num_fmt} = 0;
81 491         1152 $self->{_requires_category} = 0;
82 491         1205 $self->{_legend} = {};
83 491         1261 $self->{_cat_axis_position} = 'b';
84 491         1565 $self->{_val_axis_position} = 'l';
85 491         1223 $self->{_formula_ids} = {};
86 491         1252 $self->{_formula_data} = [];
87 491         1117 $self->{_horiz_cat_axis} = 0;
88 491         1103 $self->{_horiz_val_axis} = 1;
89 491         1171 $self->{_protection} = 0;
90 491         1120 $self->{_chartarea} = {};
91 491         1224 $self->{_plotarea} = {};
92 491         1126 $self->{_x_axis} = {};
93 491         2050 $self->{_y_axis} = {};
94 491         1821 $self->{_y2_axis} = {};
95 491         1157 $self->{_x2_axis} = {};
96 491         1221 $self->{_chart_name} = '';
97 491         1151 $self->{_show_blanks} = 'gap';
98 491         1094 $self->{_show_hidden_data} = 0;
99 491         1215 $self->{_show_crosses} = 1;
100 491         1766 $self->{_width} = 480;
101 491         1243 $self->{_height} = 288;
102 491         1169 $self->{_x_scale} = 1;
103 491         1202 $self->{_y_scale} = 1;
104 491         1165 $self->{_x_offset} = 0;
105 491         1089 $self->{_y_offset} = 0;
106 491         1064 $self->{_table} = undef;
107 491         2551 $self->{_smooth_allowed} = 0;
108 491         2148 $self->{_cross_between} = 'between';
109 491         1046 $self->{_date_category} = 0;
110 491         1892 $self->{_already_inserted} = 0;
111 491         1654 $self->{_combined} = undef;
112 491         1087 $self->{_is_secondary} = 0;
113              
114 491         28211 $self->{_label_positions} = {};
115 491         20690 $self->{_label_position_default} = '';
116              
117 491         2536 bless $self, $class;
118 491         2746 $self->_set_default_properties();
119 491         1650 return $self;
120             }
121              
122              
123             ###############################################################################
124             #
125             # _assemble_xml_file()
126             #
127             # Assemble and write the XML file.
128             #
129             sub _assemble_xml_file {
130              
131 394     394   1090 my $self = shift;
132              
133 394         2880 $self->xml_declaration();
134              
135             # Write the c:chartSpace element.
136 394         3211 $self->_write_chart_space();
137              
138             # Write the c:lang element.
139 394         2903 $self->_write_lang();
140              
141             # Write the c:style element.
142 394         2709 $self->_write_style();
143              
144             # Write the c:protection element.
145 394         2613 $self->_write_protection();
146              
147             # Write the c:chart element.
148 394         2546 $self->_write_chart();
149              
150             # Write the c:spPr element for the chartarea formatting.
151 394         2123 $self->_write_sp_pr( $self->{_chartarea} );
152              
153             # Write the c:printSettings element.
154 394 100       3561 $self->_write_print_settings() if $self->{_embedded};
155              
156             # Close the worksheet tag.
157 394         2675 $self->xml_end_tag( 'c:chartSpace' );
158              
159             # Close the XML writer filehandle.
160 394         3197 $self->xml_get_fh()->close();
161             }
162              
163              
164             ###############################################################################
165             #
166             # Public methods.
167             #
168             ###############################################################################
169              
170              
171             ###############################################################################
172             #
173             # add_series()
174             #
175             # Add a series and it's properties to a chart.
176             #
177             sub add_series {
178              
179 943     943 1 8175 my $self = shift;
180 943         3658 my %arg = @_;
181              
182             # Check that the required input has been specified.
183 943 50       3055 if ( !exists $arg{values} ) {
184 0         0 croak "Must specify 'values' in add_series()";
185             }
186              
187 943 50 66     3585 if ( $self->{_requires_category} && !exists $arg{categories} ) {
188 0         0 croak "Must specify 'categories' in add_series() for this chart type";
189             }
190              
191 943 50       1663 if ( @{ $self->{_series} } == 255 ) {
  943         2988  
192 0         0 carp "The maxiumn number of series that can be added to an "
193             . "Excel Chart is 255";
194             return
195 0         0 }
196              
197             # Convert aref params into a formula string.
198 943         4181 my $values = $self->_aref_to_formula( $arg{values} );
199 943         3142 my $categories = $self->_aref_to_formula( $arg{categories} );
200              
201             # Switch name and name_formula parameters if required.
202             my ( $name, $name_formula ) =
203 943         5031 $self->_process_names( $arg{name}, $arg{name_formula} );
204              
205             # Get an id for the data equivalent to the range formula.
206 943         5143 my $cat_id = $self->_get_data_id( $categories, $arg{categories_data} );
207 943         3228 my $val_id = $self->_get_data_id( $values, $arg{values_data} );
208 943         3295 my $name_id = $self->_get_data_id( $name_formula, $arg{name_data} );
209              
210             # Set the line properties for the series.
211 943         4301 my $line = $self->_get_line_properties( $arg{line} );
212              
213             # Allow 'border' as a synonym for 'line' in bar/column style charts.
214 943 100       3223 if ( $arg{border} ) {
215 7         25 $line = $self->_get_line_properties( $arg{border} );
216             }
217              
218             # Set the fill properties for the series.
219 943         4115 my $fill = $self->_get_fill_properties( $arg{fill} );
220              
221             # Set the pattern properties for the series.
222 943         4537 my $pattern = $self->_get_pattern_properties( $arg{pattern} );
223              
224             # Set the gradient fill properties for the series.
225 943         4434 my $gradient = $self->_get_gradient_properties( $arg{gradient} );
226              
227             # Pattern fill overrides solid fill.
228 943 100       2788 if ( $pattern ) {
229 56         101 $fill = undef;
230             }
231              
232             # Gradient fill overrides solid and pattern fills.
233 943 100       2431 if ( $gradient ) {
234 11         26 $pattern = undef;
235 11         29 $fill = undef;
236             }
237              
238             # Set the marker properties for the series.
239 943         4259 my $marker = $self->_get_marker_properties( $arg{marker} );
240              
241             # Set the trendline properties for the series.
242 943         4828 my $trendline = $self->_get_trendline_properties( $arg{trendline} );
243              
244             # Set the line smooth property for the series.
245 943         2301 my $smooth = $arg{smooth};
246              
247             # Set the error bars properties for the series.
248 943         3972 my $y_error_bars = $self->_get_error_bars_properties( $arg{y_error_bars} );
249 943         3248 my $x_error_bars = $self->_get_error_bars_properties( $arg{x_error_bars} );
250              
251             # Set the point properties for the series.
252 943         4758 my $points = $self->_get_points_properties($arg{points});
253              
254             # Set the labels properties for the series.
255 943         4574 my $labels = $self->_get_labels_properties( $arg{data_labels} );
256              
257             # Set the "invert if negative" fill property.
258 943         2266 my $invert_if_neg = $arg{invert_if_negative};
259              
260             # Set the secondary axis properties.
261 943         1803 my $x2_axis = $arg{x2_axis};
262 943         1674 my $y2_axis = $arg{y2_axis};
263              
264             # Store secondary status for combined charts.
265 943 100 100     3868 if ($x2_axis || $y2_axis) {
266 13         38 $self->{_is_secondary} = 1;
267             }
268              
269             # Set the gap for Bar/Column charts.
270 943 100       2686 if ( defined $arg{gap} ) {
271 7 100       21 if ($y2_axis) {
272 2         5 $self->{_series_gap_2} = $arg{gap};
273             }
274             else {
275 5         16 $self->{_series_gap_1} = $arg{gap};
276             }
277             }
278              
279             # Set the overlap for Bar/Column charts.
280 943 100       2465 if ( defined $arg{overlap} ) {
281 7 100       16 if ($y2_axis) {
282 2         4 $self->{_series_overlap_2} = $arg{overlap};
283             }
284             else {
285 5         12 $self->{_series_overlap_1} = $arg{overlap};
286             }
287             }
288              
289             # Add the user supplied data to the internal structures.
290             %arg = (
291 943         12655 _values => $values,
292             _categories => $categories,
293             _name => $name,
294             _name_formula => $name_formula,
295             _name_id => $name_id,
296             _val_data_id => $val_id,
297             _cat_data_id => $cat_id,
298             _line => $line,
299             _fill => $fill,
300             _pattern => $pattern,
301             _gradient => $gradient,
302             _marker => $marker,
303             _trendline => $trendline,
304             _smooth => $smooth,
305             _labels => $labels,
306             _invert_if_neg => $invert_if_neg,
307             _x2_axis => $x2_axis,
308             _y2_axis => $y2_axis,
309             _points => $points,
310             _error_bars =>
311             { _x_error_bars => $x_error_bars, _y_error_bars => $y_error_bars },
312             );
313              
314              
315 943         2177 push @{ $self->{_series} }, \%arg;
  943         4395  
316             }
317              
318              
319             ###############################################################################
320             #
321             # set_x_axis()
322             #
323             # Set the properties of the X-axis.
324             #
325             sub set_x_axis {
326              
327 647     647 1 1894 my $self = shift;
328              
329 647         2775 my $axis = $self->_convert_axis_args( $self->{_x_axis}, @_ );
330              
331 647         2418 $self->{_x_axis} = $axis;
332             }
333              
334              
335             ###############################################################################
336             #
337             # set_y_axis()
338             #
339             # Set the properties of the Y-axis.
340             #
341             sub set_y_axis {
342              
343 773     773 1 1980 my $self = shift;
344              
345 773         2476 my $axis = $self->_convert_axis_args( $self->{_y_axis}, @_ );
346              
347 773         3104 $self->{_y_axis} = $axis;
348             }
349              
350              
351             ###############################################################################
352             #
353             # set_x2_axis()
354             #
355             # Set the properties of the secondary X-axis.
356             #
357             sub set_x2_axis {
358              
359 505     505 1 1245 my $self = shift;
360              
361 505         1979 my $axis = $self->_convert_axis_args( $self->{_x2_axis}, @_ );
362              
363 505         1829 $self->{_x2_axis} = $axis;
364             }
365              
366              
367             ###############################################################################
368             #
369             # set_y2_axis()
370             #
371             # Set the properties of the secondary Y-axis.
372             #
373             sub set_y2_axis {
374              
375 492     492 1 1127 my $self = shift;
376              
377 492         1739 my $axis = $self->_convert_axis_args( $self->{_y2_axis}, @_ );
378              
379 492         1706 $self->{_y2_axis} = $axis;
380             }
381              
382              
383             ###############################################################################
384             #
385             # set_title()
386             #
387             # Set the properties of the chart title.
388             #
389             sub set_title {
390              
391 21     21 1 277 my $self = shift;
392 21         108 my %arg = @_;
393              
394             my ( $name, $name_formula ) =
395 21         155 $self->_process_names( $arg{name}, $arg{name_formula} );
396              
397 21         115 my $data_id = $self->_get_data_id( $name_formula, $arg{data} );
398              
399 21         80 $self->{_title_name} = $name;
400 21         65 $self->{_title_formula} = $name_formula;
401 21         63 $self->{_title_data_id} = $data_id;
402              
403             # Set the font properties if present.
404 21         113 $self->{_title_font} = $self->_convert_font_args( $arg{name_font} );
405              
406             # Set the title layout.
407 21         139 $self->{_title_layout} = $self->_get_layout_properties( $arg{layout}, 1 );
408              
409             # Set the title overlay option.
410 21         64 $self->{_title_overlay} = $arg{overlay};
411              
412             # Set the no automatic title option.
413 21         100 $self->{_title_none} = $arg{none};
414             }
415              
416              
417             ###############################################################################
418             #
419             # set_legend()
420             #
421             # Set the properties of the chart legend.
422             #
423             sub set_legend {
424              
425 31     31 1 519 my $self = shift;
426              
427             # Convert the user defined properties to internal properties.
428 31         200 $self->{_legend} = $self->_get_legend_properties( @_ );
429             }
430              
431              
432             ###############################################################################
433             #
434             # set_plotarea()
435             #
436             # Set the properties of the chart plotarea.
437             #
438             sub set_plotarea {
439              
440 10     10 1 115 my $self = shift;
441              
442             # Convert the user defined properties to internal properties.
443 10         71 $self->{_plotarea} = $self->_get_area_properties( @_ );
444             }
445              
446              
447             ###############################################################################
448             #
449             # set_chartarea()
450             #
451             # Set the properties of the chart chartarea.
452             #
453             sub set_chartarea {
454              
455 10     10 1 143 my $self = shift;
456              
457             # Convert the user defined properties to internal properties.
458 10         72 $self->{_chartarea} = $self->_get_area_properties( @_ );
459             }
460              
461              
462             ###############################################################################
463             #
464             # set_style()
465             #
466             # Set on of the 48 built-in Excel chart styles. The default style is 2.
467             #
468             sub set_style {
469              
470 6     6 1 103 my $self = shift;
471 6 50       19 my $style_id = defined $_[0] ? $_[0] : 2;
472              
473 6 100 100     31 if ( $style_id < 0 || $style_id > 48 ) {
474 2         4 $style_id = 2;
475             }
476              
477 6         14 $self->{_style_id} = $style_id;
478             }
479              
480              
481             ###############################################################################
482             #
483             # show_blanks_as()
484             #
485             # Set the option for displaying blank data in a chart. The default is 'gap'.
486             #
487             sub show_blanks_as {
488              
489 6     6 1 48 my $self = shift;
490 6         14 my $option = shift;
491              
492 6 50       33 return unless $option;
493              
494 6         35 my %valid = (
495             gap => 1,
496             zero => 1,
497             span => 1,
498              
499             );
500              
501 6 50       22 if ( !exists $valid{$option} ) {
502 0         0 warn "Unknown show_blanks_as() option '$option'\n";
503 0         0 return;
504             }
505              
506 6         24 $self->{_show_blanks} = $option;
507             }
508              
509              
510             ###############################################################################
511             #
512             # show_hidden_data()
513             #
514             # Display data in hidden rows or columns.
515             #
516             sub show_hidden_data {
517              
518 1     1 1 8 my $self = shift;
519              
520 1         4 $self->{_show_hidden_data} = 1;
521             }
522              
523              
524             ###############################################################################
525             #
526             # set_size()
527             #
528             # Set dimensions or scale for the chart.
529             #
530             sub set_size {
531              
532 3     3 1 30 my $self = shift;
533 3         12 my %args = @_;
534              
535 3 100       31 $self->{_width} = $args{width} if $args{width};
536 3 100       13 $self->{_height} = $args{height} if $args{height};
537 3 100       12 $self->{_x_scale} = $args{x_scale} if $args{x_scale};
538 3 100       21 $self->{_y_scale} = $args{y_scale} if $args{y_scale};
539 3 100       12 $self->{_x_offset} = $args{x_offset} if $args{x_offset};
540 3 100       17 $self->{_y_offset} = $args{y_offset} if $args{y_offset};
541              
542             }
543              
544             # Backward compatibility with poorly chosen method name.
545             *size = *set_size;
546              
547              
548             ###############################################################################
549             #
550             # set_table()
551             #
552             # Set properties for an axis data table.
553             #
554             sub set_table {
555              
556 3     3 1 34 my $self = shift;
557 3         14 my %args = @_;
558              
559 3         18 my %table = (
560             _horizontal => 1,
561             _vertical => 1,
562             _outline => 1,
563             _show_keys => 0,
564             );
565              
566 3 100       23 $table{_horizontal} = $args{horizontal} if defined $args{horizontal};
567 3 100       12 $table{_vertical} = $args{vertical} if defined $args{vertical};
568 3 100       11 $table{_outline} = $args{outline} if defined $args{outline};
569 3 100       10 $table{_show_keys} = $args{show_keys} if defined $args{show_keys};
570 3         19 $table{_font} = $self->_convert_font_args( $args{font} );
571              
572 3         13 $self->{_table} = \%table;
573             }
574              
575              
576             ###############################################################################
577             #
578             # set_up_down_bars()
579             #
580             # Set properties for the chart up-down bars.
581             #
582             sub set_up_down_bars {
583              
584 3     3 1 40 my $self = shift;
585 3         11 my %args = @_;
586              
587             # Map border to line.
588 3 50       21 if ( defined $args{up}->{border} ) {
589 0         0 $args{up}->{line} = $args{up}->{border};
590             }
591 3 100       12 if ( defined $args{down}->{border} ) {
592 1         3 $args{down}->{line} = $args{down}->{border};
593             }
594              
595             # Set the up and down bar properties.
596 3         18 my $up_line = $self->_get_line_properties( $args{up}->{line} );
597 3         19 my $down_line = $self->_get_line_properties( $args{down}->{line} );
598 3         18 my $up_fill = $self->_get_fill_properties( $args{up}->{fill} );
599 3         13 my $down_fill = $self->_get_fill_properties( $args{down}->{fill} );
600              
601             $self->{_up_down_bars} = {
602 3         23 _up => {
603             _line => $up_line,
604             _fill => $up_fill,
605             },
606             _down => {
607             _line => $down_line,
608             _fill => $down_fill,
609             },
610             };
611             }
612              
613              
614             ###############################################################################
615             #
616             # set_drop_lines()
617             #
618             # Set properties for the chart drop lines.
619             #
620             sub set_drop_lines {
621              
622 4     4 1 43 my $self = shift;
623 4         13 my %args = @_;
624              
625             # Set the drop line properties.
626 4         21 my $line = $self->_get_line_properties( $args{line} );
627              
628 4         19 $self->{_drop_lines} = { _line => $line };
629             }
630              
631              
632             ###############################################################################
633             #
634             # set_high_low_lines()
635             #
636             # Set properties for the chart high-low lines.
637             #
638             sub set_high_low_lines {
639              
640 2     2 1 21 my $self = shift;
641 2         5 my %args = @_;
642              
643             # Set the drop line properties.
644 2         17 my $line = $self->_get_line_properties( $args{line} );
645              
646 2         11 $self->{_hi_low_lines} = { _line => $line };
647             }
648              
649              
650             ###############################################################################
651             #
652             # combine()
653             #
654             # Add another chart to create a combined chart.
655             #
656             sub combine {
657              
658 9     9 1 87 my $self = shift;
659 9         19 my $chart = shift;
660              
661 9         35 $self->{_combined} = $chart;
662             }
663              
664              
665             ###############################################################################
666             #
667             # Internal methods. The following section of methods are used for the internal
668             # structuring of the Chart object and file format.
669             #
670             ###############################################################################
671              
672              
673             ###############################################################################
674             #
675             # _convert_axis_args()
676             #
677             # Convert user defined axis values into private hash values.
678             #
679             sub _convert_axis_args {
680              
681 2417     2417   3988 my $self = shift;
682 2417         3564 my $axis = shift;
683 2417         3558 my %arg = ( %{ $axis->{_defaults} }, @_ );
  2417         10559  
684              
685             my ( $name, $name_formula ) =
686 2417         9895 $self->_process_names( $arg{name}, $arg{name_formula} );
687              
688 2417         9417 my $data_id = $self->_get_data_id( $name_formula, $arg{data} );
689              
690             $axis = {
691             _defaults => $axis->{_defaults},
692             _name => $name,
693             _formula => $name_formula,
694             _data_id => $data_id,
695             _reverse => $arg{reverse},
696             _min => $arg{min},
697             _max => $arg{max},
698             _minor_unit => $arg{minor_unit},
699             _major_unit => $arg{major_unit},
700             _minor_unit_type => $arg{minor_unit_type},
701             _major_unit_type => $arg{major_unit_type},
702             _log_base => $arg{log_base},
703             _crossing => $arg{crossing},
704             _position_axis => $arg{position_axis},
705             _position => $arg{position},
706             _label_position => $arg{label_position},
707             _label_align => $arg{label_align},
708             _num_format => $arg{num_format},
709             _num_format_linked => $arg{num_format_linked},
710             _interval_unit => $arg{interval_unit},
711             _interval_tick => $arg{interval_tick},
712 2417 100       29752 _visible => defined $arg{visible} ? $arg{visible} : 1,
713             _text_axis => 0,
714             };
715              
716             # Map major_gridlines properties.
717 2417 100 100     11049 if ( $arg{major_gridlines} && $arg{major_gridlines}->{visible} ) {
718             $axis->{_major_gridlines} =
719 781         3139 $self->_get_gridline_properties( $arg{major_gridlines} );
720             }
721              
722             # Map minor_gridlines properties.
723 2417 50 66     5559 if ( $arg{minor_gridlines} && $arg{minor_gridlines}->{visible} ) {
724             $axis->{_minor_gridlines} =
725 9         21 $self->_get_gridline_properties( $arg{minor_gridlines} );
726             }
727              
728             # Convert the display units.
729 2417         7110 $axis->{_display_units} = $self->_get_display_units( $arg{display_units} );
730 2417 100       6092 if ( defined $arg{display_units_visible} ) {
731 11         28 $axis->{_display_units_visible} = $arg{display_units_visible};
732             }
733             else {
734 2406         4284 $axis->{_display_units_visible} = 1;
735             }
736              
737             # Only use the first letter of bottom, top, left or right.
738 2417 100       5491 if ( defined $axis->{_position} ) {
739 495         2904 $axis->{_position} = substr lc $axis->{_position}, 0, 1;
740             }
741              
742             # Set the position for a category axis on or between the tick marks.
743 2417 100       5116 if ( defined $axis->{_position_axis} ) {
744 3 100       15 if ( $axis->{_position_axis} eq 'on_tick' ) {
    50          
745 2         6 $axis->{_position_axis} = 'midCat';
746             }
747             elsif ( $axis->{_position_axis} eq 'between' ) {
748              
749             # Doesn't need to be modified.
750             }
751             else {
752             # Otherwise use the default value.
753 0         0 $axis->{_position_axis} = undef;
754             }
755             }
756              
757             # Set the category axis as a date axis.
758 2417 100       5237 if ( $arg{date_axis} ) {
759 4         26 $self->{_date_category} = 1;
760             }
761              
762             # Set the category axis as a text axis.
763 2417 100       4904 if ( $arg{text_axis} ) {
764 1         3 $self->{_date_category} = 0;
765 1         2 $axis->{_text_axis} = 1;
766             }
767              
768              
769             # Set the font properties if present.
770 2417         6576 $axis->{_num_font} = $self->_convert_font_args( $arg{num_font} );
771 2417         6445 $axis->{_name_font} = $self->_convert_font_args( $arg{name_font} );
772              
773             # Set the axis name layout.
774 2417         7391 $axis->{_layout} = $self->_get_layout_properties( $arg{name_layout}, 1 );
775              
776             # Set the line properties for the axis.
777 2417         7384 $axis->{_line} = $self->_get_line_properties( $arg{line} );
778              
779             # Set the fill properties for the axis.
780 2417         7270 $axis->{_fill} = $self->_get_fill_properties( $arg{fill} );
781              
782             # Set the tick marker types.
783 2417         7300 $axis->{_minor_tick_mark} = $self->_get_tick_type($arg{minor_tick_mark});
784 2417         6391 $axis->{_major_tick_mark} = $self->_get_tick_type($arg{major_tick_mark});
785              
786              
787 2417         7099 return $axis;
788             }
789              
790              
791             ###############################################################################
792             #
793             # _convert_fonts_args()
794             #
795             # Convert user defined font values into private hash values.
796             #
797             sub _convert_font_args {
798              
799 4894     4894   7274 my $self = shift;
800 4894         8146 my $args = shift;
801              
802 4894 100       10999 return unless $args;
803              
804             my $font = {
805             _name => $args->{name},
806             _color => $args->{color},
807             _size => $args->{size},
808             _bold => $args->{bold},
809             _italic => $args->{italic},
810             _underline => $args->{underline},
811             _pitch_family => $args->{pitch_family},
812             _charset => $args->{charset},
813             _baseline => $args->{baseline} || 0,
814             _rotation => $args->{rotation},
815 52   100     485 };
816              
817             # Convert font size units.
818 52 100       179 $font->{_size} *= 100 if $font->{_size};
819              
820             # Convert rotation into 60,000ths of a degree.
821 52 100       142 if ( $font->{_rotation} ) {
822 21         60 $font->{_rotation} = 60_000 * int( $font->{_rotation} );
823             }
824              
825 52         135 return $font;
826             }
827              
828              
829             ###############################################################################
830             #
831             # _aref_to_formula()
832             #
833             # Convert and aref of row col values to a range formula.
834             #
835             sub _aref_to_formula {
836              
837 1886     1886   3649 my $self = shift;
838 1886         3599 my $data = shift;
839              
840             # If it isn't an array ref it is probably a formula already.
841 1886 100       5372 return $data if !ref $data;
842              
843 33         93 my $formula = xl_range_formula( @$data );
844              
845 33         60 return $formula;
846             }
847              
848              
849             ###############################################################################
850             #
851             # _process_names()
852             #
853             # Switch name and name_formula parameters if required.
854             #
855             sub _process_names {
856              
857 3384     3384   5670 my $self = shift;
858 3384         6410 my $name = shift;
859 3384         5640 my $name_formula = shift;
860              
861 3384 100       7651 if ( defined $name ) {
862              
863 81 100       527 if ( ref $name eq 'ARRAY' ) {
    100          
864 1         4 my $cell = xl_rowcol_to_cell( $name->[1], $name->[2], 1, 1 );
865 1         3 $name_formula = quote_sheetname( $name->[0] ) . '!' . $cell;
866 1         2 $name = '';
867             }
868             elsif ( $name =~ m/^=[^!]+!\$/ ) {
869              
870             # Name looks like a formula, use it to set name_formula.
871 19         50 $name_formula = $name;
872 19         40 $name = '';
873             }
874             }
875              
876 3384         10983 return ( $name, $name_formula );
877             }
878              
879              
880             ###############################################################################
881             #
882             # _get_data_type()
883             #
884             # Find the overall type of the data associated with a series.
885             #
886             # TODO. Need to handle date type.
887             #
888             sub _get_data_type {
889              
890 255     255   567 my $self = shift;
891 255         504 my $data = shift;
892              
893             # Check for no data in the series.
894 255 50       817 return 'none' if !defined $data;
895 255 50       935 return 'none' if @$data == 0;
896              
897 255 100       961 if (ref $data->[0] eq 'ARRAY') {
898 3         8 return 'multi_str'
899             }
900              
901             # If the token isn't a number assume it is a string.
902 252         713 for my $token ( @$data ) {
903 1220 100       2501 next if !defined $token;
904 1219 100       5622 return 'str'
905             if $token !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/;
906             }
907              
908             # The series data was all numeric.
909 243         801 return 'num';
910             }
911              
912              
913             ###############################################################################
914             #
915             # _get_data_id()
916             #
917             # Assign an id to a each unique series formula or title/axis formula. Repeated
918             # formulas such as for categories get the same id. If the series or title
919             # has user specified data associated with it then that is also stored. This
920             # data is used to populate cached Excel data when creating a chart.
921             # If there is no user defined data then it will be populated by the parent
922             # workbook in Workbook::_add_chart_data()
923             #
924             sub _get_data_id {
925              
926 5267     5267   8182 my $self = shift;
927 5267         7556 my $formula = shift;
928 5267         8547 my $data = shift;
929 5267         7106 my $id;
930              
931             # Ignore series without a range formula.
932 5267 100       11800 return unless $formula;
933              
934             # Strip the leading '=' from the formula.
935 1225         5821 $formula =~ s/^=//;
936              
937             # Store the data id in a hash keyed by the formula and store the data
938             # in a separate array with the same id.
939 1225 100       4785 if ( !exists $self->{_formula_ids}->{$formula} ) {
940              
941             # Haven't seen this formula before.
942 1106         1863 $id = @{ $self->{_formula_data} };
  1106         2446  
943              
944 1106         1981 push @{ $self->{_formula_data} }, $data;
  1106         2667  
945 1106         2966 $self->{_formula_ids}->{$formula} = $id;
946             }
947             else {
948              
949             # Formula already seen. Return existing id.
950 119         394 $id = $self->{_formula_ids}->{$formula};
951              
952             # Store user defined data if it isn't already there.
953 119 100       540 if ( !defined $self->{_formula_data}->[$id] ) {
954 114         360 $self->{_formula_data}->[$id] = $data;
955             }
956             }
957              
958 1225         2617 return $id;
959             }
960              
961              
962             ###############################################################################
963             #
964             # _get_color()
965             #
966             # Convert the user specified colour index or string to a rgb colour.
967             #
968             sub _get_color {
969              
970 238     238   552 my $self = shift;
971 238         449 my $color = shift;
972              
973             # Convert a HTML style #RRGGBB color.
974 238 100 66     1504 if ( defined $color and $color =~ /^#[0-9a-fA-F]{6}$/ ) {
975 177         569 $color =~ s/^#//;
976 177         530 return uc $color;
977             }
978              
979 61         339 my $index = &Excel::Writer::XLSX::Format::_get_color( $color );
980              
981             # Set undefined colors to black.
982 61 50       212 if ( !$index ) {
983 0         0 $index = 0x08;
984 0         0 warn "Unknown color '$color' used in chart formatting. "
985             . "Converting to black.\n";
986             }
987              
988 61         338 return $self->_get_palette_color( $index );
989             }
990              
991              
992             ###############################################################################
993             #
994             # _get_palette_color()
995             #
996             # Convert from an Excel internal colour index to a XML style #RRGGBB index
997             # based on the default or user defined values in the Workbook palette.
998             # Note: This version doesn't add an alpha channel.
999             #
1000             sub _get_palette_color {
1001              
1002 61     61   137 my $self = shift;
1003 61         110 my $index = shift;
1004 61         151 my $palette = $self->{_palette};
1005              
1006             # Adjust the colour index.
1007 61         164 $index -= 8;
1008              
1009             # Palette is passed in from the Workbook class.
1010 61         109 my @rgb = @{ $palette->[$index] };
  61         216  
1011              
1012 61         483 return sprintf "%02X%02X%02X", @rgb[0, 1, 2];
1013             }
1014              
1015              
1016             ###############################################################################
1017             #
1018             # _get_swe_line_pattern()
1019             #
1020             # Get the Spreadsheet::WriteExcel line pattern for backward compatibility.
1021             #
1022             sub _get_swe_line_pattern {
1023              
1024 2     2   4 my $self = shift;
1025 2         6 my $value = lc shift;
1026 2         4 my $default = 'solid';
1027 2         4 my $pattern;
1028              
1029 2         24 my %patterns = (
1030             0 => 'solid',
1031             1 => 'dash',
1032             2 => 'dot',
1033             3 => 'dash_dot',
1034             4 => 'long_dash_dot_dot',
1035             5 => 'none',
1036             6 => 'solid',
1037             7 => 'solid',
1038             8 => 'solid',
1039             'solid' => 'solid',
1040             'dash' => 'dash',
1041             'dot' => 'dot',
1042             'dash-dot' => 'dash_dot',
1043             'dash-dot-dot' => 'long_dash_dot_dot',
1044             'none' => 'none',
1045             'dark-gray' => 'solid',
1046             'medium-gray' => 'solid',
1047             'light-gray' => 'solid',
1048             );
1049              
1050 2 50       6 if ( exists $patterns{$value} ) {
1051 2         5 $pattern = $patterns{$value};
1052             }
1053             else {
1054 0         0 $pattern = $default;
1055             }
1056              
1057 2         7 return $pattern;
1058             }
1059              
1060              
1061             ###############################################################################
1062             #
1063             # _get_swe_line_weight()
1064             #
1065             # Get the Spreadsheet::WriteExcel line weight for backward compatibility.
1066             #
1067             sub _get_swe_line_weight {
1068              
1069 1     1   7 my $self = shift;
1070 1         3 my $value = lc shift;
1071 1         2 my $default = 1;
1072 1         2 my $weight;
1073              
1074 1         9 my %weights = (
1075             1 => 0.25,
1076             2 => 1,
1077             3 => 2,
1078             4 => 3,
1079             'hairline' => 0.25,
1080             'narrow' => 1,
1081             'medium' => 2,
1082             'wide' => 3,
1083             );
1084              
1085 1 50       3 if ( exists $weights{$value} ) {
1086 1         4 $weight = $weights{$value};
1087             }
1088             else {
1089 0         0 $weight = $default;
1090             }
1091              
1092 1         4 return $weight;
1093             }
1094              
1095              
1096             ###############################################################################
1097             #
1098             # _get_line_properties()
1099             #
1100             # Convert user defined line properties to the structure required internally.
1101             #
1102             sub _get_line_properties {
1103              
1104 4291     4291   6808 my $self = shift;
1105 4291         7073 my $line = shift;
1106              
1107 4291 100       13171 return { _defined => 0 } unless $line;
1108              
1109             # Copy the user supplied properties.
1110 49         226 $line = { %$line };
1111              
1112 49         526 my %dash_types = (
1113             solid => 'solid',
1114             round_dot => 'sysDot',
1115             square_dot => 'sysDash',
1116             dash => 'dash',
1117             dash_dot => 'dashDot',
1118             long_dash => 'lgDash',
1119             long_dash_dot => 'lgDashDot',
1120             long_dash_dot_dot => 'lgDashDotDot',
1121             dot => 'dot',
1122             system_dash_dot => 'sysDashDot',
1123             system_dash_dot_dot => 'sysDashDotDot',
1124             );
1125              
1126             # Check the dash type.
1127 49         122 my $dash_type = $line->{dash_type};
1128              
1129 49 100       183 if ( defined $dash_type ) {
1130 25 50       104 if ( exists $dash_types{$dash_type} ) {
1131 25         67 $line->{dash_type} = $dash_types{$dash_type};
1132             }
1133             else {
1134 0         0 warn "Unknown dash type '$dash_type'\n";
1135 0         0 return;
1136             }
1137             }
1138              
1139 49         130 $line->{_defined} = 1;
1140              
1141 49         230 return $line;
1142             }
1143              
1144              
1145             ###############################################################################
1146             #
1147             # _get_fill_properties()
1148             #
1149             # Convert user defined fill properties to the structure required internally.
1150             #
1151             sub _get_fill_properties {
1152              
1153 3459     3459   5906 my $self = shift;
1154 3459         5666 my $fill = shift;
1155              
1156 3459 100       10208 return { _defined => 0 } unless $fill;
1157              
1158 46         129 $fill->{_defined} = 1;
1159              
1160 46         117 return $fill;
1161             }
1162              
1163              
1164             ###############################################################################
1165             #
1166             # _get_pattern_properties()
1167             #
1168             # Convert user defined pattern properties to the structure required internally.
1169             #
1170             sub _get_pattern_properties {
1171              
1172 1036     1036   2175 my $self = shift;
1173 1036         2024 my $args = shift;
1174 1036         2078 my $pattern = {};
1175              
1176 1036 100       3489 return unless $args;
1177              
1178             # Check the pattern type is present.
1179 58 50       137 if ( !$args->{pattern} ) {
1180 0         0 carp "Pattern must include 'pattern'";
1181 0         0 return;
1182             }
1183              
1184             # Check the foreground color is present.
1185 58 50       147 if ( !$args->{fg_color} ) {
1186 0         0 carp "Pattern must include 'fg_color'";
1187 0         0 return;
1188             }
1189              
1190 58         1200 my %types = (
1191             'percent_5' => 'pct5',
1192             'percent_10' => 'pct10',
1193             'percent_20' => 'pct20',
1194             'percent_25' => 'pct25',
1195             'percent_30' => 'pct30',
1196             'percent_40' => 'pct40',
1197              
1198             'percent_50' => 'pct50',
1199             'percent_60' => 'pct60',
1200             'percent_70' => 'pct70',
1201             'percent_75' => 'pct75',
1202             'percent_80' => 'pct80',
1203             'percent_90' => 'pct90',
1204              
1205             'light_downward_diagonal' => 'ltDnDiag',
1206             'light_upward_diagonal' => 'ltUpDiag',
1207             'dark_downward_diagonal' => 'dkDnDiag',
1208             'dark_upward_diagonal' => 'dkUpDiag',
1209             'wide_downward_diagonal' => 'wdDnDiag',
1210             'wide_upward_diagonal' => 'wdUpDiag',
1211              
1212             'light_vertical' => 'ltVert',
1213             'light_horizontal' => 'ltHorz',
1214             'narrow_vertical' => 'narVert',
1215             'narrow_horizontal' => 'narHorz',
1216             'dark_vertical' => 'dkVert',
1217             'dark_horizontal' => 'dkHorz',
1218              
1219             'dashed_downward_diagonal' => 'dashDnDiag',
1220             'dashed_upward_diagonal' => 'dashUpDiag',
1221             'dashed_horizontal' => 'dashHorz',
1222             'dashed_vertical' => 'dashVert',
1223             'small_confetti' => 'smConfetti',
1224             'large_confetti' => 'lgConfetti',
1225              
1226             'zigzag' => 'zigZag',
1227             'wave' => 'wave',
1228             'diagonal_brick' => 'diagBrick',
1229             'horizontal_brick' => 'horzBrick',
1230             'weave' => 'weave',
1231             'plaid' => 'plaid',
1232              
1233             'divot' => 'divot',
1234             'dotted_grid' => 'dotGrid',
1235             'dotted_diamond' => 'dotDmnd',
1236             'shingle' => 'shingle',
1237             'trellis' => 'trellis',
1238             'sphere' => 'sphere',
1239              
1240             'small_grid' => 'smGrid',
1241             'large_grid' => 'lgGrid',
1242             'small_check' => 'smCheck',
1243             'large_check' => 'lgCheck',
1244             'outlined_diamond' => 'openDmnd',
1245             'solid_diamond' => 'solidDmnd',
1246             );
1247              
1248             # Check for valid types.
1249 58         117 my $pattern_type = $args->{pattern};
1250              
1251 58 50       134 if ( exists $types{$pattern_type} ) {
1252 58         180 $pattern->{pattern} = $types{$pattern_type};
1253             }
1254             else {
1255 0         0 carp "Unknown pattern type '$pattern_type'";
1256 0         0 return;
1257             }
1258              
1259             # Specify a default background color.
1260 58 100       127 if ( !$args->{bg_color} ) {
1261 49         99 $pattern->{bg_color} = '#FFFFFF';
1262             }
1263             else {
1264 9         26 $pattern->{bg_color} = $args->{bg_color};
1265             }
1266              
1267 58         118 $pattern->{fg_color} = $args->{fg_color};
1268              
1269 58         374 return $pattern;
1270             }
1271              
1272              
1273             ###############################################################################
1274             #
1275             # _get_gradient_properties()
1276             #
1277             # Convert user defined gradient to the structure required internally.
1278             #
1279             sub _get_gradient_properties {
1280              
1281 1036     1036   2091 my $self = shift;
1282 1036         2037 my $args = shift;
1283 1036         1940 my $gradient = {};
1284              
1285 1036         5056 my %types = (
1286             linear => 'linear',
1287             radial => 'circle',
1288             rectangular => 'rect',
1289             path => 'shape'
1290             );
1291              
1292 1036 100       4009 return unless $args;
1293              
1294             # Check the colors array exists and is valid.
1295 13 50 33     116 if ( !$args->{colors} || ref $args->{colors} ne 'ARRAY' ) {
1296 0         0 carp "Gradient must include colors array";
1297 0         0 return;
1298             }
1299              
1300             # Check the colors array has the required number of entries.
1301 13 50       26 if ( @{ $args->{colors} } < 2 ) {
  13         79  
1302 0         0 carp "Gradient colors array must at least 2 values";
1303 0         0 return;
1304             }
1305              
1306 13         52 $gradient->{_colors} = $args->{colors};
1307              
1308 13 100       51 if ( $args->{positions} ) {
1309              
1310             # Check the positions array has the right number of entries.
1311 2 50       4 if ( @{ $args->{positions} } != @{ $args->{colors} } ) {
  2         6  
  2         8  
1312 0         0 carp "Gradient positions not equal to number of colors";
1313 0         0 return;
1314             }
1315              
1316             # Check the positions are in the correct range.
1317 2         5 for my $pos ( @{ $args->{positions} } ) {
  2         7  
1318 5 50 33     21 if ( $pos < 0 || $pos > 100 ) {
1319 0         0 carp "Gradient position '", $pos,
1320             "' must be in range 0 <= pos <= 100";
1321 0         0 return;
1322             }
1323             }
1324              
1325 2         13 $gradient->{_positions} = $args->{positions};
1326             }
1327             else {
1328             # Use the default gradient positions.
1329 11 100       21 if ( @{ $args->{colors} } == 2 ) {
  11 100       48  
    50          
1330 1         4 $gradient->{_positions} = [ 0, 100 ];
1331             }
1332 10         38 elsif ( @{ $args->{colors} } == 3 ) {
1333 9         44 $gradient->{_positions} = [ 0, 50, 100 ];
1334             }
1335 1         3 elsif ( @{ $args->{colors} } == 4 ) {
1336 1         4 $gradient->{_positions} = [ 0, 33, 66, 100 ];
1337             }
1338             else {
1339 0         0 carp "Must specify gradient positions";
1340 0         0 return;
1341             }
1342             }
1343              
1344             # Set the gradient angle.
1345 13 100       55 if ( defined $args->{angle} ) {
1346 2         5 my $angle = $args->{angle};
1347              
1348 2 50 33     25 if ( $angle < 0 || $angle > 359.9 ) {
1349 0         0 carp "Gradient angle '", $angle,
1350             "' must be in range 0 <= pos < 360";
1351 0         0 return;
1352             }
1353 2         8 $gradient->{_angle} = $angle;
1354             }
1355             else {
1356 11         35 $gradient->{_angle} = 90;
1357             }
1358              
1359             # Set the gradient type.
1360 13 100       44 if ( defined $args->{type} ) {
1361 3         8 my $type = $args->{type};
1362              
1363 3 50       12 if ( !exists $types{$type} ) {
1364 0         0 carp "Unknown gradient type '", $type, "'";
1365 0         0 return;
1366             }
1367 3         10 $gradient->{_type} = $types{$type};
1368             }
1369             else {
1370 10         31 $gradient->{_type} = 'linear';
1371             }
1372              
1373 13         67 return $gradient;
1374             }
1375              
1376              
1377             ###############################################################################
1378             #
1379             # _get_marker_properties()
1380             #
1381             # Convert user defined marker properties to the structure required internally.
1382             #
1383             sub _get_marker_properties {
1384              
1385 943     943   1920 my $self = shift;
1386 943         1956 my $marker = shift;
1387              
1388 943 100 66     5172 return if !$marker && ref $marker ne 'HASH';
1389              
1390             # Copy the user supplied properties.
1391 11         45 $marker = { %$marker };
1392              
1393 11         158 my %types = (
1394             automatic => 'automatic',
1395             none => 'none',
1396             square => 'square',
1397             diamond => 'diamond',
1398             triangle => 'triangle',
1399             x => 'x',
1400             star => 'star',
1401             dot => 'dot',
1402             short_dash => 'dot',
1403             dash => 'dash',
1404             long_dash => 'dash',
1405             circle => 'circle',
1406             plus => 'plus',
1407             picture => 'picture',
1408             );
1409              
1410             # Check for valid types.
1411 11         30 my $marker_type = $marker->{type};
1412              
1413 11 50       35 if ( defined $marker_type ) {
1414 11 100       36 if ( $marker_type eq 'automatic' ) {
1415 6         14 $marker->{automatic} = 1;
1416             }
1417              
1418 11 50       34 if ( exists $types{$marker_type} ) {
1419 11         41 $marker->{type} = $types{$marker_type};
1420             }
1421             else {
1422 0         0 warn "Unknown marker type '$marker_type'\n";
1423 0         0 return;
1424             }
1425             }
1426              
1427             # Set the line properties for the marker..
1428 11         41 my $line = $self->_get_line_properties( $marker->{line} );
1429              
1430             # Allow 'border' as a synonym for 'line'.
1431 11 50       41 if ( $marker->{border} ) {
1432 0         0 $line = $self->_get_line_properties( $marker->{border} );
1433             }
1434              
1435             # Set the fill properties for the marker.
1436 11         44 my $fill = $self->_get_fill_properties( $marker->{fill} );
1437              
1438             # Set the pattern properties for the series.
1439 11         41 my $pattern = $self->_get_pattern_properties( $marker->{pattern} );
1440              
1441             # Set the gradient fill properties for the series.
1442 11         37 my $gradient = $self->_get_gradient_properties( $marker->{gradient} );
1443              
1444             # Pattern fill overrides solid fill.
1445 11 50       35 if ( $pattern ) {
1446 0         0 $fill = undef;
1447             }
1448              
1449             # Gradient fill overrides solid and pattern fills.
1450 11 50       42 if ( $gradient ) {
1451 0         0 $pattern = undef;
1452 0         0 $fill = undef;
1453             }
1454              
1455 11         35 $marker->{_line} = $line;
1456 11         40 $marker->{_fill} = $fill;
1457 11         28 $marker->{_pattern} = $pattern;
1458 11         27 $marker->{_gradient} = $gradient;
1459              
1460 11         49 return $marker;
1461             }
1462              
1463              
1464             ###############################################################################
1465             #
1466             # _get_trendline_properties()
1467             #
1468             # Convert user defined trendline properties to the structure required
1469             # internally.
1470             #
1471             sub _get_trendline_properties {
1472              
1473 943     943   1928 my $self = shift;
1474 943         1908 my $trendline = shift;
1475              
1476 943 100 66     4527 return if !$trendline && ref $trendline ne 'HASH';
1477              
1478             # Copy the user supplied properties.
1479 13         89 $trendline = { %$trendline };
1480              
1481 13         114 my %types = (
1482             exponential => 'exp',
1483             linear => 'linear',
1484             log => 'log',
1485             moving_average => 'movingAvg',
1486             polynomial => 'poly',
1487             power => 'power',
1488             );
1489              
1490             # Check the trendline type.
1491 13         37 my $trend_type = $trendline->{type};
1492              
1493 13 50       50 if ( exists $types{$trend_type} ) {
1494 13         40 $trendline->{type} = $types{$trend_type};
1495             }
1496             else {
1497 0         0 warn "Unknown trendline type '$trend_type'\n";
1498 0         0 return;
1499             }
1500              
1501             # Set the line properties for the trendline..
1502 13         49 my $line = $self->_get_line_properties( $trendline->{line} );
1503              
1504             # Allow 'border' as a synonym for 'line'.
1505 13 50       60 if ( $trendline->{border} ) {
1506 0         0 $line = $self->_get_line_properties( $trendline->{border} );
1507             }
1508              
1509             # Set the fill properties for the trendline.
1510 13         51 my $fill = $self->_get_fill_properties( $trendline->{fill} );
1511              
1512             # Set the pattern properties for the series.
1513 13         62 my $pattern = $self->_get_pattern_properties( $trendline->{pattern} );
1514              
1515             # Set the gradient fill properties for the series.
1516 13         57 my $gradient = $self->_get_gradient_properties( $trendline->{gradient} );
1517              
1518             # Pattern fill overrides solid fill.
1519 13 50       45 if ( $pattern ) {
1520 0         0 $fill = undef;
1521             }
1522              
1523             # Gradient fill overrides solid and pattern fills.
1524 13 50       38 if ( $gradient ) {
1525 0         0 $pattern = undef;
1526 0         0 $fill = undef;
1527             }
1528              
1529 13         31 $trendline->{_line} = $line;
1530 13         46 $trendline->{_fill} = $fill;
1531 13         38 $trendline->{_pattern} = $pattern;
1532 13         37 $trendline->{_gradient} = $gradient;
1533              
1534 13         54 return $trendline;
1535             }
1536              
1537              
1538             ###############################################################################
1539             #
1540             # _get_error_bars_properties()
1541             #
1542             # Convert user defined error bars properties to structure required internally.
1543             #
1544             sub _get_error_bars_properties {
1545              
1546 1886     1886   3163 my $self = shift;
1547 1886         3349 my $args = shift;
1548              
1549 1886 100 66     7283 return if !$args && ref $args ne 'HASH';
1550              
1551             # Copy the user supplied properties.
1552 14         60 $args = { %$args };
1553              
1554              
1555             # Default values.
1556 14         125 my $error_bars = {
1557             _type => 'fixedVal',
1558             _value => 1,
1559             _endcap => 1,
1560             _direction => 'both',
1561             _plus_values => [1],
1562             _minus_values => [1],
1563             _plus_data => [],
1564             _minus_data => [],
1565             };
1566              
1567 14         91 my %types = (
1568             fixed => 'fixedVal',
1569             percentage => 'percentage',
1570             standard_deviation => 'stdDev',
1571             standard_error => 'stdErr',
1572             custom => 'cust',
1573             );
1574              
1575             # Check the error bars type.
1576 14         46 my $error_type = $args->{type};
1577              
1578 14 50       43 if ( exists $types{$error_type} ) {
1579 14         55 $error_bars->{_type} = $types{$error_type};
1580             }
1581             else {
1582 0         0 warn "Unknown error bars type '$error_type'\n";
1583 0         0 return;
1584             }
1585              
1586             # Set the value for error types that require it.
1587 14 100       49 if ( defined $args->{value} ) {
1588 3         5 $error_bars->{_value} = $args->{value};
1589             }
1590              
1591             # Set the end-cap style.
1592 14 100       53 if ( defined $args->{end_style} ) {
1593 1         2 $error_bars->{_endcap} = $args->{end_style};
1594             }
1595              
1596             # Set the error bar direction.
1597 14 100       49 if ( defined $args->{direction} ) {
1598 2 100       7 if ( $args->{direction} eq 'minus' ) {
    50          
1599 1         2 $error_bars->{_direction} = 'minus';
1600             }
1601             elsif ( $args->{direction} eq 'plus' ) {
1602 1         2 $error_bars->{_direction} = 'plus';
1603             }
1604             else {
1605             # Default to 'both'.
1606             }
1607             }
1608              
1609             # Set any custom values.
1610 14 100       48 if ( defined $args->{plus_values} ) {
1611 3         10 $error_bars->{_plus_values} = $args->{plus_values};
1612             }
1613 14 100       47 if ( defined $args->{minus_values} ) {
1614 3         12 $error_bars->{_minus_values} = $args->{minus_values};
1615             }
1616 14 100       50 if ( defined $args->{plus_data} ) {
1617 1         3 $error_bars->{_plus_data} = $args->{plus_data};
1618             }
1619 14 100       50 if ( defined $args->{minus_data} ) {
1620 1         3 $error_bars->{_minus_data} = $args->{minus_data};
1621             }
1622              
1623             # Set the line properties for the error bars.
1624 14         59 $error_bars->{_line} = $self->_get_line_properties( $args->{line} );
1625              
1626 14         58 return $error_bars;
1627             }
1628              
1629              
1630             ###############################################################################
1631             #
1632             # _get_gridline_properties()
1633             #
1634             # Convert user defined gridline properties to the structure required internally.
1635             #
1636             sub _get_gridline_properties {
1637              
1638 790     790   1624 my $self = shift;
1639 790         1395 my $args = shift;
1640 790         1443 my $gridline;
1641              
1642             # Set the visible property for the gridline.
1643 790         2114 $gridline->{_visible} = $args->{visible};
1644              
1645             # Set the line properties for the gridline..
1646 790         2606 $gridline->{_line} = $self->_get_line_properties( $args->{line} );
1647              
1648 790         2214 return $gridline;
1649             }
1650              
1651              
1652             ###############################################################################
1653             #
1654             # _get_labels_properties()
1655             #
1656             # Convert user defined labels properties to the structure required internally.
1657             #
1658             sub _get_labels_properties {
1659              
1660 961     961   2312 my $self = shift;
1661 961         1903 my $labels = shift;
1662              
1663 961 100 66     4736 return if !$labels && ref $labels ne 'HASH';
1664              
1665             # Copy the user supplied properties.
1666 65         306 $labels = { %$labels };
1667              
1668             # Map user defined label positions to Excel positions.
1669 65 100       302 if ( my $position = $labels->{position} ) {
1670              
1671 46 50       179 if ( exists $self->{_label_positions}->{$position} ) {
1672 46 100       196 if ($position eq $self->{_label_position_default}) {
1673 11         47 $labels->{position} = undef;
1674             }
1675             else {
1676 35         93 $labels->{position} = $self->{_label_positions}->{$position};
1677             }
1678             }
1679             else {
1680 0         0 carp "Unsupported label position '$position' for this chart type";
1681             return undef
1682 0         0 }
1683             }
1684              
1685             # Map the user defined label separator to the Excel separator.
1686 65 100       217 if ( my $separator = $labels->{separator} ) {
1687              
1688 5         26 my %separators = (
1689             ',' => ', ',
1690             ';' => '; ',
1691             '.' => '. ',
1692             "\n" => "\n",
1693             ' ' => ' '
1694             );
1695              
1696 5 50       16 if ( exists $separators{$separator} ) {
1697 5         15 $labels->{separator} = $separators{$separator};
1698             }
1699             else {
1700 0         0 carp "Unsupported label separator";
1701             return undef
1702 0         0 }
1703             }
1704              
1705 65 100       238 if ($labels->{font}) {
1706 5         36 $labels->{font} = $self->_convert_font_args( $labels->{font} );
1707             }
1708              
1709 65         172 return $labels;
1710             }
1711              
1712              
1713             ###############################################################################
1714             #
1715             # _get_area_properties()
1716             #
1717             # Convert user defined area properties to the structure required internally.
1718             #
1719             sub _get_area_properties {
1720              
1721 20     20   45 my $self = shift;
1722 20         111 my %arg = @_;
1723 20         58 my $area = {};
1724              
1725              
1726             # Map deprecated Spreadsheet::WriteExcel fill colour.
1727 20 100       73 if ( $arg{color} ) {
1728 2         10 $arg{fill}->{color} = $arg{color};
1729             }
1730              
1731             # Map deprecated Spreadsheet::WriteExcel line_weight.
1732 20 100       84 if ( $arg{line_weight} ) {
1733 1         13 my $width = $self->_get_swe_line_weight( $arg{line_weight} );
1734 1         4 $arg{border}->{width} = $width;
1735             }
1736              
1737             # Map deprecated Spreadsheet::WriteExcel line_pattern.
1738 20 100       81 if ( $arg{line_pattern} ) {
1739 2         18 my $pattern = $self->_get_swe_line_pattern( $arg{line_pattern} );
1740              
1741 2 100       7 if ( $pattern eq 'none' ) {
1742 1         3 $arg{border}->{none} = 1;
1743             }
1744             else {
1745 1         3 $arg{border}->{dash_type} = $pattern;
1746             }
1747             }
1748              
1749             # Map deprecated Spreadsheet::WriteExcel line colour.
1750 20 100       96 if ( $arg{line_color} ) {
1751 1         3 $arg{border}->{color} = $arg{line_color};
1752             }
1753              
1754              
1755             # Handle Excel::Writer::XLSX style properties.
1756              
1757             # Set the line properties for the chartarea.
1758 20         86 my $line = $self->_get_line_properties( $arg{line} );
1759              
1760             # Allow 'border' as a synonym for 'line'.
1761 20 100       88 if ( $arg{border} ) {
1762 13         36 $line = $self->_get_line_properties( $arg{border} );
1763             }
1764              
1765             # Set the fill properties for the chartarea.
1766 20         75 my $fill = $self->_get_fill_properties( $arg{fill} );
1767              
1768             # Set the pattern properties for the series.
1769 20         94 my $pattern = $self->_get_pattern_properties( $arg{pattern} );
1770              
1771             # Set the gradient fill properties for the series.
1772 20         82 my $gradient = $self->_get_gradient_properties( $arg{gradient} );
1773              
1774             # Pattern fill overrides solid fill.
1775 20 100       103 if ( $pattern ) {
1776 2         9 $fill = undef;
1777             }
1778              
1779             # Gradient fill overrides solid and pattern fills.
1780 20 100       117 if ( $gradient ) {
1781 2         4 $pattern = undef;
1782 2         5 $fill = undef;
1783             }
1784              
1785             # Set the plotarea layout.
1786 20         106 my $layout = $self->_get_layout_properties( $arg{layout} );
1787              
1788 20         77 $area->{_line} = $line;
1789 20         43 $area->{_fill} = $fill;
1790 20         52 $area->{_pattern} = $pattern;
1791 20         41 $area->{_gradient} = $gradient;
1792 20         38 $area->{_layout} = $layout;
1793              
1794 20         88 return $area;
1795             }
1796              
1797              
1798             ###############################################################################
1799             #
1800             # _get_legend_properties()
1801             #
1802             # Convert user defined legend properties to the structure required internally.
1803             #
1804             sub _get_legend_properties {
1805              
1806 31     31   70 my $self = shift;
1807 31         112 my %arg = @_;
1808 31         72 my $legend = {};
1809              
1810 31   100     170 $legend->{_position} = $arg{position} || 'right';
1811 31         88 $legend->{_delete_series} = $arg{delete_series};
1812 31         167 $legend->{_font} = $self->_convert_font_args( $arg{font} );
1813              
1814             # Set the legend layout.
1815 31         144 $legend->{_layout} = $self->_get_layout_properties( $arg{layout} );
1816              
1817             # Turn off the legend.
1818 31 100       126 if ( $arg{none} ) {
1819 2         8 $legend->{_position} = 'none';
1820             }
1821              
1822             # Set the line properties for the legend.
1823 31         131 my $line = $self->_get_line_properties( $arg{line} );
1824              
1825             # Allow 'border' as a synonym for 'line'.
1826 31 100       137 if ( $arg{border} ) {
1827 1         3 $line = $self->_get_line_properties( $arg{border} );
1828             }
1829              
1830             # Set the fill properties for the legend.
1831 31         138 my $fill = $self->_get_fill_properties( $arg{fill} );
1832              
1833             # Set the pattern properties for the legend.
1834 31         150 my $pattern = $self->_get_pattern_properties( $arg{pattern} );
1835              
1836             # Set the gradient fill properties for the legend.
1837 31         142 my $gradient = $self->_get_gradient_properties( $arg{gradient} );
1838              
1839             # Pattern fill overrides solid fill.
1840 31 50       98 if ( $pattern ) {
1841 0         0 $fill = undef;
1842             }
1843              
1844             # Gradient fill overrides solid and pattern fills.
1845 31 50       130 if ( $gradient ) {
1846 0         0 $pattern = undef;
1847 0         0 $fill = undef;
1848             }
1849              
1850             # Set the legend layout.
1851 31         110 my $layout = $self->_get_layout_properties( $arg{layout} );
1852              
1853 31         79 $legend->{_line} = $line;
1854 31         67 $legend->{_fill} = $fill;
1855 31         73 $legend->{_pattern} = $pattern;
1856 31         91 $legend->{_gradient} = $gradient;
1857 31         63 $legend->{_layout} = $layout;
1858              
1859 31         127 return $legend;
1860             }
1861              
1862              
1863             ###############################################################################
1864             #
1865             # _get_layout_properties()
1866             #
1867             # Convert user defined layout properties to the format required internally.
1868             #
1869             sub _get_layout_properties {
1870              
1871 2520     2520   4182 my $self = shift;
1872 2520         4309 my $args = shift;
1873 2520         3872 my $is_text = shift;
1874 2520         4061 my $layout = {};
1875 2520         4431 my @properties;
1876             my %allowable;
1877              
1878 2520 100       7409 return if !$args;
1879              
1880 11 100       46 if ( $is_text ) {
1881 6         21 @properties = ( 'x', 'y' );
1882             }
1883             else {
1884 5         17 @properties = ( 'x', 'y', 'width', 'height' );
1885             }
1886              
1887             # Check for valid properties.
1888 11         43 @allowable{@properties} = undef;
1889              
1890 11         56 for my $key ( keys %$args ) {
1891              
1892 32 50       90 if ( !exists $allowable{$key} ) {
1893 0         0 warn "Property '$key' not allowed in layout options\n";
1894 0         0 return;
1895             }
1896             }
1897              
1898             # Set the layout properties.
1899 11         33 for my $property ( @properties ) {
1900              
1901 32 50       94 if ( !exists $args->{$property} ) {
1902 0         0 warn "Property '$property' must be specified in layout options\n";
1903 0         0 return;
1904             }
1905              
1906 32         59 my $value = $args->{$property};
1907              
1908 32 50       246 if ( $value !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ ) {
1909 0         0 warn "Property '$property' value '$value' must be numeric"
1910             . " in layout options\n";
1911 0         0 return;
1912             }
1913              
1914 32 50 33     160 if ( $value < 0 || $value > 1 ) {
1915 0         0 warn "Property '$property' value '$value' must be in range "
1916             . "0 < x <= 1 in layout options\n";
1917 0         0 return;
1918             }
1919              
1920             # Convert to the format used by Excel for easier testing
1921 32         162 $layout->{$property} = sprintf "%.17g", $value;
1922             }
1923              
1924 11         61 return $layout;
1925             }
1926              
1927              
1928             ###############################################################################
1929             #
1930             # _get_points_properties()
1931             #
1932             # Convert user defined points properties to structure required internally.
1933             #
1934             sub _get_points_properties {
1935              
1936 943     943   1834 my $self = shift;
1937 943         1875 my $user_points = shift;
1938 943         1760 my @points;
1939              
1940 943 100       2799 return unless $user_points;
1941              
1942 9         27 for my $user_point ( @$user_points ) {
1943              
1944 22         44 my $point;
1945              
1946 22 100       57 if ( defined $user_point ) {
1947              
1948             # Set the line properties for the point.
1949 18         81 my $line = $self->_get_line_properties( $user_point->{line} );
1950              
1951             # Allow 'border' as a synonym for 'line'.
1952 18 100       58 if ( $user_point->{border} ) {
1953 1         3 $line = $self->_get_line_properties( $user_point->{border} );
1954             }
1955              
1956             # Set the fill properties for the chartarea.
1957 18         68 my $fill = $self->_get_fill_properties( $user_point->{fill} );
1958              
1959              
1960             # Set the pattern properties for the series.
1961             my $pattern =
1962 18         58 $self->_get_pattern_properties( $user_point->{pattern} );
1963              
1964             # Set the gradient fill properties for the series.
1965             my $gradient =
1966 18         415 $self->_get_gradient_properties( $user_point->{gradient} );
1967              
1968             # Pattern fill overrides solid fill.
1969 18 50       50 if ( $pattern ) {
1970 0         0 $fill = undef;
1971             }
1972              
1973             # Gradient fill overrides solid and pattern fills.
1974 18 50       43 if ( $gradient ) {
1975 0         0 $pattern = undef;
1976 0         0 $fill = undef;
1977             }
1978             # Gradient fill overrides solid fill.
1979 18 50       69 if ( $gradient ) {
1980 0         0 $fill = undef;
1981             }
1982              
1983 18         47 $point->{_line} = $line;
1984 18         33 $point->{_fill} = $fill;
1985 18         33 $point->{_pattern} = $pattern;
1986 18         34 $point->{_gradient} = $gradient;
1987             }
1988              
1989 22         56 push @points, $point;
1990             }
1991              
1992 9         32 return \@points;
1993             }
1994              
1995              
1996             ###############################################################################
1997             #
1998             # _get_display_units()
1999             #
2000             # Convert user defined display units to internal units.
2001             #
2002             sub _get_display_units {
2003              
2004 2417     2417   3932 my $self = shift;
2005 2417         4328 my $display_units = shift;
2006              
2007 2417 100       6584 return if !$display_units;
2008              
2009 12         134 my %types = (
2010             'hundreds' => 'hundreds',
2011             'thousands' => 'thousands',
2012             'ten_thousands' => 'tenThousands',
2013             'hundred_thousands' => 'hundredThousands',
2014             'millions' => 'millions',
2015             'ten_millions' => 'tenMillions',
2016             'hundred_millions' => 'hundredMillions',
2017             'billions' => 'billions',
2018             'trillions' => 'trillions',
2019             );
2020              
2021 12 50       41 if ( exists $types{$display_units} ) {
2022 12         55 $display_units = $types{$display_units};
2023             }
2024             else {
2025 0         0 warn "Unknown display_units type '$display_units'\n";
2026 0         0 return;
2027             }
2028              
2029 12         58 return $display_units;
2030             }
2031              
2032              
2033              
2034             ###############################################################################
2035             #
2036             # _get_tick_type()
2037             #
2038             # Convert user tick types to internal units.
2039             #
2040             sub _get_tick_type {
2041              
2042 4834     4834   7023 my $self = shift;
2043 4834         7693 my $tick_type = shift;
2044              
2045 4834 100       14879 return if !$tick_type;
2046              
2047 5         22 my %types = (
2048             'outside' => 'out',
2049             'inside' => 'in',
2050             'none' => 'none',
2051             'cross' => 'cross',
2052             );
2053              
2054 5 50       14 if ( exists $types{$tick_type} ) {
2055 5         10 $tick_type = $types{$tick_type};
2056             }
2057             else {
2058 0         0 warn "Unknown tick_type type '$tick_type'\n";
2059 0         0 return;
2060             }
2061              
2062 5         16 return $tick_type;
2063             }
2064              
2065              
2066             ###############################################################################
2067             #
2068             # _get_primary_axes_series()
2069             #
2070             # Returns series which use the primary axes.
2071             #
2072             sub _get_primary_axes_series {
2073              
2074 346     346   917 my $self = shift;
2075 346         846 my @primary_axes_series;
2076              
2077 346         864 for my $series ( @{ $self->{_series} } ) {
  346         1332  
2078 878 100       3357 push @primary_axes_series, $series unless $series->{_y2_axis};
2079             }
2080              
2081 346         1504 return @primary_axes_series;
2082             }
2083              
2084              
2085             ###############################################################################
2086             #
2087             # _get_secondary_axes_series()
2088             #
2089             # Returns series which use the secondary axes.
2090             #
2091             sub _get_secondary_axes_series {
2092              
2093 346     346   1068 my $self = shift;
2094 346         833 my @secondary_axes_series;
2095              
2096 346         846 for my $series ( @{ $self->{_series} } ) {
  346         1346  
2097 878 100       2977 push @secondary_axes_series, $series if $series->{_y2_axis};
2098             }
2099              
2100 346         1184 return @secondary_axes_series;
2101             }
2102              
2103              
2104             ###############################################################################
2105             #
2106             # _add_axis_ids()
2107             #
2108             # Add unique ids for primary or secondary axes
2109             #
2110             sub _add_axis_ids {
2111              
2112 354     354   929 my $self = shift;
2113 354         1073 my %args = @_;
2114 354         1234 my $chart_id = 5001 + $self->{_id};
2115 354         916 my $axis_count = 1 + @{ $self->{_axis2_ids} } + @{ $self->{_axis_ids} };
  354         1138  
  354         1012  
2116              
2117 354         2491 my $id1 = sprintf '%04d%04d', $chart_id, $axis_count;
2118 354         1455 my $id2 = sprintf '%04d%04d', $chart_id, $axis_count + 1;
2119              
2120 354 100       1707 push @{ $self->{_axis_ids} }, $id1, $id2 if $args{primary_axes};
  342         1595  
2121 354 100       1962 push @{ $self->{_axis2_ids} }, $id1, $id2 if !$args{primary_axes};
  12         52  
2122             }
2123              
2124              
2125             ##############################################################################
2126             #
2127             # _get_font_style_attributes.
2128             #
2129             # Get the font style attributes from a font hashref.
2130             #
2131             sub _get_font_style_attributes {
2132              
2133 204     204   377 my $self = shift;
2134 204         341 my $font = shift;
2135              
2136 204 100       643 return () unless $font;
2137              
2138 69         110 my @attributes;
2139 69 100       211 push @attributes, ( 'sz' => $font->{_size} ) if $font->{_size};
2140 69 100       198 push @attributes, ( 'b' => $font->{_bold} ) if defined $font->{_bold};
2141 69 100       208 push @attributes, ( 'i' => $font->{_italic} ) if defined $font->{_italic};
2142 69 100       194 push @attributes, ( 'u' => 'sng' ) if defined $font->{_underline};
2143              
2144             # Turn off baseline when testing fonts that don't have it.
2145 69 100       211 if ($font->{_baseline} != -1) {
2146 32         87 push @attributes, ( 'baseline' => $font->{_baseline} );
2147             }
2148              
2149 69         203 return @attributes;
2150             }
2151              
2152              
2153             ##############################################################################
2154             #
2155             # _get_font_latin_attributes.
2156             #
2157             # Get the font latin attributes from a font hashref.
2158             #
2159             sub _get_font_latin_attributes {
2160              
2161 204     204   374 my $self = shift;
2162 204         348 my $font = shift;
2163              
2164 204 100       554 return () unless $font;
2165              
2166 69         115 my @attributes;
2167 69 100       195 push @attributes, ( 'typeface' => $font->{_name} ) if $font->{_name};
2168              
2169             push @attributes, ( 'pitchFamily' => $font->{_pitch_family} )
2170 69 100       186 if defined $font->{_pitch_family};
2171              
2172             push @attributes, ( 'charset' => $font->{_charset} )
2173 69 100       190 if defined $font->{_charset};
2174              
2175 69         172 return @attributes;
2176             }
2177              
2178              
2179             ###############################################################################
2180             #
2181             # Config data.
2182             #
2183             ###############################################################################
2184              
2185             ###############################################################################
2186             #
2187             # _set_default_properties()
2188             #
2189             # Setup the default properties for a chart.
2190             #
2191             sub _set_default_properties {
2192              
2193 491     491   1184 my $self = shift;
2194              
2195             # Set the default axis properties.
2196             $self->{_x_axis}->{_defaults} = {
2197 491         5044 num_format => 'General',
2198             major_gridlines => { visible => 0 }
2199             };
2200              
2201             $self->{_y_axis}->{_defaults} = {
2202 491         2635 num_format => 'General',
2203             major_gridlines => { visible => 1 }
2204             };
2205              
2206             $self->{_x2_axis}->{_defaults} = {
2207 491         2369 num_format => 'General',
2208             label_position => 'none',
2209             crossing => 'max',
2210             visible => 0
2211             };
2212              
2213             $self->{_y2_axis}->{_defaults} = {
2214 491         2515 num_format => 'General',
2215             major_gridlines => { visible => 0 },
2216             position => 'right',
2217             visible => 1
2218             };
2219              
2220 491         2109 $self->set_x_axis();
2221 491         1895 $self->set_y_axis();
2222              
2223 491         1996 $self->set_x2_axis();
2224 491         1892 $self->set_y2_axis();
2225             }
2226              
2227              
2228             ###############################################################################
2229             #
2230             # _set_embedded_config_data()
2231             #
2232             # Setup the default configuration data for an embedded chart.
2233             #
2234             sub _set_embedded_config_data {
2235              
2236 385     385   966 my $self = shift;
2237              
2238 385         1081 $self->{_embedded} = 1;
2239             }
2240              
2241              
2242             ###############################################################################
2243             #
2244             # XML writing methods.
2245             #
2246             ###############################################################################
2247              
2248              
2249             ##############################################################################
2250             #
2251             # _write_chart_space()
2252             #
2253             # Write the element.
2254             #
2255             sub _write_chart_space {
2256              
2257 395     395   984 my $self = shift;
2258 395         941 my $schema = 'http://schemas.openxmlformats.org/';
2259 395         1419 my $xmlns_c = $schema . 'drawingml/2006/chart';
2260 395         1088 my $xmlns_a = $schema . 'drawingml/2006/main';
2261 395         1041 my $xmlns_r = $schema . 'officeDocument/2006/relationships';
2262              
2263 395         1651 my @attributes = (
2264             'xmlns:c' => $xmlns_c,
2265             'xmlns:a' => $xmlns_a,
2266             'xmlns:r' => $xmlns_r,
2267             );
2268              
2269 395         2624 $self->xml_start_tag( 'c:chartSpace', @attributes );
2270             }
2271              
2272              
2273             ##############################################################################
2274             #
2275             # _write_lang()
2276             #
2277             # Write the element.
2278             #
2279             sub _write_lang {
2280              
2281 395     395   998 my $self = shift;
2282 395         863 my $val = 'en-US';
2283              
2284 395         1186 my @attributes = ( 'val' => $val );
2285              
2286 395         2371 $self->xml_empty_tag( 'c:lang', @attributes );
2287             }
2288              
2289              
2290             ##############################################################################
2291             #
2292             # _write_style()
2293             #
2294             # Write the element.
2295             #
2296             sub _write_style {
2297              
2298 398     398   1059 my $self = shift;
2299 398         1056 my $style_id = $self->{_style_id};
2300              
2301             # Don't write an element for the default style, 2.
2302 398 100       1719 return if $style_id == 2;
2303              
2304 3         8 my @attributes = ( 'val' => $style_id );
2305              
2306 3         35 $self->xml_empty_tag( 'c:style', @attributes );
2307             }
2308              
2309              
2310             ##############################################################################
2311             #
2312             # _write_chart()
2313             #
2314             # Write the element.
2315             #
2316             sub _write_chart {
2317              
2318 394     394   964 my $self = shift;
2319              
2320 394         1714 $self->xml_start_tag( 'c:chart' );
2321              
2322             # Write the chart title elements.
2323              
2324 394 100       1779 if ( $self->{_title_none} ) {
2325              
2326             # Turn off the title.
2327 1         8 $self->_write_auto_title_deleted();
2328             }
2329             else {
2330 393         909 my $title;
2331 393 100       2549 if ( $title = $self->{_title_formula} ) {
    100          
2332             $self->_write_title_formula(
2333              
2334             $title,
2335             $self->{_title_data_id},
2336             undef,
2337             $self->{_title_font},
2338             $self->{_title_layout},
2339             $self->{_title_overlay}
2340 5         38 );
2341             }
2342             elsif ( $title = $self->{_title_name} ) {
2343             $self->_write_title_rich(
2344              
2345             $title,
2346             undef,
2347             $self->{_title_font},
2348             $self->{_title_layout},
2349             $self->{_title_overlay}
2350 15         121 );
2351             }
2352             }
2353              
2354             # Write the c:plotArea element.
2355 394         2927 $self->_write_plot_area();
2356              
2357             # Write the c:legend element.
2358 394         3084 $self->_write_legend();
2359              
2360             # Write the c:plotVisOnly element.
2361 394         3526 $self->_write_plot_vis_only();
2362              
2363             # Write the c:dispBlanksAs element.
2364 394         3339 $self->_write_disp_blanks_as();
2365              
2366 394         1828 $self->xml_end_tag( 'c:chart' );
2367             }
2368              
2369              
2370             ##############################################################################
2371             #
2372             # _write_disp_blanks_as()
2373             #
2374             # Write the element.
2375             #
2376             sub _write_disp_blanks_as {
2377              
2378 394     394   1041 my $self = shift;
2379 394         1112 my $val = $self->{_show_blanks};
2380              
2381             # Ignore the default value.
2382 394 100       1797 return if $val eq 'gap';
2383              
2384 4         14 my @attributes = ( 'val' => $val );
2385              
2386 4         14 $self->xml_empty_tag( 'c:dispBlanksAs', @attributes );
2387             }
2388              
2389              
2390             ##############################################################################
2391             #
2392             # _write_plot_area()
2393             #
2394             # Write the element.
2395             #
2396             sub _write_plot_area {
2397              
2398 307     307   843 my $self = shift;
2399 307         885 my $second_chart = $self->{_combined};
2400              
2401 307         1549 $self->xml_start_tag( 'c:plotArea' );
2402              
2403             # Write the c:layout element.
2404 307         2531 $self->_write_layout( $self->{_plotarea}->{_layout}, 'plot' );
2405              
2406             # Write the subclass chart type elements for primary and secondary axes.
2407 307         1940 $self->_write_chart_type( primary_axes => 1 );
2408 307         1491 $self->_write_chart_type( primary_axes => 0 );
2409              
2410              
2411             # Configure a combined chart if present.
2412 307 100       1206 if ( $second_chart ) {
2413              
2414             # Secondary axis has unique id otherwise use same as primary.
2415 8 100       107 if ( $second_chart->{_is_secondary} ) {
2416 4         17 $second_chart->{_id} = 1000 + $self->{_id};
2417             }
2418             else {
2419 4         14 $second_chart->{_id} = $self->{_id};
2420             }
2421              
2422             # Shart the same filehandle for writing.
2423 8         19 $second_chart->{_fh} = $self->{_fh};
2424              
2425             # Share series index with primary chart.
2426 8         17 $second_chart->{_series_index} = $self->{_series_index};
2427              
2428             # Write the subclass chart type elements for combined chart.
2429 8         52 $second_chart->_write_chart_type( primary_axes => 1 );
2430 8         34 $second_chart->_write_chart_type( primary_axes => 0 );
2431             }
2432              
2433             # Write the category and value elements for the primary axes.
2434             my @args = (
2435             x_axis => $self->{_x_axis},
2436             y_axis => $self->{_y_axis},
2437             axis_ids => $self->{_axis_ids}
2438 307         1775 );
2439              
2440 307 100       1427 if ( $self->{_date_category} ) {
2441 16         120 $self->_write_date_axis( @args );
2442             }
2443             else {
2444 291         2409 $self->_write_cat_axis( @args );
2445             }
2446              
2447 307         2305 $self->_write_val_axis( @args );
2448              
2449             # Write the category and value elements for the secondary axes.
2450             @args = (
2451             x_axis => $self->{_x2_axis},
2452             y_axis => $self->{_y2_axis},
2453             axis_ids => $self->{_axis2_ids}
2454 307         1658 );
2455              
2456 307         1492 $self->_write_val_axis( @args );
2457              
2458             # Write the secondary axis for the secondary chart.
2459 307 100 100     1339 if ( $second_chart && $second_chart->{_is_secondary} ) {
2460              
2461             @args = (
2462             x_axis => $second_chart->{_x2_axis},
2463             y_axis => $second_chart->{_y2_axis},
2464             axis_ids => $second_chart->{_axis2_ids}
2465 4         21 );
2466              
2467 4         23 $second_chart->_write_val_axis( @args );
2468             }
2469              
2470              
2471 307 100       1392 if ( $self->{_date_category} ) {
2472 16         51 $self->_write_date_axis( @args );
2473             }
2474             else {
2475 291         1325 $self->_write_cat_axis( @args );
2476             }
2477              
2478             # Write the c:dTable element.
2479 307         2518 $self->_write_d_table();
2480              
2481             # Write the c:spPr element for the plotarea formatting.
2482 307         1585 $self->_write_sp_pr( $self->{_plotarea} );
2483              
2484 307         1756 $self->xml_end_tag( 'c:plotArea' );
2485             }
2486              
2487              
2488             ##############################################################################
2489             #
2490             # _write_layout()
2491             #
2492             # Write the element.
2493             #
2494             sub _write_layout {
2495              
2496 868     868   1900 my $self = shift;
2497 868         2118 my $layout = shift;
2498 868         1643 my $type = shift;
2499              
2500 868 100       2689 if ( !$layout ) {
2501             # Automatic layout.
2502 859         2758 $self->xml_empty_tag( 'c:layout' );
2503             }
2504             else {
2505             # User defined manual layout.
2506 9         45 $self->xml_start_tag( 'c:layout' );
2507 9         67 $self->_write_manual_layout( $layout, $type );
2508 9         118 $self->xml_end_tag( 'c:layout' );
2509             }
2510             }
2511              
2512             ##############################################################################
2513             #
2514             # _write_manual_layout()
2515             #
2516             # Write the element.
2517             #
2518             sub _write_manual_layout {
2519              
2520 9     9   32 my $self = shift;
2521 9         25 my $layout = shift;
2522 9         28 my $type = shift;
2523              
2524 9         65 $self->xml_start_tag( 'c:manualLayout' );
2525              
2526             # Plotarea has a layoutTarget element.
2527 9 100       45 if ( $type eq 'plot' ) {
2528 1         4 $self->xml_empty_tag( 'c:layoutTarget', ( 'val' => 'inner' ) );
2529             }
2530              
2531             # Set the x, y positions.
2532 9         39 $self->xml_empty_tag( 'c:xMode', ( 'val' => 'edge' ) );
2533 9         52 $self->xml_empty_tag( 'c:yMode', ( 'val' => 'edge' ) );
2534 9         53 $self->xml_empty_tag( 'c:x', ( 'val' => $layout->{x} ) );
2535 9         43 $self->xml_empty_tag( 'c:y', ( 'val' => $layout->{y} ) );
2536              
2537             # For plotarea and legend set the width and height.
2538 9 100       35 if ( $type ne 'text' ) {
2539 3         15 $self->xml_empty_tag( 'c:w', ( 'val' => $layout->{width} ) );
2540 3         13 $self->xml_empty_tag( 'c:h', ( 'val' => $layout->{height} ) );
2541             }
2542              
2543 9         37 $self->xml_end_tag( 'c:manualLayout' );
2544             }
2545              
2546             ##############################################################################
2547             #
2548             # _write_chart_type()
2549             #
2550             # Write the chart type element. This method should be overridden by the
2551             # subclasses.
2552             #
2553             sub _write_chart_type {
2554              
2555 0     0   0 my $self = shift;
2556             }
2557              
2558              
2559             ##############################################################################
2560             #
2561             # _write_grouping()
2562             #
2563             # Write the element.
2564             #
2565             sub _write_grouping {
2566              
2567 302     302   869 my $self = shift;
2568 302         767 my $val = shift;
2569              
2570 302         1129 my @attributes = ( 'val' => $val );
2571              
2572 302         1212 $self->xml_empty_tag( 'c:grouping', @attributes );
2573             }
2574              
2575              
2576             ##############################################################################
2577             #
2578             # _write_series()
2579             #
2580             # Write the series elements.
2581             #
2582             sub _write_series {
2583              
2584 234     234   495 my $self = shift;
2585 234         426 my $series = shift;
2586              
2587 234         955 $self->_write_ser( $series );
2588             }
2589              
2590              
2591             ##############################################################################
2592             #
2593             # _write_ser()
2594             #
2595             # Write the element.
2596             #
2597             sub _write_ser {
2598              
2599 876     876   1869 my $self = shift;
2600 876         1511 my $series = shift;
2601 876         1964 my $index = $self->{_series_index}++;
2602              
2603 876         2836 $self->xml_start_tag( 'c:ser' );
2604              
2605             # Write the c:idx element.
2606 876         4119 $self->_write_idx( $index );
2607              
2608             # Write the c:order element.
2609 876         3839 $self->_write_order( $index );
2610              
2611             # Write the series name.
2612 876         4001 $self->_write_series_name( $series );
2613              
2614             # Write the c:spPr element.
2615 876         3876 $self->_write_sp_pr( $series );
2616              
2617             # Write the c:marker element.
2618 876         3923 $self->_write_marker( $series->{_marker} );
2619              
2620             # Write the c:invertIfNegative element.
2621 876         3922 $self->_write_c_invert_if_negative( $series->{_invert_if_neg} );
2622              
2623             # Write the c:dPt element.
2624 876         3567 $self->_write_d_pt( $series->{_points} );
2625              
2626             # Write the c:dLbls element.
2627 876         3600 $self->_write_d_lbls( $series->{_labels} );
2628              
2629             # Write the c:trendline element.
2630 876         3639 $self->_write_trendline( $series->{_trendline} );
2631              
2632             # Write the c:errBars element.
2633 876         3884 $self->_write_error_bars( $series->{_error_bars} );
2634              
2635             # Write the c:cat element.
2636 876         3642 $self->_write_cat( $series );
2637              
2638             # Write the c:val element.
2639 876         3732 $self->_write_val( $series );
2640              
2641             # Write the c:smooth element.
2642 876 100       2915 if ( $self->{_smooth_allowed} ) {
2643 199         996 $self->_write_c_smooth( $series->{_smooth} );
2644             }
2645              
2646 876         2747 $self->xml_end_tag( 'c:ser' );
2647             }
2648              
2649              
2650             ##############################################################################
2651             #
2652             # _write_idx()
2653             #
2654             # Write the element.
2655             #
2656             sub _write_idx {
2657              
2658 966     966   1815 my $self = shift;
2659 966         1680 my $val = shift;
2660              
2661 966         2392 my @attributes = ( 'val' => $val );
2662              
2663 966         2946 $self->xml_empty_tag( 'c:idx', @attributes );
2664             }
2665              
2666              
2667             ##############################################################################
2668             #
2669             # _write_order()
2670             #
2671             # Write the element.
2672             #
2673             sub _write_order {
2674              
2675 939     939   1880 my $self = shift;
2676 939         1637 my $val = shift;
2677              
2678 939         2203 my @attributes = ( 'val' => $val );
2679              
2680 939         2732 $self->xml_empty_tag( 'c:order', @attributes );
2681             }
2682              
2683              
2684             ##############################################################################
2685             #
2686             # _write_series_name()
2687             #
2688             # Write the series name.
2689             #
2690             sub _write_series_name {
2691              
2692 938     938   1926 my $self = shift;
2693 938         1670 my $series = shift;
2694              
2695 938         1648 my $name;
2696 938 100       4463 if ( $name = $series->{_name_formula} ) {
    100          
2697 11         60 $self->_write_tx_formula( $name, $series->{_name_id} );
2698             }
2699             elsif ( $name = $series->{_name} ) {
2700 2         20 $self->_write_tx_value( $name );
2701             }
2702              
2703             }
2704              
2705              
2706             ##############################################################################
2707             #
2708             # _write_cat()
2709             #
2710             # Write the element.
2711             #
2712             sub _write_cat {
2713              
2714 876     876   1653 my $self = shift;
2715 876         1430 my $series = shift;
2716 876         1733 my $formula = $series->{_categories};
2717 876         1562 my $data_id = $series->{_cat_data_id};
2718 876         1412 my $data;
2719              
2720 876 100       2509 if ( defined $data_id ) {
2721 193         498 $data = $self->{_formula_data}->[$data_id];
2722             }
2723              
2724             # Ignore elements for charts without category values.
2725 876 100       2376 return unless $formula;
2726              
2727 193         769 $self->xml_start_tag( 'c:cat' );
2728              
2729             # Check the type of cached data.
2730 193         972 my $type = $self->_get_data_type( $data );
2731              
2732 193 100       1017 if ( $type eq 'str' ) {
    100          
2733              
2734 7         16 $self->{_cat_has_num_fmt} = 0;
2735              
2736             # Write the c:numRef element.
2737 7         26 $self->_write_str_ref( $formula, $data, $type );
2738             }
2739             elsif ( $type eq 'multi_str') {
2740              
2741 3         7 $self->{_cat_has_num_fmt} = 0;
2742              
2743             # Write the c:multiLvLStrRef element.
2744 3         9 $self->_write_multi_lvl_str_ref( $formula, $data );
2745             }
2746             else {
2747              
2748 183         451 $self->{_cat_has_num_fmt} = 1;
2749              
2750             # Write the c:numRef element.
2751 183         1038 $self->_write_num_ref( $formula, $data, $type );
2752             }
2753              
2754              
2755 193         613 $self->xml_end_tag( 'c:cat' );
2756             }
2757              
2758              
2759             ##############################################################################
2760             #
2761             # _write_val()
2762             #
2763             # Write the element.
2764             #
2765             sub _write_val {
2766              
2767 876     876   1623 my $self = shift;
2768 876         1450 my $series = shift;
2769 876         1804 my $formula = $series->{_values};
2770 876         1606 my $data_id = $series->{_val_data_id};
2771 876         1829 my $data = $self->{_formula_data}->[$data_id];
2772              
2773 876         2973 $self->xml_start_tag( 'c:val' );
2774              
2775             # Unlike Cat axes data should only be numeric.
2776              
2777             # Write the c:numRef element.
2778 876         3577 $self->_write_num_ref( $formula, $data, 'num' );
2779              
2780 876         2423 $self->xml_end_tag( 'c:val' );
2781             }
2782              
2783              
2784             ##############################################################################
2785             #
2786             # _write_num_ref()
2787             #
2788             # Write the element.
2789             #
2790             sub _write_num_ref {
2791              
2792 1183     1183   2133 my $self = shift;
2793 1183         2075 my $formula = shift;
2794 1183         2111 my $data = shift;
2795 1183         2087 my $type = shift;
2796              
2797 1183         3739 $self->xml_start_tag( 'c:numRef' );
2798              
2799             # Write the c:f element.
2800 1183         5142 $self->_write_series_formula( $formula );
2801              
2802 1183 50       3845 if ( $type eq 'num' ) {
    0          
2803              
2804             # Write the c:numCache element.
2805 1183         4778 $self->_write_num_cache( $data );
2806             }
2807             elsif ( $type eq 'str' ) {
2808              
2809             # Write the c:strCache element.
2810 0         0 $self->_write_str_cache( $data );
2811             }
2812              
2813 1183         3410 $self->xml_end_tag( 'c:numRef' );
2814             }
2815              
2816              
2817             ##############################################################################
2818             #
2819             # _write_str_ref()
2820             #
2821             # Write the element.
2822             #
2823             sub _write_str_ref {
2824              
2825 33     33   74 my $self = shift;
2826 33         77 my $formula = shift;
2827 33         68 my $data = shift;
2828 33         68 my $type = shift;
2829              
2830 33         126 $self->xml_start_tag( 'c:strRef' );
2831              
2832             # Write the c:f element.
2833 33         152 $self->_write_series_formula( $formula );
2834              
2835 33 50       186 if ( $type eq 'num' ) {
    50          
2836              
2837             # Write the c:numCache element.
2838 0         0 $self->_write_num_cache( $data );
2839             }
2840             elsif ( $type eq 'str' ) {
2841              
2842             # Write the c:strCache element.
2843 33         153 $self->_write_str_cache( $data );
2844             }
2845              
2846 33         126 $self->xml_end_tag( 'c:strRef' );
2847             }
2848              
2849              
2850             ##############################################################################
2851             #
2852             # _write_multi_lvl_str_ref()
2853             #
2854             # Write the element.
2855             #
2856             sub _write_multi_lvl_str_ref {
2857              
2858 3     3   5 my $self = shift;
2859 3         6 my $formula = shift;
2860 3         4 my $data = shift;
2861 3         5 my $count = @$data;
2862              
2863 3 50       7 return if !$count;
2864              
2865 3         9 $self->xml_start_tag( 'c:multiLvlStrRef' );
2866              
2867             # Write the c:f element.
2868 3         9 $self->_write_series_formula( $formula );
2869              
2870 3         10 $self->xml_start_tag( 'c:multiLvlStrCache' );
2871              
2872             # Write the c:ptCount element.
2873 3         6 $count = @{ $data->[-1] };
  3         14  
2874 3         11 $self->_write_pt_count( $count );
2875              
2876             # Write the data arrays in reverse order.
2877 3         9 for my $aref ( reverse @$data ) {
2878 6         17 $self->xml_start_tag( 'c:lvl' );
2879              
2880 6         18 for my $i ( 0 .. @$aref - 1 ) {
2881             # Write the c:pt element.
2882 30         53 $self->_write_pt( $i, $aref->[$i] );
2883             }
2884              
2885 6         13 $self->xml_end_tag( 'c:lvl' );
2886             }
2887              
2888 3         10 $self->xml_end_tag( 'c:multiLvlStrCache' );
2889              
2890 3         7 $self->xml_end_tag( 'c:multiLvlStrRef' );
2891             }
2892              
2893              
2894             ##############################################################################
2895             #
2896             # _write_series_formula()
2897             #
2898             # Write the element.
2899             #
2900             sub _write_series_formula {
2901              
2902 1220     1220   2298 my $self = shift;
2903 1220         2299 my $formula = shift;
2904              
2905             # Strip the leading '=' from the formula.
2906 1220         5471 $formula =~ s/^=//;
2907              
2908 1220         5299 $self->xml_data_element( 'c:f', $formula );
2909             }
2910              
2911              
2912             ##############################################################################
2913             #
2914             # _write_axis_ids()
2915             #
2916             # Write the elements for the primary or secondary axes.
2917             #
2918             sub _write_axis_ids {
2919              
2920 354     354   1001 my $self = shift;
2921 354         1384 my %args = @_;
2922              
2923             # Generate the axis ids.
2924 354         3013 $self->_add_axis_ids( %args );
2925              
2926 354 100       1762 if ( $args{primary_axes} ) {
2927              
2928             # Write the axis ids for the primary axes.
2929 342         2986 $self->_write_axis_id( $self->{_axis_ids}->[0] );
2930 342         1477 $self->_write_axis_id( $self->{_axis_ids}->[1] );
2931             }
2932             else {
2933             # Write the axis ids for the secondary axes.
2934 12         53 $self->_write_axis_id( $self->{_axis2_ids}->[0] );
2935 12         45 $self->_write_axis_id( $self->{_axis2_ids}->[1] );
2936             }
2937             }
2938              
2939              
2940             ##############################################################################
2941             #
2942             # _write_axis_id()
2943             #
2944             # Write the element.
2945             #
2946             sub _write_axis_id {
2947              
2948 1409     1409   2735 my $self = shift;
2949 1409         2264 my $val = shift;
2950              
2951 1409         3270 my @attributes = ( 'val' => $val );
2952              
2953 1409         4202 $self->xml_empty_tag( 'c:axId', @attributes );
2954             }
2955              
2956              
2957             ##############################################################################
2958             #
2959             # _write_cat_axis()
2960             #
2961             # Write the element. Usually the X axis.
2962             #
2963             sub _write_cat_axis {
2964              
2965 582     582   1327 my $self = shift;
2966 582         2160 my %args = @_;
2967 582         1401 my $x_axis = $args{x_axis};
2968 582         1102 my $y_axis = $args{y_axis};
2969 582         1266 my $axis_ids = $args{axis_ids};
2970              
2971             # if there are no axis_ids then we don't need to write this element
2972 582 50       1780 return unless $axis_ids;
2973 582 100       2207 return unless scalar @$axis_ids;
2974              
2975 301         868 my $position = $self->{_cat_axis_position};
2976 301         760 my $is_y_axis = $self->{_horiz_cat_axis};
2977              
2978             # Overwrite the default axis position with a user supplied value.
2979 301   66     2129 $position = $x_axis->{_position} || $position;
2980              
2981 301         1548 $self->xml_start_tag( 'c:catAx' );
2982              
2983 301         1366 $self->_write_axis_id( $axis_ids->[0] );
2984              
2985             # Write the c:scaling element.
2986 301         2769 $self->_write_scaling( $x_axis->{_reverse} );
2987              
2988 301 100       1573 $self->_write_delete( 1 ) unless $x_axis->{_visible};
2989              
2990             # Write the c:axPos element.
2991 301         2560 $self->_write_axis_pos( $position, $y_axis->{_reverse} );
2992              
2993             # Write the c:majorGridlines element.
2994 301         3252 $self->_write_major_gridlines( $x_axis->{_major_gridlines} );
2995              
2996             # Write the c:minorGridlines element.
2997 301         2558 $self->_write_minor_gridlines( $x_axis->{_minor_gridlines} );
2998              
2999             # Write the axis title elements.
3000 301         822 my $title;
3001 301 100       2395 if ( $title = $x_axis->{_formula} ) {
    100          
3002              
3003             $self->_write_title_formula( $title, $x_axis->{_data_id}, $is_y_axis,
3004 3         13 $x_axis->{_name_font}, $x_axis->{_layout} );
3005             }
3006             elsif ( $title = $x_axis->{_name} ) {
3007             $self->_write_title_rich( $title, $is_y_axis, $x_axis->{_name_font},
3008 17         114 $x_axis->{_layout} );
3009             }
3010              
3011             # Write the c:numFmt element.
3012 301         2436 $self->_write_cat_number_format( $x_axis );
3013              
3014             # Write the c:majorTickMark element.
3015 301         2306 $self->_write_major_tick_mark( $x_axis->{_major_tick_mark} );
3016              
3017             # Write the c:minorTickMark element.
3018 301         2173 $self->_write_minor_tick_mark( $x_axis->{_minor_tick_mark} );
3019              
3020             # Write the c:tickLblPos element.
3021 301         2033 $self->_write_tick_label_pos( $x_axis->{_label_position} );
3022              
3023             # Write the c:spPr element for the axis line.
3024 301         1522 $self->_write_sp_pr( $x_axis );
3025              
3026             # Write the axis font elements.
3027 301         2360 $self->_write_axis_font( $x_axis->{_num_font} );
3028              
3029             # Write the c:crossAx element.
3030 301         1998 $self->_write_cross_axis( $axis_ids->[1] );
3031              
3032 301 100 100     2171 if ( $self->{_show_crosses} || $x_axis->{_visible} ) {
3033              
3034             # Note, the category crossing comes from the value axis.
3035 297 100 100     2344 if ( !defined $y_axis->{_crossing} || $y_axis->{_crossing} eq 'max' ) {
3036              
3037             # Write the c:crosses element.
3038 296         2241 $self->_write_crosses( $y_axis->{_crossing} );
3039             }
3040             else {
3041              
3042             # Write the c:crossesAt element.
3043 1         21 $self->_write_c_crosses_at( $y_axis->{_crossing} );
3044             }
3045             }
3046              
3047             # Write the c:auto element.
3048 301 100       1576 if (!$x_axis->{_text_axis}) {
3049 300         2192 $self->_write_auto( 1 );
3050             }
3051              
3052             # Write the c:labelAlign element.
3053 301         2590 $self->_write_label_align( $x_axis->{_label_align} );
3054              
3055             # Write the c:labelOffset element.
3056 301         2389 $self->_write_label_offset( 100 );
3057              
3058             # Write the c:tickLblSkip element.
3059 301         2385 $self->_write_tick_lbl_skip( $x_axis->{_interval_unit} );
3060              
3061             # Write the c:tickMarkSkip element.
3062 301         1948 $self->_write_tick_mark_skip( $x_axis->{_interval_tick} );
3063              
3064 301         1290 $self->xml_end_tag( 'c:catAx' );
3065             }
3066              
3067              
3068             ##############################################################################
3069             #
3070             # _write_val_axis()
3071             #
3072             # Write the element. Usually the Y axis.
3073             #
3074             # TODO. Maybe should have a _write_cat_val_axis() method as well for scatter.
3075             #
3076             sub _write_val_axis {
3077              
3078 680     680   1417 my $self = shift;
3079 680         2623 my %args = @_;
3080 680         1592 my $x_axis = $args{x_axis};
3081 680         1373 my $y_axis = $args{y_axis};
3082 680         1321 my $axis_ids = $args{axis_ids};
3083 680   66     3697 my $position = $args{position} || $self->{_val_axis_position};
3084 680         1453 my $is_y_axis = $self->{_horiz_val_axis};
3085              
3086 680 100 50     4162 return unless $axis_ids && scalar @$axis_ids;
3087              
3088             # Overwrite the default axis position with a user supplied value.
3089 350   66     2156 $position = $y_axis->{_position} || $position;
3090              
3091 350         1916 $self->xml_start_tag( 'c:valAx' );
3092              
3093 350         1719 $self->_write_axis_id( $axis_ids->[1] );
3094              
3095             # Write the c:scaling element.
3096             $self->_write_scaling(
3097             $y_axis->{_reverse}, $y_axis->{_min},
3098             $y_axis->{_max}, $y_axis->{_log_base}
3099 350         2585 );
3100              
3101 350 50       1609 $self->_write_delete( 1 ) unless $y_axis->{_visible};
3102              
3103             # Write the c:axPos element.
3104 350         1873 $self->_write_axis_pos( $position, $x_axis->{_reverse} );
3105              
3106             # Write the c:majorGridlines element.
3107 350         1776 $self->_write_major_gridlines( $y_axis->{_major_gridlines} );
3108              
3109             # Write the c:minorGridlines element.
3110 350         1966 $self->_write_minor_gridlines( $y_axis->{_minor_gridlines} );
3111              
3112             # Write the axis title elements.
3113 350         786 my $title;
3114 350 100       2342 if ( $title = $y_axis->{_formula} ) {
    100          
3115             $self->_write_title_formula( $title, $y_axis->{_data_id}, $is_y_axis,
3116 4         25 $y_axis->{_name_font}, $y_axis->{_layout} );
3117             }
3118             elsif ( $title = $y_axis->{_name} ) {
3119             $self->_write_title_rich( $title, $is_y_axis, $y_axis->{_name_font},
3120 19         187 $y_axis->{_layout} );
3121             }
3122              
3123             # Write the c:numberFormat element.
3124 350         2698 $self->_write_number_format( $y_axis );
3125              
3126             # Write the c:majorTickMark element.
3127 350         1775 $self->_write_major_tick_mark( $y_axis->{_major_tick_mark} );
3128              
3129             # Write the c:minorTickMark element.
3130 350         1552 $self->_write_minor_tick_mark( $y_axis->{_minor_tick_mark} );
3131              
3132             # Write the c:tickLblPos element.
3133 350         1641 $self->_write_tick_label_pos( $y_axis->{_label_position} );
3134              
3135             # Write the c:spPr element for the axis line.
3136 350         1789 $self->_write_sp_pr( $y_axis );
3137              
3138             # Write the axis font elements.
3139 350         1629 $self->_write_axis_font( $y_axis->{_num_font} );
3140              
3141             # Write the c:crossAx element.
3142 350         1571 $self->_write_cross_axis( $axis_ids->[0] );
3143              
3144             # Note, the category crossing comes from the value axis.
3145 350 100 100     2728 if ( !defined $x_axis->{_crossing} || $x_axis->{_crossing} eq 'max' ) {
3146              
3147             # Write the c:crosses element.
3148 348         1784 $self->_write_crosses( $x_axis->{_crossing} );
3149             }
3150             else {
3151              
3152             # Write the c:crossesAt element.
3153 2         9 $self->_write_c_crosses_at( $x_axis->{_crossing} );
3154             }
3155              
3156             # Write the c:crossBetween element.
3157 350         3645 $self->_write_cross_between( $x_axis->{_position_axis} );
3158              
3159             # Write the c:majorUnit element.
3160 350         2704 $self->_write_c_major_unit( $y_axis->{_major_unit} );
3161              
3162             # Write the c:minorUnit element.
3163 350         2279 $self->_write_c_minor_unit( $y_axis->{_minor_unit} );
3164              
3165             # Write the c:dispUnits element.
3166             $self->_write_disp_units( $y_axis->{_display_units},
3167 350         3013 $y_axis->{_display_units_visible} );
3168              
3169 350         1567 $self->xml_end_tag( 'c:valAx' );
3170             }
3171              
3172              
3173             ##############################################################################
3174             #
3175             # _write_cat_val_axis()
3176             #
3177             # Write the element. This is for the second valAx in scatter plots.
3178             # Usually the X axis.
3179             #
3180             sub _write_cat_val_axis {
3181              
3182 62     62   134 my $self = shift;
3183 62         337 my %args = @_;
3184 62         157 my $x_axis = $args{x_axis};
3185 62         155 my $y_axis = $args{y_axis};
3186 62         154 my $axis_ids = $args{axis_ids};
3187 62   33     277 my $position = $args{position} || $self->{_val_axis_position};
3188 62         131 my $is_y_axis = $self->{_horiz_val_axis};
3189              
3190 62 100 50     405 return unless $axis_ids && scalar @$axis_ids;
3191              
3192             # Overwrite the default axis position with a user supplied value.
3193 32   66     230 $position = $x_axis->{_position} || $position;
3194              
3195 32         206 $self->xml_start_tag( 'c:valAx' );
3196              
3197 32         165 $self->_write_axis_id( $axis_ids->[0] );
3198              
3199             # Write the c:scaling element.
3200             $self->_write_scaling(
3201             $x_axis->{_reverse}, $x_axis->{_min},
3202             $x_axis->{_max}, $x_axis->{_log_base}
3203 32         353 );
3204              
3205 32 100       145 $self->_write_delete( 1 ) unless $x_axis->{_visible};
3206              
3207             # Write the c:axPos element.
3208 32         296 $self->_write_axis_pos( $position, $y_axis->{_reverse} );
3209              
3210             # Write the c:majorGridlines element.
3211 32         343 $self->_write_major_gridlines( $x_axis->{_major_gridlines} );
3212              
3213             # Write the c:minorGridlines element.
3214 32         275 $self->_write_minor_gridlines( $x_axis->{_minor_gridlines} );
3215              
3216             # Write the axis title elements.
3217 32         74 my $title;
3218 32 100       329 if ( $title = $x_axis->{_formula} ) {
    100          
3219             $self->_write_title_formula( $title, $x_axis->{_data_id}, $is_y_axis,
3220 1         7 $x_axis->{_name_font}, $x_axis->{_layout} );
3221             }
3222             elsif ( $title = $x_axis->{_name} ) {
3223             $self->_write_title_rich( $title, $is_y_axis, $x_axis->{_name_font},
3224 1         5 $x_axis->{_layout} );
3225             }
3226              
3227             # Write the c:numberFormat element.
3228 32         231 $self->_write_number_format( $x_axis );
3229              
3230             # Write the c:majorTickMark element.
3231 32         311 $self->_write_major_tick_mark( $x_axis->{_major_tick_mark} );
3232              
3233             # Write the c:minorTickMark element.
3234 32         265 $self->_write_minor_tick_mark( $x_axis->{_minor_tick_mark} );
3235              
3236             # Write the c:tickLblPos element.
3237 32         275 $self->_write_tick_label_pos( $x_axis->{_label_position} );
3238              
3239             # Write the c:spPr element for the axis line.
3240 32         174 $self->_write_sp_pr( $x_axis );
3241              
3242             # Write the axis font elements.
3243 32         289 $self->_write_axis_font( $x_axis->{_num_font} );
3244              
3245             # Write the c:crossAx element.
3246 32         247 $self->_write_cross_axis( $axis_ids->[1] );
3247              
3248             # Note, the category crossing comes from the value axis.
3249 32 100 100     348 if ( !defined $y_axis->{_crossing} || $y_axis->{_crossing} eq 'max' ) {
3250              
3251             # Write the c:crosses element.
3252 31         267 $self->_write_crosses( $y_axis->{_crossing} );
3253             }
3254             else {
3255              
3256             # Write the c:crossesAt element.
3257 1         8 $self->_write_c_crosses_at( $y_axis->{_crossing} );
3258             }
3259              
3260             # Write the c:crossBetween element.
3261 32         386 $self->_write_cross_between( $y_axis->{_position_axis} );
3262              
3263             # Write the c:majorUnit element.
3264 32         313 $self->_write_c_major_unit( $x_axis->{_major_unit} );
3265              
3266             # Write the c:minorUnit element.
3267 32         224 $self->_write_c_minor_unit( $x_axis->{_minor_unit} );
3268              
3269             # Write the c:dispUnits element.
3270             $self->_write_disp_units( $x_axis->{_display_units},
3271 32         232 $x_axis->{_display_units_visible} );
3272              
3273 32         149 $self->xml_end_tag( 'c:valAx' );
3274             }
3275              
3276              
3277             ##############################################################################
3278             #
3279             # _write_date_axis()
3280             #
3281             # Write the element. Usually the X axis.
3282             #
3283             sub _write_date_axis {
3284              
3285 32     32   67 my $self = shift;
3286 32         129 my %args = @_;
3287 32         73 my $x_axis = $args{x_axis};
3288 32         73 my $y_axis = $args{y_axis};
3289 32         64 my $axis_ids = $args{axis_ids};
3290              
3291 32 100 50     250 return unless $axis_ids && scalar @$axis_ids;
3292              
3293 17         47 my $position = $self->{_cat_axis_position};
3294              
3295             # Overwrite the default axis position with a user supplied value.
3296 17   33     116 $position = $x_axis->{_position} || $position;
3297              
3298 17         92 $self->xml_start_tag( 'c:dateAx' );
3299              
3300 17         83 $self->_write_axis_id( $axis_ids->[0] );
3301              
3302             # Write the c:scaling element.
3303             $self->_write_scaling(
3304             $x_axis->{_reverse}, $x_axis->{_min},
3305             $x_axis->{_max}, $x_axis->{_log_base}
3306 17         176 );
3307              
3308 17 100       117 $self->_write_delete( 1 ) unless $x_axis->{_visible};
3309              
3310             # Write the c:axPos element.
3311 17         162 $self->_write_axis_pos( $position, $y_axis->{_reverse} );
3312              
3313             # Write the c:majorGridlines element.
3314 17         157 $self->_write_major_gridlines( $x_axis->{_major_gridlines} );
3315              
3316             # Write the c:minorGridlines element.
3317 17         146 $self->_write_minor_gridlines( $x_axis->{_minor_gridlines} );
3318              
3319             # Write the axis title elements.
3320 17         39 my $title;
3321 17 50       135 if ( $title = $x_axis->{_formula} ) {
    100          
3322             $self->_write_title_formula( $title, $x_axis->{_data_id}, undef,
3323 0         0 $x_axis->{_name_font}, $x_axis->{_layout} );
3324             }
3325             elsif ( $title = $x_axis->{_name} ) {
3326             $self->_write_title_rich( $title, undef, $x_axis->{_name_font},
3327 1         4 $x_axis->{_layout} );
3328             }
3329              
3330             # Write the c:numFmt element.
3331 17         143 $self->_write_number_format( $x_axis );
3332              
3333             # Write the c:majorTickMark element.
3334 17         129 $self->_write_major_tick_mark( $x_axis->{_major_tick_mark} );
3335              
3336             # Write the c:minorTickMark element.
3337 17         120 $self->_write_minor_tick_mark( $x_axis->{_minor_tick_mark} );
3338              
3339             # Write the c:tickLblPos element.
3340 17         136 $self->_write_tick_label_pos( $x_axis->{_label_position} );
3341              
3342             # Write the c:spPr element for the axis line.
3343 17         74 $self->_write_sp_pr( $x_axis );
3344              
3345             # Write the axis font elements.
3346 17         129 $self->_write_axis_font( $x_axis->{_num_font} );
3347              
3348             # Write the c:crossAx element.
3349 17         98 $self->_write_cross_axis( $axis_ids->[1] );
3350              
3351 17 100 100     173 if ( $self->{_show_crosses} || $x_axis->{_visible} ) {
3352              
3353             # Note, the category crossing comes from the value axis.
3354 16 50 33     96 if ( !defined $y_axis->{_crossing} || $y_axis->{_crossing} eq 'max' ) {
3355              
3356             # Write the c:crosses element.
3357 16         115 $self->_write_crosses( $y_axis->{_crossing} );
3358             }
3359             else {
3360              
3361             # Write the c:crossesAt element.
3362 0         0 $self->_write_c_crosses_at( $y_axis->{_crossing} );
3363             }
3364             }
3365              
3366             # Write the c:auto element.
3367 17         147 $self->_write_auto( 1 );
3368              
3369             # Write the c:labelOffset element.
3370 17         140 $self->_write_label_offset( 100 );
3371              
3372             # Write the c:tickLblSkip element.
3373 17         118 $self->_write_tick_lbl_skip( $x_axis->{_interval_unit} );
3374              
3375             # Write the c:tickMarkSkip element.
3376 17         118 $self->_write_tick_mark_skip( $x_axis->{_interval_tick} );
3377              
3378             # Write the c:majorUnit element.
3379 17         99 $self->_write_c_major_unit( $x_axis->{_major_unit} );
3380              
3381             # Write the c:majorTimeUnit element.
3382 17 100       138 if ( defined $x_axis->{_major_unit} ) {
3383 3         19 $self->_write_c_major_time_unit( $x_axis->{_major_unit_type} );
3384             }
3385              
3386             # Write the c:minorUnit element.
3387 17         121 $self->_write_c_minor_unit( $x_axis->{_minor_unit} );
3388              
3389             # Write the c:minorTimeUnit element.
3390 17 100       59 if ( defined $x_axis->{_minor_unit} ) {
3391 3         17 $self->_write_c_minor_time_unit( $x_axis->{_minor_unit_type} );
3392             }
3393              
3394 17         71 $self->xml_end_tag( 'c:dateAx' );
3395             }
3396              
3397              
3398             ##############################################################################
3399             #
3400             # _write_scaling()
3401             #
3402             # Write the element.
3403             #
3404             sub _write_scaling {
3405              
3406 700     700   1570 my $self = shift;
3407 700         1307 my $reverse = shift;
3408 700         1287 my $min = shift;
3409 700         1241 my $max = shift;
3410 700         1304 my $log_base = shift;
3411              
3412 700         2496 $self->xml_start_tag( 'c:scaling' );
3413              
3414             # Write the c:logBase element.
3415 700         3643 $self->_write_c_log_base( $log_base );
3416              
3417             # Write the c:orientation element.
3418 700         3221 $self->_write_orientation( $reverse );
3419              
3420             # Write the c:max element.
3421 700         3664 $self->_write_c_max( $max );
3422              
3423             # Write the c:min element.
3424 700         3246 $self->_write_c_min( $min );
3425              
3426 700         2197 $self->xml_end_tag( 'c:scaling' );
3427             }
3428              
3429              
3430             ##############################################################################
3431             #
3432             # _write_c_log_base()
3433             #
3434             # Write the element.
3435             #
3436             sub _write_c_log_base {
3437              
3438 700     700   1500 my $self = shift;
3439 700         1335 my $val = shift;
3440              
3441 700 100       2186 return unless $val;
3442              
3443 1         3 my @attributes = ( 'val' => $val );
3444              
3445 1         4 $self->xml_empty_tag( 'c:logBase', @attributes );
3446             }
3447              
3448              
3449             ##############################################################################
3450             #
3451             # _write_orientation()
3452             #
3453             # Write the element.
3454             #
3455             sub _write_orientation {
3456              
3457 701     701   1472 my $self = shift;
3458 701         1289 my $reverse = shift;
3459 701         1448 my $val = 'minMax';
3460              
3461 701 100       2022 $val = 'maxMin' if $reverse;
3462              
3463 701         1960 my @attributes = ( 'val' => $val );
3464              
3465 701         2321 $self->xml_empty_tag( 'c:orientation', @attributes );
3466             }
3467              
3468              
3469             ##############################################################################
3470             #
3471             # _write_c_max()
3472             #
3473             # Write the element.
3474             #
3475             sub _write_c_max {
3476              
3477 700     700   1415 my $self = shift;
3478 700         1260 my $max = shift;
3479              
3480 700 100       2296 return unless defined $max;
3481              
3482 7         15 my @attributes = ( 'val' => $max );
3483              
3484 7         27 $self->xml_empty_tag( 'c:max', @attributes );
3485             }
3486              
3487              
3488             ##############################################################################
3489             #
3490             # _write_c_min()
3491             #
3492             # Write the element.
3493             #
3494             sub _write_c_min {
3495              
3496 700     700   1350 my $self = shift;
3497 700         1253 my $min = shift;
3498              
3499 700 100       2135 return unless defined $min;
3500              
3501 7         17 my @attributes = ( 'val' => $min );
3502              
3503 7         18 $self->xml_empty_tag( 'c:min', @attributes );
3504             }
3505              
3506              
3507             ##############################################################################
3508             #
3509             # _write_axis_pos()
3510             #
3511             # Write the element.
3512             #
3513             sub _write_axis_pos {
3514              
3515 701     701   1508 my $self = shift;
3516 701         1482 my $val = shift;
3517 701         1297 my $reverse = shift;
3518              
3519 701 100       2061 if ( $reverse ) {
3520 5 100       24 $val = 'r' if $val eq 'l';
3521 5 100       14 $val = 't' if $val eq 'b';
3522             }
3523              
3524 701         1970 my @attributes = ( 'val' => $val );
3525              
3526 701         2293 $self->xml_empty_tag( 'c:axPos', @attributes );
3527             }
3528              
3529              
3530             ##############################################################################
3531             #
3532             # _write_number_format()
3533             #
3534             # Write the element. Note: It is assumed that if a user
3535             # defined number format is supplied (i.e., non-default) then the sourceLinked
3536             # attribute is 0. The user can override this if required.
3537             #
3538             sub _write_number_format {
3539              
3540 401     401   1048 my $self = shift;
3541 401         873 my $axis = shift;
3542 401         1107 my $format_code = $axis->{_num_format};
3543 401         900 my $source_linked = 1;
3544              
3545             # Check if a user defined number format has been set.
3546 401 100       1923 if ( $format_code ne $axis->{_defaults}->{num_format} ) {
3547 8         20 $source_linked = 0;
3548             }
3549              
3550             # User override of sourceLinked.
3551 401 100       1531 if ( $axis->{_num_format_linked} ) {
3552 4         9 $source_linked = 1;
3553             }
3554              
3555 401         1529 my @attributes = (
3556             'formatCode' => $format_code,
3557             'sourceLinked' => $source_linked,
3558             );
3559              
3560 401         1873 $self->xml_empty_tag( 'c:numFmt', @attributes );
3561             }
3562              
3563              
3564             ##############################################################################
3565             #
3566             # _write_cat_number_format()
3567             #
3568             # Write the element. Special case handler for category axes which
3569             # don't always have a number format.
3570             #
3571             sub _write_cat_number_format {
3572              
3573 303     303   801 my $self = shift;
3574 303         690 my $axis = shift;
3575 303         778 my $format_code = $axis->{_num_format};
3576 303         702 my $source_linked = 1;
3577 303         732 my $default_format = 1;
3578              
3579             # Check if a user defined number format has been set.
3580 303 100       1490 if ( $format_code ne $axis->{_defaults}->{num_format} ) {
3581 6         15 $source_linked = 0;
3582 6         13 $default_format = 0;
3583             }
3584              
3585             # User override of linkedSource.
3586 303 100       1437 if ( $axis->{_num_format_linked} ) {
3587 2         24 $source_linked = 1;
3588             }
3589              
3590             # Skip if cat doesn't have a num format (unless it is non-default).
3591 303 100 100     2231 if ( !$self->{_cat_has_num_fmt} && $default_format ) {
3592 230         633 return;
3593             }
3594              
3595 73         314 my @attributes = (
3596             'formatCode' => $format_code,
3597             'sourceLinked' => $source_linked,
3598             );
3599              
3600 73         348 $self->xml_empty_tag( 'c:numFmt', @attributes );
3601             }
3602              
3603              
3604             ##############################################################################
3605             #
3606             # _write_number_format()
3607             #
3608             # Write the element for data labels.
3609             #
3610             sub _write_data_label_number_format {
3611              
3612 3     3   6 my $self = shift;
3613 3         6 my $format_code = shift;
3614 3         5 my $source_linked = 0;
3615              
3616 3         10 my @attributes = (
3617             'formatCode' => $format_code,
3618             'sourceLinked' => $source_linked,
3619             );
3620              
3621 3         9 $self->xml_empty_tag( 'c:numFmt', @attributes );
3622             }
3623              
3624              
3625             ##############################################################################
3626             #
3627             # _write_major_tick_mark()
3628             #
3629             # Write the element.
3630             #
3631             sub _write_major_tick_mark {
3632              
3633 700     700   1514 my $self = shift;
3634 700         1306 my $val = shift;
3635              
3636 700 100       2167 return unless $val;
3637              
3638 7         21 my @attributes = ( 'val' => $val );
3639              
3640 7         23 $self->xml_empty_tag( 'c:majorTickMark', @attributes );
3641             }
3642              
3643              
3644             ##############################################################################
3645             #
3646             # _write_minor_tick_mark()
3647             #
3648             # Write the element.
3649             #
3650             sub _write_minor_tick_mark {
3651              
3652 700     700   1410 my $self = shift;
3653 700         1310 my $val = shift;
3654              
3655 700 100       1995 return unless $val;
3656              
3657 2         6 my @attributes = ( 'val' => $val );
3658              
3659 2         8 $self->xml_empty_tag( 'c:minorTickMark', @attributes );
3660             }
3661              
3662              
3663             ##############################################################################
3664             #
3665             # _write_tick_label_pos()
3666             #
3667             # Write the element.
3668             #
3669             sub _write_tick_label_pos {
3670              
3671 701     701   1448 my $self = shift;
3672 701   100     3466 my $val = shift || 'nextTo';
3673              
3674 701 100       2405 if ( $val eq 'next_to' ) {
3675 2         4 $val = 'nextTo';
3676             }
3677              
3678 701         1941 my @attributes = ( 'val' => $val );
3679              
3680 701         2390 $self->xml_empty_tag( 'c:tickLblPos', @attributes );
3681             }
3682              
3683              
3684             ##############################################################################
3685             #
3686             # _write_cross_axis()
3687             #
3688             # Write the element.
3689             #
3690             sub _write_cross_axis {
3691              
3692 701     701   1431 my $self = shift;
3693 701         1273 my $val = shift;
3694              
3695 701         1922 my @attributes = ( 'val' => $val );
3696              
3697 701         2465 $self->xml_empty_tag( 'c:crossAx', @attributes );
3698             }
3699              
3700              
3701             ##############################################################################
3702             #
3703             # _write_crosses()
3704             #
3705             # Write the element.
3706             #
3707             sub _write_crosses {
3708              
3709 692     692   1594 my $self = shift;
3710 692   100     3095 my $val = shift || 'autoZero';
3711              
3712 692         2039 my @attributes = ( 'val' => $val );
3713              
3714 692         2403 $self->xml_empty_tag( 'c:crosses', @attributes );
3715             }
3716              
3717              
3718             ##############################################################################
3719             #
3720             # _write_c_crosses_at()
3721             #
3722             # Write the element.
3723             #
3724             sub _write_c_crosses_at {
3725              
3726 4     4   10 my $self = shift;
3727 4         13 my $val = shift;
3728              
3729 4         13 my @attributes = ( 'val' => $val );
3730              
3731 4         12 $self->xml_empty_tag( 'c:crossesAt', @attributes );
3732             }
3733              
3734              
3735             ##############################################################################
3736             #
3737             # _write_auto()
3738             #
3739             # Write the element.
3740             #
3741             sub _write_auto {
3742              
3743 318     318   899 my $self = shift;
3744 318         752 my $val = shift;
3745              
3746 318         1121 my @attributes = ( 'val' => $val );
3747              
3748 318         1316 $self->xml_empty_tag( 'c:auto', @attributes );
3749             }
3750              
3751              
3752             ##############################################################################
3753             #
3754             # _write_label_align()
3755             #
3756             # Write the element.
3757             #
3758             sub _write_label_align {
3759              
3760 302     302   842 my $self = shift;
3761 302   100     1963 my $val = shift || 'ctr';
3762              
3763 302 100       1451 if ( $val eq 'right' ) {
3764 1         11 $val = 'r';
3765             }
3766              
3767 302 100       1288 if ( $val eq 'left' ) {
3768 1         1 $val = 'l';
3769             }
3770              
3771 302         998 my @attributes = ( 'val' => $val );
3772              
3773 302         1319 $self->xml_empty_tag( 'c:lblAlgn', @attributes );
3774             }
3775              
3776              
3777             ##############################################################################
3778             #
3779             # _write_label_offset()
3780             #
3781             # Write the element.
3782             #
3783             sub _write_label_offset {
3784              
3785 319     319   891 my $self = shift;
3786 319         854 my $val = shift;
3787              
3788 319         1148 my @attributes = ( 'val' => $val );
3789              
3790 319         1422 $self->xml_empty_tag( 'c:lblOffset', @attributes );
3791             }
3792              
3793              
3794             ##############################################################################
3795             #
3796             # _write_tick_lbl_skip()
3797             #
3798             # Write the element.
3799             #
3800             sub _write_tick_lbl_skip {
3801              
3802 318     318   803 my $self = shift;
3803 318         691 my $val = shift;
3804              
3805 318 100       1216 return unless $val;
3806              
3807 2         7 my @attributes = ( 'val' => $val );
3808              
3809 2         25 $self->xml_empty_tag( 'c:tickLblSkip', @attributes );
3810             }
3811              
3812              
3813             ##############################################################################
3814             #
3815             # _write_tick_mark_skip()
3816             #
3817             # Write the element.
3818             #
3819             sub _write_tick_mark_skip {
3820              
3821 318     318   794 my $self = shift;
3822 318         764 my $val = shift;
3823              
3824 318 100       1144 return unless $val;
3825              
3826 1         3 my @attributes = ( 'val' => $val );
3827              
3828 1         3 $self->xml_empty_tag( 'c:tickMarkSkip', @attributes );
3829             }
3830              
3831              
3832             ##############################################################################
3833             #
3834             # _write_major_gridlines()
3835             #
3836             # Write the element.
3837             #
3838             sub _write_major_gridlines {
3839              
3840 701     701   1580 my $self = shift;
3841 701         1598 my $gridlines = shift;
3842              
3843 701 100       2238 return unless $gridlines;
3844 348 50       1631 return unless $gridlines->{_visible};
3845              
3846 348 100       2008 if ( $gridlines->{_line}->{_defined} ) {
3847 2         5 $self->xml_start_tag( 'c:majorGridlines' );
3848              
3849             # Write the c:spPr element.
3850 2         6 $self->_write_sp_pr( $gridlines );
3851              
3852 2         4 $self->xml_end_tag( 'c:majorGridlines' );
3853             }
3854             else {
3855 346         1582 $self->xml_empty_tag( 'c:majorGridlines' );
3856             }
3857             }
3858              
3859              
3860             ##############################################################################
3861             #
3862             # _write_minor_gridlines()
3863             #
3864             # Write the element.
3865             #
3866             sub _write_minor_gridlines {
3867              
3868 700     700   1482 my $self = shift;
3869 700         1727 my $gridlines = shift;
3870              
3871 700 100       2165 return unless $gridlines;
3872 9 50       31 return unless $gridlines->{_visible};
3873              
3874 9 100       24 if ( $gridlines->{_line}->{_defined} ) {
3875 2         5 $self->xml_start_tag( 'c:minorGridlines' );
3876              
3877             # Write the c:spPr element.
3878 2         5 $self->_write_sp_pr( $gridlines );
3879              
3880 2         5 $self->xml_end_tag( 'c:minorGridlines' );
3881             }
3882             else {
3883 7         19 $self->xml_empty_tag( 'c:minorGridlines' );
3884             }
3885             }
3886              
3887              
3888             ##############################################################################
3889             #
3890             # _write_cross_between()
3891             #
3892             # Write the element.
3893             #
3894             sub _write_cross_between {
3895              
3896 382     382   1013 my $self = shift;
3897              
3898 382   66     2688 my $val = shift || $self->{_cross_between};
3899              
3900 382         1343 my @attributes = ( 'val' => $val );
3901              
3902 382         1638 $self->xml_empty_tag( 'c:crossBetween', @attributes );
3903             }
3904              
3905              
3906             ##############################################################################
3907             #
3908             # _write_c_major_unit()
3909             #
3910             # Write the element.
3911             #
3912             sub _write_c_major_unit {
3913              
3914 399     399   987 my $self = shift;
3915 399         961 my $val = shift;
3916              
3917 399 100       1592 return unless $val;
3918              
3919 6         22 my @attributes = ( 'val' => $val );
3920              
3921 6         23 $self->xml_empty_tag( 'c:majorUnit', @attributes );
3922             }
3923              
3924              
3925             ##############################################################################
3926             #
3927             # _write_c_minor_unit()
3928             #
3929             # Write the element.
3930             #
3931             sub _write_c_minor_unit {
3932              
3933 399     399   995 my $self = shift;
3934 399         847 my $val = shift;
3935              
3936 399 100       1395 return unless $val;
3937              
3938 6         17 my @attributes = ( 'val' => $val );
3939              
3940 6         22 $self->xml_empty_tag( 'c:minorUnit', @attributes );
3941             }
3942              
3943              
3944             ##############################################################################
3945             #
3946             # _write_c_major_time_unit()
3947             #
3948             # Write the element.
3949             #
3950             sub _write_c_major_time_unit {
3951              
3952 3     3   8 my $self = shift;
3953 3   100     11 my $val = shift || 'days';
3954              
3955 3         9 my @attributes = ( 'val' => $val );
3956              
3957 3         19 $self->xml_empty_tag( 'c:majorTimeUnit', @attributes );
3958             }
3959              
3960              
3961             ##############################################################################
3962             #
3963             # _write_c_minor_time_unit()
3964             #
3965             # Write the element.
3966             #
3967             sub _write_c_minor_time_unit {
3968              
3969 3     3   7 my $self = shift;
3970 3   100     21 my $val = shift || 'days';
3971              
3972 3         9 my @attributes = ( 'val' => $val );
3973              
3974 3         13 $self->xml_empty_tag( 'c:minorTimeUnit', @attributes );
3975             }
3976              
3977              
3978             ##############################################################################
3979             #
3980             # _write_legend()
3981             #
3982             # Write the element.
3983             #
3984             sub _write_legend {
3985              
3986 350     350   965 my $self = shift;
3987 350         1022 my $legend = $self->{_legend};
3988 350   100     2506 my $position = $legend->{_position} || 'right';
3989 350         922 my $font = $legend->{_font};
3990 350         1055 my @delete_series = ();
3991 350         868 my $overlay = 0;
3992              
3993 350 100 66     1906 if ( defined $legend->{_delete_series}
3994             && ref $legend->{_delete_series} eq 'ARRAY' )
3995             {
3996 4         12 @delete_series = @{ $legend->{_delete_series} };
  4         16  
3997             }
3998              
3999 350 100       1676 if ( $position =~ s/^overlay_// ) {
4000 5         9 $overlay = 1;
4001             }
4002              
4003 350         3073 my %allowed = (
4004             right => 'r',
4005             left => 'l',
4006             top => 't',
4007             bottom => 'b',
4008             top_right => 'tr',
4009             );
4010              
4011 350 100       1638 return if $position eq 'none';
4012 347 100       1561 return unless exists $allowed{$position};
4013              
4014 346         1082 $position = $allowed{$position};
4015              
4016 346         1884 $self->xml_start_tag( 'c:legend' );
4017              
4018             # Write the c:legendPos element.
4019 346         2592 $self->_write_legend_pos( $position );
4020              
4021             # Remove series labels from the legend.
4022 346         1440 for my $index ( @delete_series ) {
4023              
4024             # Write the c:legendEntry element.
4025 8         36 $self->_write_legend_entry( $index );
4026             }
4027              
4028             # Write the c:layout element.
4029 346         2148 $self->_write_layout( $legend->{_layout}, 'legend' );
4030              
4031             # Write the c:overlay element.
4032 346 100       1536 $self->_write_overlay() if $overlay;
4033              
4034             # Write the c:spPr element.
4035 346         1858 $self->_write_sp_pr( $legend );
4036              
4037             # Write the c:txPr element.
4038 346 100       1344 if ( $font ) {
4039 2         16 $self->_write_tx_pr( undef, $font );
4040             }
4041              
4042 346         1560 $self->xml_end_tag( 'c:legend' );
4043             }
4044              
4045              
4046             ##############################################################################
4047             #
4048             # _write_legend_pos()
4049             #
4050             # Write the element.
4051             #
4052             sub _write_legend_pos {
4053              
4054 402     402   1065 my $self = shift;
4055 402         967 my $val = shift;
4056              
4057 402         1352 my @attributes = ( 'val' => $val );
4058              
4059 402         2026 $self->xml_empty_tag( 'c:legendPos', @attributes );
4060             }
4061              
4062              
4063             ##############################################################################
4064             #
4065             # _write_legend_entry()
4066             #
4067             # Write the element.
4068             #
4069             sub _write_legend_entry {
4070              
4071 9     9   22 my $self = shift;
4072 9         14 my $index = shift;
4073              
4074 9         29 $self->xml_start_tag( 'c:legendEntry' );
4075              
4076             # Write the c:idx element.
4077 9         29 $self->_write_idx( $index );
4078              
4079             # Write the c:delete element.
4080 9         49 $self->_write_delete( 1 );
4081              
4082 9         27 $self->xml_end_tag( 'c:legendEntry' );
4083             }
4084              
4085              
4086             ##############################################################################
4087             #
4088             # _write_overlay()
4089             #
4090             # Write the element.
4091             #
4092             sub _write_overlay {
4093              
4094 8     8   19 my $self = shift;
4095 8         52 my $val = 1;
4096              
4097 8         25 my @attributes = ( 'val' => $val );
4098              
4099 8         32 $self->xml_empty_tag( 'c:overlay', @attributes );
4100             }
4101              
4102              
4103             ##############################################################################
4104             #
4105             # _write_plot_vis_only()
4106             #
4107             # Write the element.
4108             #
4109             sub _write_plot_vis_only {
4110              
4111 395     395   1042 my $self = shift;
4112 395         948 my $val = 1;
4113              
4114             # Ignore this element if we are plotting hidden data.
4115 395 100       1802 return if $self->{_show_hidden_data};
4116              
4117 394         1461 my @attributes = ( 'val' => $val );
4118              
4119 394         2118 $self->xml_empty_tag( 'c:plotVisOnly', @attributes );
4120             }
4121              
4122              
4123             ##############################################################################
4124             #
4125             # _write_print_settings()
4126             #
4127             # Write the element.
4128             #
4129             sub _write_print_settings {
4130              
4131 374     374   1010 my $self = shift;
4132              
4133 374         1723 $self->xml_start_tag( 'c:printSettings' );
4134              
4135             # Write the c:headerFooter element.
4136 374         2646 $self->_write_header_footer();
4137              
4138             # Write the c:pageMargins element.
4139 374         3191 $self->_write_page_margins();
4140              
4141             # Write the c:pageSetup element.
4142 374         2925 $self->_write_page_setup();
4143              
4144 374         2044 $self->xml_end_tag( 'c:printSettings' );
4145             }
4146              
4147              
4148             ##############################################################################
4149             #
4150             # _write_header_footer()
4151             #
4152             # Write the element.
4153             #
4154             sub _write_header_footer {
4155              
4156 374     374   1037 my $self = shift;
4157              
4158 374         1901 $self->xml_empty_tag( 'c:headerFooter' );
4159             }
4160              
4161              
4162             ##############################################################################
4163             #
4164             # _write_page_margins()
4165             #
4166             # Write the element.
4167             #
4168             sub _write_page_margins {
4169              
4170 375     375   991 my $self = shift;
4171 375         869 my $b = 0.75;
4172 375         794 my $l = 0.7;
4173 375         819 my $r = 0.7;
4174 375         866 my $t = 0.75;
4175 375         882 my $header = 0.3;
4176 375         813 my $footer = 0.3;
4177              
4178 375         1975 my @attributes = (
4179             'b' => $b,
4180             'l' => $l,
4181             'r' => $r,
4182             't' => $t,
4183             'header' => $header,
4184             'footer' => $footer,
4185             );
4186              
4187 375         2207 $self->xml_empty_tag( 'c:pageMargins', @attributes );
4188             }
4189              
4190              
4191             ##############################################################################
4192             #
4193             # _write_page_setup()
4194             #
4195             # Write the element.
4196             #
4197             sub _write_page_setup {
4198              
4199 375     375   995 my $self = shift;
4200              
4201 375         1625 $self->xml_empty_tag( 'c:pageSetup' );
4202             }
4203              
4204              
4205             ##############################################################################
4206             #
4207             # _write_auto_title_deleted()
4208             #
4209             # Write the element.
4210             #
4211             sub _write_auto_title_deleted {
4212              
4213 1     1   2 my $self = shift;
4214              
4215 1         3 my @attributes = ( 'val' => 1 );
4216              
4217 1         4 $self->xml_empty_tag( 'c:autoTitleDeleted', @attributes );
4218             }
4219              
4220              
4221             ##############################################################################
4222             #
4223             # _write_title_rich()
4224             #
4225             # Write the element for a rich string.
4226             #
4227             sub _write_title_rich {
4228              
4229 53     53   110 my $self = shift;
4230 53         99 my $title = shift;
4231 53         88 my $is_y_axis = shift;
4232 53         104 my $font = shift;
4233 53         128 my $layout = shift;
4234 53         91 my $overlay = shift;
4235              
4236 53         200 $self->xml_start_tag( 'c:title' );
4237              
4238             # Write the c:tx element.
4239 53         280 $self->_write_tx_rich( $title, $is_y_axis, $font );
4240              
4241             # Write the c:layout element.
4242 53         243 $self->_write_layout( $layout, 'text' );
4243              
4244             # Write the c:overlay element.
4245 53 100       195 $self->_write_overlay() if $overlay;
4246              
4247 53         201 $self->xml_end_tag( 'c:title' );
4248             }
4249              
4250              
4251             ##############################################################################
4252             #
4253             # _write_title_formula()
4254             #
4255             # Write the element for a rich string.
4256             #
4257             sub _write_title_formula {
4258              
4259 13     13   27 my $self = shift;
4260 13         25 my $title = shift;
4261 13         22 my $data_id = shift;
4262 13         22 my $is_y_axis = shift;
4263 13         20 my $font = shift;
4264 13         30 my $layout = shift;
4265 13         20 my $overlay = shift;
4266              
4267 13         45 $self->xml_start_tag( 'c:title' );
4268              
4269             # Write the c:tx element.
4270 13         73 $self->_write_tx_formula( $title, $data_id );
4271              
4272             # Write the c:layout element.
4273 13         68 $self->_write_layout( $layout, 'text' );
4274              
4275             # Write the c:overlay element.
4276 13 100       41 $self->_write_overlay() if $overlay;
4277              
4278             # Write the c:txPr element.
4279 13         64 $self->_write_tx_pr( $is_y_axis, $font );
4280              
4281 13         32 $self->xml_end_tag( 'c:title' );
4282             }
4283              
4284              
4285             ##############################################################################
4286             #
4287             # _write_tx_rich()
4288             #
4289             # Write the element.
4290             #
4291             sub _write_tx_rich {
4292              
4293 53     53   106 my $self = shift;
4294 53         119 my $title = shift;
4295 53         92 my $is_y_axis = shift;
4296 53         87 my $font = shift;
4297              
4298 53         188 $self->xml_start_tag( 'c:tx' );
4299              
4300             # Write the c:rich element.
4301 53         314 $self->_write_rich( $title, $is_y_axis, $font );
4302              
4303 53         147 $self->xml_end_tag( 'c:tx' );
4304             }
4305              
4306              
4307             ##############################################################################
4308             #
4309             # _write_tx_value()
4310             #
4311             # Write the element with a simple value such as for series names.
4312             #
4313             sub _write_tx_value {
4314              
4315 2     2   6 my $self = shift;
4316 2         4 my $title = shift;
4317              
4318 2         8 $self->xml_start_tag( 'c:tx' );
4319              
4320             # Write the c:v element.
4321 2         11 $self->_write_v( $title );
4322              
4323 2         17 $self->xml_end_tag( 'c:tx' );
4324             }
4325              
4326              
4327             ##############################################################################
4328             #
4329             # _write_tx_formula()
4330             #
4331             # Write the element.
4332             #
4333             sub _write_tx_formula {
4334              
4335 24     24   70 my $self = shift;
4336 24         49 my $title = shift;
4337 24         51 my $data_id = shift;
4338 24         46 my $data;
4339              
4340 24 50       63 if ( defined $data_id ) {
4341 24         58 $data = $self->{_formula_data}->[$data_id];
4342             }
4343              
4344 24         84 $self->xml_start_tag( 'c:tx' );
4345              
4346             # Write the c:strRef element.
4347 24         127 $self->_write_str_ref( $title, $data, 'str' );
4348              
4349 24         68 $self->xml_end_tag( 'c:tx' );
4350             }
4351              
4352              
4353             ##############################################################################
4354             #
4355             # _write_rich()
4356             #
4357             # Write the element.
4358             #
4359             sub _write_rich {
4360              
4361 53     53   121 my $self = shift;
4362 53         128 my $title = shift;
4363 53         102 my $is_y_axis = shift;
4364 53         97 my $rotation = undef;
4365 53         110 my $font = shift;
4366              
4367 53 50 66     233 if ( $font && exists $font->{_rotation} ) {
4368 17         36 $rotation = $font->{_rotation};
4369             }
4370              
4371 53         182 $self->xml_start_tag( 'c:rich' );
4372              
4373             # Write the a:bodyPr element.
4374 53         269 $self->_write_a_body_pr( $rotation, $is_y_axis );
4375              
4376             # Write the a:lstStyle element.
4377 53         262 $self->_write_a_lst_style();
4378              
4379             # Write the a:p element.
4380 53         254 $self->_write_a_p_rich( $title, $font );
4381              
4382 53         144 $self->xml_end_tag( 'c:rich' );
4383             }
4384              
4385              
4386             ##############################################################################
4387             #
4388             # _write_a_body_pr()
4389             #
4390             # Write the element.
4391             sub _write_a_body_pr {
4392              
4393 151     151   313 my $self = shift;
4394 151         301 my $rot = shift;
4395 151         260 my $is_y_axis = shift;
4396              
4397 151         322 my @attributes = ();
4398              
4399 151 100 100     913 if ( !defined $rot && $is_y_axis ) {
4400 18         41 $rot = -5400000;
4401             }
4402              
4403 151 100       462 if (defined $rot) {
4404 39 100       202 if ($rot == 16_200_000) {
    100          
4405             # 270 deg/stacked angle.
4406 4         19 push @attributes, ( 'rot' => 0 );
4407 4         7 push @attributes, ( 'vert' => 'wordArtVert' );
4408              
4409             }
4410             elsif ($rot == 16_260_000) {
4411             # 271 deg/East Asian vertical.
4412 4         8 push @attributes, ( 'rot' => 0 );
4413 4         11 push @attributes, ( 'vert' => 'eaVert' );
4414              
4415             }
4416             else {
4417 31         113 push @attributes, ( 'rot' => $rot );
4418 31         96 push @attributes, ( 'vert' => 'horz' );
4419             }
4420             }
4421              
4422 151         556 $self->xml_empty_tag( 'a:bodyPr', @attributes );
4423             }
4424              
4425              
4426             ##############################################################################
4427             #
4428             # _write_a_lst_style()
4429             #
4430             # Write the element.
4431             #
4432             sub _write_a_lst_style {
4433              
4434 151     151   309 my $self = shift;
4435              
4436 151         457 $self->xml_empty_tag( 'a:lstStyle' );
4437             }
4438              
4439              
4440             ##############################################################################
4441             #
4442             # _write_a_p_rich()
4443             #
4444             # Write the element for rich string titles.
4445             #
4446             sub _write_a_p_rich {
4447              
4448 53     53   96 my $self = shift;
4449 53         127 my $title = shift;
4450 53         88 my $font = shift;
4451              
4452 53         204 $self->xml_start_tag( 'a:p' );
4453              
4454             # Write the a:pPr element.
4455 53         270 $self->_write_a_p_pr_rich( $font );
4456              
4457             # Write the a:r element.
4458 53         276 $self->_write_a_r( $title, $font );
4459              
4460 53         143 $self->xml_end_tag( 'a:p' );
4461             }
4462              
4463              
4464             ##############################################################################
4465             #
4466             # _write_a_p_formula()
4467             #
4468             # Write the element for formula titles.
4469             #
4470             sub _write_a_p_formula {
4471              
4472 16     16   30 my $self = shift;
4473 16         46 my $font = shift;
4474              
4475 16         55 $self->xml_start_tag( 'a:p' );
4476              
4477             # Write the a:pPr element.
4478 16         83 $self->_write_a_p_pr_formula( $font );
4479              
4480             # Write the a:endParaRPr element.
4481 16         88 $self->_write_a_end_para_rpr();
4482              
4483 16         56 $self->xml_end_tag( 'a:p' );
4484             }
4485              
4486              
4487             ##############################################################################
4488             #
4489             # _write_a_p_pr_rich()
4490             #
4491             # Write the element for rich string titles.
4492             #
4493             sub _write_a_p_pr_rich {
4494              
4495 80     80   172 my $self = shift;
4496 80         147 my $font = shift;
4497              
4498 80         292 $self->xml_start_tag( 'a:pPr' );
4499              
4500             # Write the a:defRPr element.
4501 80         415 $self->_write_a_def_rpr( $font );
4502              
4503 80         338 $self->xml_end_tag( 'a:pPr' );
4504             }
4505              
4506              
4507             ##############################################################################
4508             #
4509             # _write_a_p_pr_formula()
4510             #
4511             # Write the element for formula titles.
4512             #
4513             sub _write_a_p_pr_formula {
4514              
4515 16     16   35 my $self = shift;
4516 16         25 my $font = shift;
4517              
4518 16         84 $self->xml_start_tag( 'a:pPr' );
4519              
4520             # Write the a:defRPr element.
4521 16         85 $self->_write_a_def_rpr( $font );
4522              
4523 16         65 $self->xml_end_tag( 'a:pPr' );
4524             }
4525              
4526              
4527             ##############################################################################
4528             #
4529             # _write_a_def_rpr()
4530             #
4531             # Write the element.
4532             #
4533             sub _write_a_def_rpr {
4534              
4535 151     151   354 my $self = shift;
4536 151         305 my $font = shift;
4537 151         269 my $has_color = 0;
4538              
4539 151         686 my @style_attributes = $self->_get_font_style_attributes( $font );
4540 151         700 my @latin_attributes = $self->_get_font_latin_attributes( $font );
4541              
4542 151 100 100     649 $has_color = 1 if $font && $font->{_color};
4543              
4544 151 100 100     899 if ( @latin_attributes || $has_color ) {
4545 10         63 $self->xml_start_tag( 'a:defRPr', @style_attributes );
4546              
4547              
4548 10 100       32 if ( $has_color ) {
4549 6         35 $self->_write_a_solid_fill( { color => $font->{_color} } );
4550             }
4551              
4552 10 100       38 if ( @latin_attributes ) {
4553 8         52 $self->_write_a_latin( @latin_attributes );
4554             }
4555              
4556 10         42 $self->xml_end_tag( 'a:defRPr' );
4557             }
4558             else {
4559 141         518 $self->xml_empty_tag( 'a:defRPr', @style_attributes );
4560             }
4561             }
4562              
4563              
4564             ##############################################################################
4565             #
4566             # _write_a_end_para_rpr()
4567             #
4568             # Write the element.
4569             #
4570             sub _write_a_end_para_rpr {
4571              
4572 98     98   210 my $self = shift;
4573 98         207 my $lang = 'en-US';
4574              
4575 98         317 my @attributes = ( 'lang' => $lang );
4576              
4577 98         307 $self->xml_empty_tag( 'a:endParaRPr', @attributes );
4578             }
4579              
4580              
4581             ##############################################################################
4582             #
4583             # _write_a_r()
4584             #
4585             # Write the element.
4586             #
4587             sub _write_a_r {
4588              
4589 53     53   134 my $self = shift;
4590 53         124 my $title = shift;
4591 53         89 my $font = shift;
4592              
4593 53         185 $self->xml_start_tag( 'a:r' );
4594              
4595             # Write the a:rPr element.
4596 53         274 $self->_write_a_r_pr( $font );
4597              
4598             # Write the a:t element.
4599 53         286 $self->_write_a_t( $title );
4600              
4601 53         177 $self->xml_end_tag( 'a:r' );
4602             }
4603              
4604              
4605             ##############################################################################
4606             #
4607             # _write_a_r_pr()
4608             #
4609             # Write the element.
4610             #
4611             sub _write_a_r_pr {
4612              
4613 53     53   107 my $self = shift;
4614 53         101 my $font = shift;
4615 53         105 my $has_color = 0;
4616 53         101 my $lang = 'en-US';
4617              
4618 53         141 my @style_attributes = $self->_get_font_style_attributes( $font );
4619 53         183 my @latin_attributes = $self->_get_font_latin_attributes( $font );
4620              
4621 53 100 100     212 $has_color = 1 if $font && $font->{_color};
4622              
4623             # Add the lang type to the attributes.
4624 53         159 @style_attributes = ( 'lang' => $lang, @style_attributes );
4625              
4626              
4627 53 100 66     277 if ( @latin_attributes || $has_color ) {
4628 3         12 $self->xml_start_tag( 'a:rPr', @style_attributes );
4629              
4630              
4631 3 50       13 if ( $has_color ) {
4632 3         15 $self->_write_a_solid_fill( { color => $font->{_color} } );
4633             }
4634              
4635 3 50       11 if ( @latin_attributes ) {
4636 3         11 $self->_write_a_latin( @latin_attributes );
4637             }
4638              
4639 3         10 $self->xml_end_tag( 'a:rPr' );
4640             }
4641             else {
4642 50         182 $self->xml_empty_tag( 'a:rPr', @style_attributes );
4643             }
4644              
4645              
4646             }
4647              
4648              
4649             ##############################################################################
4650             #
4651             # _write_a_t()
4652             #
4653             # Write the element.
4654             #
4655             sub _write_a_t {
4656              
4657 53     53   138 my $self = shift;
4658 53         105 my $title = shift;
4659              
4660 53         263 $self->xml_data_element( 'a:t', $title );
4661             }
4662              
4663              
4664             ##############################################################################
4665             #
4666             # _write_tx_pr()
4667             #
4668             # Write the element.
4669             #
4670             sub _write_tx_pr {
4671              
4672 16     16   34 my $self = shift;
4673 16         43 my $is_y_axis = shift;
4674 16         29 my $font = shift;
4675 16         40 my $rotation = undef;
4676              
4677 16 50 66     93 if ( $font && exists $font->{_rotation} ) {
4678 7         31 $rotation = $font->{_rotation};
4679             }
4680              
4681 16         55 $self->xml_start_tag( 'c:txPr' );
4682              
4683             # Write the a:bodyPr element.
4684 16         169 $self->_write_a_body_pr( $rotation, $is_y_axis );
4685              
4686             # Write the a:lstStyle element.
4687 16         92 $self->_write_a_lst_style();
4688              
4689             # Write the a:p element.
4690 16         73 $self->_write_a_p_formula( $font );
4691              
4692 16         49 $self->xml_end_tag( 'c:txPr' );
4693             }
4694              
4695              
4696             ##############################################################################
4697             #
4698             # _write_marker()
4699             #
4700             # Write the element.
4701             #
4702             sub _write_marker {
4703              
4704 939     939   1827 my $self = shift;
4705 939   100     4214 my $marker = shift || $self->{_default_marker};
4706              
4707 939 100       2757 return unless $marker;
4708 259 100       790 return if $marker->{automatic};
4709              
4710 253         961 $self->xml_start_tag( 'c:marker' );
4711              
4712             # Write the c:symbol element.
4713 253         1353 $self->_write_symbol( $marker->{type} );
4714              
4715             # Write the c:size element.
4716 253         556 my $size = $marker->{size};
4717 253 100       825 $self->_write_marker_size( $size ) if $size;
4718              
4719             # Write the c:spPr element.
4720 253         819 $self->_write_sp_pr( $marker );
4721              
4722 253         1047 $self->xml_end_tag( 'c:marker' );
4723             }
4724              
4725              
4726             ##############################################################################
4727             #
4728             # _write_marker_size()
4729             #
4730             # Write the element.
4731             #
4732             sub _write_marker_size {
4733              
4734 17     17   95 my $self = shift;
4735 17         41 my $val = shift;
4736              
4737 17         66 my @attributes = ( 'val' => $val );
4738              
4739 17         63 $self->xml_empty_tag( 'c:size', @attributes );
4740             }
4741              
4742              
4743             ##############################################################################
4744             #
4745             # _write_symbol()
4746             #
4747             # Write the element.
4748             #
4749             sub _write_symbol {
4750              
4751 254     254   486 my $self = shift;
4752 254         478 my $val = shift;
4753              
4754 254         707 my @attributes = ( 'val' => $val );
4755              
4756 254         755 $self->xml_empty_tag( 'c:symbol', @attributes );
4757             }
4758              
4759              
4760             ##############################################################################
4761             #
4762             # _write_sp_pr()
4763             #
4764             # Write the element.
4765             #
4766             sub _write_sp_pr {
4767              
4768 3133     3133   5669 my $self = shift;
4769 3133         4576 my $series = shift;
4770              
4771 3133 100 100     24003 if ( !$series->{_line}->{_defined}
      100        
      100        
4772             and !$series->{_fill}->{_defined}
4773             and !$series->{_pattern}
4774             and !$series->{_gradient} )
4775             {
4776 2912         5804 return;
4777             }
4778              
4779 221         822 $self->xml_start_tag( 'c:spPr' );
4780              
4781             # Write the fill elements for solid charts such as pie/doughnut and bar.
4782 221 100       769 if ( $series->{_fill}->{_defined} ) {
4783              
4784 46 100       192 if ( $series->{_fill}->{none} ) {
4785              
4786             # Write the a:noFill element.
4787 6         24 $self->_write_a_no_fill();
4788             }
4789             else {
4790             # Write the a:solidFill element.
4791 40         227 $self->_write_a_solid_fill( $series->{_fill} );
4792             }
4793             }
4794              
4795 221 100       878 if ( $series->{_pattern} ) {
4796              
4797             # Write the a:pattFill element.
4798 58         176 $self->_write_a_patt_fill( $series->{_pattern} );
4799             }
4800              
4801 221 100       725 if ( $series->{_gradient} ) {
4802              
4803             # Write the a:gradFill element.
4804 13         116 $self->_write_a_grad_fill( $series->{_gradient} );
4805             }
4806              
4807              
4808             # Write the a:ln element.
4809 221 100       789 if ( $series->{_line}->{_defined} ) {
4810 127         790 $self->_write_a_ln( $series->{_line} );
4811             }
4812              
4813 221         824 $self->xml_end_tag( 'c:spPr' );
4814             }
4815              
4816              
4817             ##############################################################################
4818             #
4819             # _write_a_ln()
4820             #
4821             # Write the element.
4822             #
4823             sub _write_a_ln {
4824              
4825 127     127   283 my $self = shift;
4826 127         254 my $line = shift;
4827 127         287 my @attributes = ();
4828              
4829             # Add the line width as an attribute.
4830 127 100       484 if ( my $width = $line->{width} ) {
4831              
4832             # Round width to nearest 0.25, like Excel.
4833 89         369 $width = int( ( $width + 0.125 ) * 4 ) / 4;
4834              
4835             # Convert to internal units.
4836 89         241 $width = int( 0.5 + ( 12700 * $width ) );
4837              
4838 89         240 @attributes = ( 'w' => $width );
4839             }
4840              
4841 127         493 $self->xml_start_tag( 'a:ln', @attributes );
4842              
4843             # Write the line fill.
4844 127 100       588 if ( $line->{none} ) {
    100          
4845              
4846             # Write the a:noFill element.
4847 86         378 $self->_write_a_no_fill();
4848             }
4849             elsif ( $line->{color} ) {
4850              
4851             # Write the a:solidFill element.
4852 35         207 $self->_write_a_solid_fill( $line );
4853             }
4854              
4855             # Write the line/dash type.
4856 127 100       492 if ( my $type = $line->{dash_type} ) {
4857              
4858             # Write the a:prstDash element.
4859 25         188 $self->_write_a_prst_dash( $type );
4860             }
4861              
4862 127         568 $self->xml_end_tag( 'a:ln' );
4863             }
4864              
4865              
4866             ##############################################################################
4867             #
4868             # _write_a_no_fill()
4869             #
4870             # Write the element.
4871             #
4872             sub _write_a_no_fill {
4873              
4874 92     92   196 my $self = shift;
4875              
4876 92         273 $self->xml_empty_tag( 'a:noFill' );
4877             }
4878              
4879              
4880             ##############################################################################
4881             #
4882             # _write_a_solid_fill()
4883             #
4884             # Write the element.
4885             #
4886             sub _write_a_solid_fill {
4887              
4888 84     84   212 my $self = shift;
4889 84         161 my $fill = shift;
4890              
4891 84         431 $self->xml_start_tag( 'a:solidFill' );
4892              
4893 84 50       285 if ( $fill->{color} ) {
4894              
4895 84         413 my $color = $self->_get_color( $fill->{color} );
4896              
4897             # Write the a:srgbClr element.
4898 84         485 $self->_write_a_srgb_clr( $color, $fill->{transparency} );
4899             }
4900              
4901 84         392 $self->xml_end_tag( 'a:solidFill' );
4902             }
4903              
4904              
4905             ##############################################################################
4906             #
4907             # _write_a_srgb_clr()
4908             #
4909             # Write the element.
4910             #
4911             sub _write_a_srgb_clr {
4912              
4913 238     238   472 my $self = shift;
4914 238         407 my $color = shift;
4915 238         436 my $transparency = shift;
4916              
4917 238         592 my @attributes = ( 'val' => $color );
4918              
4919 238 100       596 if ( $transparency ) {
4920 6         33 $self->xml_start_tag( 'a:srgbClr', @attributes );
4921              
4922             # Write the a:alpha element.
4923 6         50 $self->_write_a_alpha( $transparency );
4924              
4925 6         31 $self->xml_end_tag( 'a:srgbClr' );
4926             }
4927             else {
4928 232         640 $self->xml_empty_tag( 'a:srgbClr', @attributes );
4929             }
4930             }
4931              
4932              
4933             ##############################################################################
4934             #
4935             # _write_a_alpha()
4936             #
4937             # Write the element.
4938             #
4939             sub _write_a_alpha {
4940              
4941 6     6   20 my $self = shift;
4942 6         12 my $val = shift;
4943              
4944 6         54 $val = ( 100 - int( $val ) ) * 1000;
4945              
4946 6         21 my @attributes = ( 'val' => $val );
4947              
4948 6         26 $self->xml_empty_tag( 'a:alpha', @attributes );
4949             }
4950              
4951              
4952             ##############################################################################
4953             #
4954             # _write_a_prst_dash()
4955             #
4956             # Write the element.
4957             #
4958             sub _write_a_prst_dash {
4959              
4960 25     25   102 my $self = shift;
4961 25         56 my $val = shift;
4962              
4963 25         83 my @attributes = ( 'val' => $val );
4964              
4965 25         87 $self->xml_empty_tag( 'a:prstDash', @attributes );
4966             }
4967              
4968              
4969             ##############################################################################
4970             #
4971             # _write_trendline()
4972             #
4973             # Write the element.
4974             #
4975             sub _write_trendline {
4976              
4977 938     938   1743 my $self = shift;
4978 938         1648 my $trendline = shift;
4979              
4980 938 100       2510 return unless $trendline;
4981              
4982 13         57 $self->xml_start_tag( 'c:trendline' );
4983              
4984             # Write the c:name element.
4985 13         94 $self->_write_name( $trendline->{name} );
4986              
4987             # Write the c:spPr element.
4988 13         53 $self->_write_sp_pr( $trendline );
4989              
4990             # Write the c:trendlineType element.
4991 13         80 $self->_write_trendline_type( $trendline->{type} );
4992              
4993             # Write the c:order element for polynomial trendlines.
4994 13 100       66 if ( $trendline->{type} eq 'poly' ) {
4995 4         23 $self->_write_trendline_order( $trendline->{order} );
4996             }
4997              
4998             # Write the c:period element for moving average trendlines.
4999 13 100       57 if ( $trendline->{type} eq 'movingAvg' ) {
5000 1         6 $self->_write_period( $trendline->{period} );
5001             }
5002              
5003             # Write the c:forward element.
5004 13         156 $self->_write_forward( $trendline->{forward} );
5005              
5006             # Write the c:backward element.
5007 13         131 $self->_write_backward( $trendline->{backward} );
5008              
5009 13 100       61 if ( defined $trendline->{intercept} ) {
5010             # Write the c:intercept element.
5011 2         10 $self->_write_intercept( $trendline->{intercept} );
5012             }
5013              
5014 13 100       48 if ($trendline->{display_r_squared}) {
5015             # Write the c:dispRSqr element.
5016 4         22 $self->_write_disp_rsqr();
5017             }
5018              
5019 13 100       58 if ($trendline->{display_equation}) {
5020             # Write the c:dispEq element.
5021 6         87 $self->_write_disp_eq();
5022              
5023             # Write the c:trendlineLbl element.
5024 6         48 $self->_write_trendline_lbl();
5025             }
5026              
5027 13         45 $self->xml_end_tag( 'c:trendline' );
5028             }
5029              
5030              
5031             ##############################################################################
5032             #
5033             # _write_trendline_type()
5034             #
5035             # Write the element.
5036             #
5037             sub _write_trendline_type {
5038              
5039 13     13   37 my $self = shift;
5040 13         44 my $val = shift;
5041              
5042 13         45 my @attributes = ( 'val' => $val );
5043              
5044 13         64 $self->xml_empty_tag( 'c:trendlineType', @attributes );
5045             }
5046              
5047              
5048             ##############################################################################
5049             #
5050             # _write_name()
5051             #
5052             # Write the element.
5053             #
5054             sub _write_name {
5055              
5056 13     13   38 my $self = shift;
5057 13         32 my $data = shift;
5058              
5059 13 100       50 return unless defined $data;
5060              
5061 4         27 $self->xml_data_element( 'c:name', $data );
5062             }
5063              
5064              
5065             ##############################################################################
5066             #
5067             # _write_trendline_order()
5068             #
5069             # Write the element.
5070             #
5071             sub _write_trendline_order {
5072              
5073 4     4   18 my $self = shift;
5074 4 50       17 my $val = defined $_[0] ? $_[0] : 2;
5075              
5076 4         12 my @attributes = ( 'val' => $val );
5077              
5078 4         13 $self->xml_empty_tag( 'c:order', @attributes );
5079             }
5080              
5081              
5082             ##############################################################################
5083             #
5084             # _write_period()
5085             #
5086             # Write the element.
5087             #
5088             sub _write_period {
5089              
5090 1     1   2 my $self = shift;
5091 1 50       3 my $val = defined $_[0] ? $_[0] : 2;
5092              
5093 1         3 my @attributes = ( 'val' => $val );
5094              
5095 1         12 $self->xml_empty_tag( 'c:period', @attributes );
5096             }
5097              
5098              
5099             ##############################################################################
5100             #
5101             # _write_forward()
5102             #
5103             # Write the element.
5104             #
5105             sub _write_forward {
5106              
5107 13     13   36 my $self = shift;
5108 13         32 my $val = shift;
5109              
5110 13 100       61 return unless $val;
5111              
5112 4         20 my @attributes = ( 'val' => $val );
5113              
5114 4         46 $self->xml_empty_tag( 'c:forward', @attributes );
5115             }
5116              
5117              
5118             ##############################################################################
5119             #
5120             # _write_backward()
5121             #
5122             # Write the element.
5123             #
5124             sub _write_backward {
5125              
5126 13     13   33 my $self = shift;
5127 13         31 my $val = shift;
5128              
5129 13 100       48 return unless $val;
5130              
5131 4         11 my @attributes = ( 'val' => $val );
5132              
5133 4         15 $self->xml_empty_tag( 'c:backward', @attributes );
5134             }
5135              
5136              
5137             ##############################################################################
5138             #
5139             # _write_intercept()
5140             #
5141             # Write the element.
5142             #
5143             sub _write_intercept {
5144              
5145 2     2   4 my $self = shift;
5146 2         4 my $val = shift;
5147              
5148 2         6 my @attributes = ( 'val' => $val );
5149              
5150 2         6 $self->xml_empty_tag( 'c:intercept', @attributes );
5151             }
5152              
5153              
5154             ##############################################################################
5155             #
5156             # _write_disp_eq()
5157             #
5158             # Write the element.
5159             #
5160             sub _write_disp_eq {
5161              
5162 6     6   17 my $self = shift;
5163              
5164 6         19 my @attributes = ( 'val' => 1 );
5165              
5166 6         23 $self->xml_empty_tag( 'c:dispEq', @attributes );
5167             }
5168              
5169              
5170             ##############################################################################
5171             #
5172             # _write_disp_rsqr()
5173             #
5174             # Write the element.
5175             #
5176             sub _write_disp_rsqr {
5177              
5178 4     4   10 my $self = shift;
5179              
5180 4         12 my @attributes = ( 'val' => 1 );
5181              
5182 4         15 $self->xml_empty_tag( 'c:dispRSqr', @attributes );
5183             }
5184              
5185             ##############################################################################
5186             #
5187             # _write_trendline_lbl()
5188             #
5189             # Write the element.
5190             #
5191             sub _write_trendline_lbl {
5192              
5193 6     6   23 my $self = shift;
5194              
5195 6         25 $self->xml_start_tag( 'c:trendlineLbl' );
5196              
5197             # Write the c:layout element.
5198 6         23 $self->_write_layout();
5199              
5200             # Write the c:numFmt element.
5201 6         58 $self->_write_trendline_num_fmt();
5202              
5203 6         22 $self->xml_end_tag( 'c:trendlineLbl' );
5204             }
5205              
5206             ##############################################################################
5207             #
5208             # _write_trendline_num_fmt()
5209             #
5210             # Write the element.
5211             #
5212             sub _write_trendline_num_fmt {
5213              
5214 6     6   15 my $self = shift;
5215 6         12 my $format_code = 'General';
5216 6         13 my $source_linked = 0;
5217              
5218 6         19 my @attributes = (
5219             'formatCode' => $format_code,
5220             'sourceLinked' => $source_linked,
5221             );
5222              
5223 6         28 $self->xml_empty_tag( 'c:numFmt', @attributes );
5224             }
5225              
5226             ##############################################################################
5227             #
5228             # _write_hi_low_lines()
5229             #
5230             # Write the element.
5231             #
5232             sub _write_hi_low_lines {
5233              
5234 100     100   279 my $self = shift;
5235              
5236 100         374 my $hi_low_lines = $self->{_hi_low_lines};
5237              
5238 100 100       504 return unless $hi_low_lines;
5239              
5240 14 100       77 if ( $hi_low_lines->{_line}->{_defined} ) {
5241              
5242 1         3 $self->xml_start_tag( 'c:hiLowLines' );
5243              
5244             # Write the c:spPr element.
5245 1         4 $self->_write_sp_pr( $hi_low_lines );
5246              
5247 1         2 $self->xml_end_tag( 'c:hiLowLines' );
5248             }
5249             else {
5250 13         62 $self->xml_empty_tag( 'c:hiLowLines' );
5251             }
5252             }
5253              
5254              
5255             #############################################################################
5256             #
5257             # _write_drop_lines()
5258             #
5259             # Write the element.
5260             #
5261             sub _write_drop_lines {
5262              
5263 112     112   326 my $self = shift;
5264              
5265 112         342 my $drop_lines = $self->{_drop_lines};
5266              
5267 112 100       577 return unless $drop_lines;
5268              
5269 4 100       16 if ( $drop_lines->{_line}->{_defined} ) {
5270              
5271 1         3 $self->xml_start_tag( 'c:dropLines' );
5272              
5273             # Write the c:spPr element.
5274 1         4 $self->_write_sp_pr( $drop_lines );
5275              
5276 1         3 $self->xml_end_tag( 'c:dropLines' );
5277             }
5278             else {
5279 3         12 $self->xml_empty_tag( 'c:dropLines' );
5280             }
5281             }
5282              
5283              
5284             ##############################################################################
5285             #
5286             # _write_overlap()
5287             #
5288             # Write the element.
5289             #
5290             sub _write_overlap {
5291              
5292 202     202   556 my $self = shift;
5293 202         590 my $val = shift;
5294              
5295 202 100       906 return if !defined $val;
5296              
5297 12         37 my @attributes = ( 'val' => $val );
5298              
5299 12         50 $self->xml_empty_tag( 'c:overlap', @attributes );
5300             }
5301              
5302              
5303             ##############################################################################
5304             #
5305             # _write_num_cache()
5306             #
5307             # Write the element.
5308             #
5309             sub _write_num_cache {
5310              
5311 1184     1184   2234 my $self = shift;
5312 1184         2418 my $data = shift;
5313 1184         1970 my $count = 0;
5314              
5315 1184 50       3170 if (defined $data) {
5316 1184         2653 $count = @$data;
5317             }
5318              
5319 1184         3746 $self->xml_start_tag( 'c:numCache' );
5320              
5321             # Write the c:formatCode element.
5322 1184         4995 $self->_write_format_code( 'General' );
5323              
5324             # Write the c:ptCount element.
5325 1184         4701 $self->_write_pt_count( $count );
5326              
5327 1184         4277 for my $i ( 0 .. $count - 1 ) {
5328 5718         10283 my $token = $data->[$i];
5329              
5330             # Write non-numeric data as 0.
5331 5718 100 100     36797 if ( defined $token
5332             && $token !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ )
5333             {
5334 3         10 $token = 0;
5335             }
5336              
5337             # Write the c:pt element.
5338 5718         13922 $self->_write_pt( $i, $token );
5339             }
5340              
5341 1184         3322 $self->xml_end_tag( 'c:numCache' );
5342             }
5343              
5344              
5345             ##############################################################################
5346             #
5347             # _write_str_cache()
5348             #
5349             # Write the element.
5350             #
5351             sub _write_str_cache {
5352              
5353 33     33   60 my $self = shift;
5354 33         69 my $data = shift;
5355 33         75 my $count = @$data;
5356              
5357 33         117 $self->xml_start_tag( 'c:strCache' );
5358              
5359             # Write the c:ptCount element.
5360 33         163 $self->_write_pt_count( $count );
5361              
5362 33         130 for my $i ( 0 .. $count - 1 ) {
5363              
5364             # Write the c:pt element.
5365 63         202 $self->_write_pt( $i, $data->[$i] );
5366             }
5367              
5368 33         100 $self->xml_end_tag( 'c:strCache' );
5369             }
5370              
5371              
5372             ##############################################################################
5373             #
5374             # _write_format_code()
5375             #
5376             # Write the element.
5377             #
5378             sub _write_format_code {
5379              
5380 1189     1189   2269 my $self = shift;
5381 1189         2097 my $data = shift;
5382              
5383 1189         3210 $self->xml_data_element( 'c:formatCode', $data );
5384             }
5385              
5386              
5387             ##############################################################################
5388             #
5389             # _write_pt_count()
5390             #
5391             # Write the element.
5392             #
5393             sub _write_pt_count {
5394              
5395 1225     1225   2274 my $self = shift;
5396 1225         2024 my $val = shift;
5397              
5398 1225         2971 my @attributes = ( 'val' => $val );
5399              
5400 1225         3445 $self->xml_empty_tag( 'c:ptCount', @attributes );
5401             }
5402              
5403              
5404             ##############################################################################
5405             #
5406             # _write_pt()
5407             #
5408             # Write the element.
5409             #
5410             sub _write_pt {
5411              
5412 5820     5820   8995 my $self = shift;
5413 5820         7952 my $idx = shift;
5414 5820         8157 my $value = shift;
5415              
5416 5820 100       11108 return if !defined $value;
5417              
5418 5802         11118 my @attributes = ( 'idx' => $idx );
5419              
5420 5802         15137 $self->xml_start_tag( 'c:pt', @attributes );
5421              
5422             # Write the c:v element.
5423 5802         16172 $self->_write_v( $value );
5424              
5425 5802         13847 $self->xml_end_tag( 'c:pt' );
5426             }
5427              
5428              
5429             ##############################################################################
5430             #
5431             # _write_v()
5432             #
5433             # Write the element.
5434             #
5435             sub _write_v {
5436              
5437 5805     5805   8597 my $self = shift;
5438 5805         8378 my $data = shift;
5439              
5440 5805         11905 $self->xml_data_element( 'c:v', $data );
5441             }
5442              
5443              
5444             ##############################################################################
5445             #
5446             # _write_protection()
5447             #
5448             # Write the element.
5449             #
5450             sub _write_protection {
5451              
5452 394     394   1006 my $self = shift;
5453              
5454 394 100       1738 return unless $self->{_protection};
5455              
5456 1         4 $self->xml_empty_tag( 'c:protection' );
5457             }
5458              
5459              
5460             ##############################################################################
5461             #
5462             # _write_d_pt()
5463             #
5464             # Write the elements.
5465             #
5466             sub _write_d_pt {
5467              
5468 938     938   1713 my $self = shift;
5469 938         1578 my $points = shift;
5470 938         1633 my $index = -1;
5471              
5472 938 100       2473 return unless $points;
5473              
5474 9         30 for my $point ( @$points ) {
5475              
5476 22         41 $index++;
5477 22 100       46 next unless $point;
5478              
5479 18         85 $self->_write_d_pt_point( $index, $point );
5480             }
5481             }
5482              
5483              
5484             ##############################################################################
5485             #
5486             # _write_d_pt_point()
5487             #
5488             # Write an individual element.
5489             #
5490             sub _write_d_pt_point {
5491              
5492 14     14   27 my $self = shift;
5493 14         23 my $index = shift;
5494 14         19 my $point = shift;
5495              
5496 14         45 $self->xml_start_tag( 'c:dPt' );
5497              
5498             # Write the c:idx element.
5499 14         54 $self->_write_idx( $index );
5500              
5501             # Write the c:spPr element.
5502 14         42 $self->_write_sp_pr( $point );
5503              
5504 14         36 $self->xml_end_tag( 'c:dPt' );
5505              
5506             }
5507              
5508              
5509             ##############################################################################
5510             #
5511             # _write_d_lbls()
5512             #
5513             # Write the element.
5514             #
5515             sub _write_d_lbls {
5516              
5517 956     956   1865 my $self = shift;
5518 956         1601 my $labels = shift;
5519              
5520 956 100       2519 return unless $labels;
5521              
5522 65         252 $self->xml_start_tag( 'c:dLbls' );
5523              
5524             # Write the c:numFmt element.
5525 65 100       271 if ( $labels->{num_format} ) {
5526 3         14 $self->_write_data_label_number_format( $labels->{num_format} );
5527             }
5528              
5529             # Write the data label font elements.
5530 65 100       204 if ($labels->{font} ) {
5531 5         30 $self->_write_axis_font( $labels->{font} );
5532             }
5533              
5534             # Write the c:dLblPos element.
5535 65 100       346 $self->_write_d_lbl_pos( $labels->{position} ) if $labels->{position};
5536              
5537             # Write the c:showLegendKey element.
5538 65 100       248 $self->_write_show_legend_key() if $labels->{legend_key};
5539              
5540             # Write the c:showVal element.
5541 65 100       433 $self->_write_show_val() if $labels->{value};
5542              
5543             # Write the c:showCatName element.
5544 65 100       278 $self->_write_show_cat_name() if $labels->{category};
5545              
5546             # Write the c:showSerName element.
5547 65 100       250 $self->_write_show_ser_name() if $labels->{series_name};
5548              
5549             # Write the c:showPercent element.
5550 65 100       214 $self->_write_show_percent() if $labels->{percentage};
5551              
5552             # Write the c:separator element.
5553 65 100       200 $self->_write_separator($labels->{separator}) if $labels->{separator};
5554              
5555             # Write the c:showLeaderLines element.
5556 65 100       238 $self->_write_show_leader_lines() if $labels->{leader_lines};
5557              
5558 65         252 $self->xml_end_tag( 'c:dLbls' );
5559             }
5560              
5561             ##############################################################################
5562             #
5563             # _write_show_legend_key()
5564             #
5565             # Write the element.
5566             #
5567             sub _write_show_legend_key {
5568              
5569 2     2   4 my $self = shift;
5570 2         4 my $val = 1;
5571              
5572 2         6 my @attributes = ( 'val' => $val );
5573              
5574 2         6 $self->xml_empty_tag( 'c:showLegendKey', @attributes );
5575             }
5576              
5577             ##############################################################################
5578             #
5579             # _write_show_val()
5580             #
5581             # Write the element.
5582             #
5583             sub _write_show_val {
5584              
5585 62     62   123 my $self = shift;
5586 62         132 my $val = 1;
5587              
5588 62         160 my @attributes = ( 'val' => $val );
5589              
5590 62         209 $self->xml_empty_tag( 'c:showVal', @attributes );
5591             }
5592              
5593              
5594             ##############################################################################
5595             #
5596             # _write_show_cat_name()
5597             #
5598             # Write the element.
5599             #
5600             sub _write_show_cat_name {
5601              
5602 11     11   29 my $self = shift;
5603 11         27 my $val = 1;
5604              
5605 11         33 my @attributes = ( 'val' => $val );
5606              
5607 11         37 $self->xml_empty_tag( 'c:showCatName', @attributes );
5608             }
5609              
5610              
5611             ##############################################################################
5612             #
5613             # _write_show_ser_name()
5614             #
5615             # Write the element.
5616             #
5617             sub _write_show_ser_name {
5618              
5619 5     5   12 my $self = shift;
5620 5         9 my $val = 1;
5621              
5622 5         14 my @attributes = ( 'val' => $val );
5623              
5624 5         16 $self->xml_empty_tag( 'c:showSerName', @attributes );
5625             }
5626              
5627              
5628             ##############################################################################
5629             #
5630             # _write_show_percent()
5631             #
5632             # Write the element.
5633             #
5634             sub _write_show_percent {
5635              
5636 2     2   13 my $self = shift;
5637 2         5 my $val = 1;
5638              
5639 2         7 my @attributes = ( 'val' => $val );
5640              
5641 2         9 $self->xml_empty_tag( 'c:showPercent', @attributes );
5642             }
5643              
5644             ##############################################################################
5645             #
5646             # _write_separator()
5647             #
5648             # Write the element.
5649             #
5650             sub _write_separator {
5651              
5652 5     5   10 my $self = shift;
5653 5         8 my $data = shift;
5654              
5655 5         26 $self->xml_data_element( 'c:separator', $data );
5656             }
5657              
5658             ##############################################################################
5659             #
5660             # _write_show_leader_lines()
5661             #
5662             # Write the element.
5663             #
5664             sub _write_show_leader_lines {
5665              
5666 13     13   25 my $self = shift;
5667 13         26 my $val = 1;
5668              
5669 13         35 my @attributes = ( 'val' => $val );
5670              
5671 13         41 $self->xml_empty_tag( 'c:showLeaderLines', @attributes );
5672             }
5673              
5674              
5675             ##############################################################################
5676             #
5677             # _write_d_lbl_pos()
5678             #
5679             # Write the element.
5680             #
5681             sub _write_d_lbl_pos {
5682              
5683 35     35   72 my $self = shift;
5684 35         79 my $val = shift;
5685              
5686 35         103 my @attributes = ( 'val' => $val );
5687              
5688 35         125 $self->xml_empty_tag( 'c:dLblPos', @attributes );
5689             }
5690              
5691              
5692             ##############################################################################
5693             #
5694             # _write_delete()
5695             #
5696             # Write the element.
5697             #
5698             sub _write_delete {
5699              
5700 21     21   63 my $self = shift;
5701 21         42 my $val = shift;
5702              
5703 21         84 my @attributes = ( 'val' => $val );
5704              
5705 21         69 $self->xml_empty_tag( 'c:delete', @attributes );
5706             }
5707              
5708              
5709             ##############################################################################
5710             #
5711             # _write_c_invert_if_negative()
5712             #
5713             # Write the element.
5714             #
5715             sub _write_c_invert_if_negative {
5716              
5717 876     876   1608 my $self = shift;
5718 876         1642 my $invert = shift;
5719 876         1563 my $val = 1;
5720              
5721 876 100       2442 return unless $invert;
5722              
5723 2         7 my @attributes = ( 'val' => $val );
5724              
5725 2         10 $self->xml_empty_tag( 'c:invertIfNegative', @attributes );
5726             }
5727              
5728              
5729             ##############################################################################
5730             #
5731             # _write_axis_font()
5732             #
5733             # Write the axis font elements.
5734             #
5735             sub _write_axis_font {
5736              
5737 705     705   1412 my $self = shift;
5738 705         1251 my $font = shift;
5739              
5740 705 100       1988 return unless $font;
5741              
5742 27         130 $self->xml_start_tag( 'c:txPr' );
5743 27         144 $self->_write_a_body_pr($font->{_rotation});
5744 27         130 $self->_write_a_lst_style();
5745 27         115 $self->xml_start_tag( 'a:p' );
5746              
5747 27         142 $self->_write_a_p_pr_rich( $font );
5748              
5749 27         177 $self->_write_a_end_para_rpr();
5750 27         108 $self->xml_end_tag( 'a:p' );
5751 27         82 $self->xml_end_tag( 'c:txPr' );
5752             }
5753              
5754              
5755             ##############################################################################
5756             #
5757             # _write_a_latin()
5758             #
5759             # Write the element.
5760             #
5761             sub _write_a_latin {
5762              
5763 12     12   38 my $self = shift;
5764 12         38 my @attributes = @_;
5765              
5766 12         60 $self->xml_empty_tag( 'a:latin', @attributes );
5767             }
5768              
5769              
5770             ##############################################################################
5771             #
5772             # _write_d_table()
5773             #
5774             # Write the element.
5775             #
5776             sub _write_d_table {
5777              
5778 307     307   917 my $self = shift;
5779 307         936 my $table = $self->{_table};
5780              
5781 307 100       1237 return if !$table;
5782              
5783 3         22 $self->xml_start_tag( 'c:dTable' );
5784              
5785 3 100       15 if ( $table->{_horizontal} ) {
5786              
5787             # Write the c:showHorzBorder element.
5788 1         27 $self->_write_show_horz_border();
5789             }
5790              
5791 3 100       25 if ( $table->{_vertical} ) {
5792              
5793             # Write the c:showVertBorder element.
5794 1         7 $self->_write_show_vert_border();
5795             }
5796              
5797 3 100       25 if ( $table->{_outline} ) {
5798              
5799             # Write the c:showOutline element.
5800 1         10 $self->_write_show_outline();
5801             }
5802              
5803 3 100       13 if ( $table->{_show_keys} ) {
5804              
5805             # Write the c:showKeys element.
5806 2         16 $self->_write_show_keys();
5807             }
5808              
5809 3 100       13 if ( $table->{_font} ) {
5810             # Write the table font.
5811 1         7 $self->_write_tx_pr( undef, $table->{_font} );
5812             }
5813              
5814 3         11 $self->xml_end_tag( 'c:dTable' );
5815             }
5816              
5817              
5818             ##############################################################################
5819             #
5820             # _write_show_horz_border()
5821             #
5822             # Write the element.
5823             #
5824             sub _write_show_horz_border {
5825              
5826 1     1   4 my $self = shift;
5827              
5828 1         3 my @attributes = ( 'val' => 1 );
5829              
5830 1         5 $self->xml_empty_tag( 'c:showHorzBorder', @attributes );
5831             }
5832              
5833             ##############################################################################
5834             #
5835             # _write_show_vert_border()
5836             #
5837             # Write the element.
5838             #
5839             sub _write_show_vert_border {
5840              
5841 1     1   2 my $self = shift;
5842              
5843 1         3 my @attributes = ( 'val' => 1 );
5844              
5845 1         4 $self->xml_empty_tag( 'c:showVertBorder', @attributes );
5846             }
5847              
5848              
5849             ##############################################################################
5850             #
5851             # _write_show_outline()
5852             #
5853             # Write the element.
5854             #
5855             sub _write_show_outline {
5856              
5857 1     1   3 my $self = shift;
5858              
5859 1         2 my @attributes = ( 'val' => 1 );
5860              
5861 1         4 $self->xml_empty_tag( 'c:showOutline', @attributes );
5862             }
5863              
5864              
5865             ##############################################################################
5866             #
5867             # _write_show_keys()
5868             #
5869             # Write the element.
5870             #
5871             sub _write_show_keys {
5872              
5873 2     2   4 my $self = shift;
5874              
5875 2         7 my @attributes = ( 'val' => 1 );
5876              
5877 2         7 $self->xml_empty_tag( 'c:showKeys', @attributes );
5878             }
5879              
5880              
5881             ##############################################################################
5882             #
5883             # _write_error_bars()
5884             #
5885             # Write the X and Y error bars.
5886             #
5887             sub _write_error_bars {
5888              
5889 938     938   1837 my $self = shift;
5890 938         1782 my $error_bars = shift;
5891              
5892 938 50       2606 return unless $error_bars;
5893              
5894 938 100       2796 if ( $error_bars->{_x_error_bars} ) {
5895 2         12 $self->_write_err_bars( 'x', $error_bars->{_x_error_bars} );
5896             }
5897              
5898 938 100       2873 if ( $error_bars->{_y_error_bars} ) {
5899 12         66 $self->_write_err_bars( 'y', $error_bars->{_y_error_bars} );
5900             }
5901              
5902             }
5903              
5904              
5905             ##############################################################################
5906             #
5907             # _write_err_bars()
5908             #
5909             # Write the element.
5910             #
5911             sub _write_err_bars {
5912              
5913 14     14   29 my $self = shift;
5914 14         28 my $direction = shift;
5915 14         24 my $error_bars = shift;
5916              
5917 14 50       38 return unless $error_bars;
5918              
5919 14         72 $self->xml_start_tag( 'c:errBars' );
5920              
5921             # Write the c:errDir element.
5922 14         108 $self->_write_err_dir( $direction );
5923              
5924             # Write the c:errBarType element.
5925 14         107 $self->_write_err_bar_type( $error_bars->{_direction} );
5926              
5927             # Write the c:errValType element.
5928 14         88 $self->_write_err_val_type( $error_bars->{_type} );
5929              
5930 14 100       64 if ( !$error_bars->{_endcap} ) {
5931              
5932             # Write the c:noEndCap element.
5933 1         5 $self->_write_no_end_cap();
5934             }
5935              
5936 14 100       80 if ( $error_bars->{_type} eq 'stdErr' ) {
    100          
5937              
5938             # Don't need to write a c:errValType tag.
5939             }
5940             elsif ( $error_bars->{_type} eq 'cust' ) {
5941              
5942             # Write the custom error tags.
5943 3         17 $self->_write_custom_error( $error_bars );
5944             }
5945             else {
5946             # Write the c:val element.
5947 3         13 $self->_write_error_val( $error_bars->{_value} );
5948             }
5949              
5950             # Write the c:spPr element.
5951 14         59 $self->_write_sp_pr( $error_bars );
5952              
5953 14         58 $self->xml_end_tag( 'c:errBars' );
5954             }
5955              
5956              
5957             ##############################################################################
5958             #
5959             # _write_err_dir()
5960             #
5961             # Write the element.
5962             #
5963             sub _write_err_dir {
5964              
5965 12     12   28 my $self = shift;
5966 12         21 my $val = shift;
5967              
5968 12         40 my @attributes = ( 'val' => $val );
5969              
5970 12         45 $self->xml_empty_tag( 'c:errDir', @attributes );
5971             }
5972              
5973              
5974             ##############################################################################
5975             #
5976             # _write_err_bar_type()
5977             #
5978             # Write the element.
5979             #
5980             sub _write_err_bar_type {
5981              
5982 14     14   31 my $self = shift;
5983 14         28 my $val = shift;
5984              
5985 14         37 my @attributes = ( 'val' => $val );
5986              
5987 14         47 $self->xml_empty_tag( 'c:errBarType', @attributes );
5988             }
5989              
5990              
5991             ##############################################################################
5992             #
5993             # _write_err_val_type()
5994             #
5995             # Write the element.
5996             #
5997             sub _write_err_val_type {
5998              
5999 14     14   26 my $self = shift;
6000 14         28 my $val = shift;
6001              
6002 14         38 my @attributes = ( 'val' => $val );
6003              
6004 14         51 $self->xml_empty_tag( 'c:errValType', @attributes );
6005             }
6006              
6007              
6008             ##############################################################################
6009             #
6010             # _write_no_end_cap()
6011             #
6012             # Write the element.
6013             #
6014             sub _write_no_end_cap {
6015              
6016 1     1   2 my $self = shift;
6017              
6018 1         3 my @attributes = ( 'val' => 1 );
6019              
6020 1         3 $self->xml_empty_tag( 'c:noEndCap', @attributes );
6021             }
6022              
6023              
6024             ##############################################################################
6025             #
6026             # _write_error_val()
6027             #
6028             # Write the element for error bars.
6029             #
6030             sub _write_error_val {
6031              
6032 3     3   12 my $self = shift;
6033 3         9 my $val = shift;
6034              
6035 3         8 my @attributes = ( 'val' => $val );
6036              
6037 3         9 $self->xml_empty_tag( 'c:val', @attributes );
6038             }
6039              
6040              
6041             ##############################################################################
6042             #
6043             # _write_custom_error()
6044             #
6045             # Write the custom error bars tags.
6046             #
6047             sub _write_custom_error {
6048              
6049 3     3   7 my $self = shift;
6050 3         6 my $error_bars = shift;
6051              
6052 3 50       12 if ( $error_bars->{_plus_values} ) {
6053              
6054             # Write the c:plus element.
6055 3         12 $self->xml_start_tag( 'c:plus' );
6056              
6057 3 100       13 if ( ref $error_bars->{_plus_values} eq 'ARRAY' ) {
6058 2         10 $self->_write_num_lit( $error_bars->{_plus_values} );
6059             }
6060             else {
6061             $self->_write_num_ref( $error_bars->{_plus_values},
6062 1         7 $error_bars->{_plus_data}, 'num' );
6063             }
6064              
6065 3         10 $self->xml_end_tag( 'c:plus' );
6066             }
6067              
6068 3 50       13 if ( $error_bars->{_minus_values} ) {
6069              
6070             # Write the c:minus element.
6071 3         30 $self->xml_start_tag( 'c:minus' );
6072              
6073 3 100       19 if ( ref $error_bars->{_minus_values} eq 'ARRAY' ) {
6074 2         7 $self->_write_num_lit( $error_bars->{_minus_values} );
6075             }
6076             else {
6077             $self->_write_num_ref( $error_bars->{_minus_values},
6078 1         5 $error_bars->{_minus_data}, 'num' );
6079             }
6080              
6081 3         15 $self->xml_end_tag( 'c:minus' );
6082             }
6083             }
6084              
6085              
6086              
6087             ##############################################################################
6088             #
6089             # _write_num_lit()
6090             #
6091             # Write the element for literal number list elements.
6092             #
6093             sub _write_num_lit {
6094              
6095 4     4   10 my $self = shift;
6096 4         14 my $data = shift;
6097 4         9 my $count = @$data;
6098              
6099              
6100             # Write the c:numLit element.
6101 4         22 $self->xml_start_tag( 'c:numLit' );
6102              
6103             # Write the c:formatCode element.
6104 4         18 $self->_write_format_code( 'General' );
6105              
6106             # Write the c:ptCount element.
6107 4         18 $self->_write_pt_count( $count );
6108              
6109 4         13 for my $i ( 0 .. $count - 1 ) {
6110 8         22 my $token = $data->[$i];
6111              
6112             # Write non-numeric data as 0.
6113 8 50 33     76 if ( defined $token
6114             && $token !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/ )
6115             {
6116 0         0 $token = 0;
6117             }
6118              
6119             # Write the c:pt element.
6120 8         40 $self->_write_pt( $i, $token );
6121             }
6122              
6123 4         10 $self->xml_end_tag( 'c:numLit' );
6124              
6125              
6126             }
6127              
6128              
6129             ##############################################################################
6130             #
6131             # _write_up_down_bars()
6132             #
6133             # Write the element.
6134             #
6135             sub _write_up_down_bars {
6136              
6137 101     101   273 my $self = shift;
6138 101         345 my $up_down_bars = $self->{_up_down_bars};
6139              
6140 101 100       416 return unless $up_down_bars;
6141              
6142 3         15 $self->xml_start_tag( 'c:upDownBars' );
6143              
6144             # Write the c:gapWidth element.
6145 3         20 $self->_write_gap_width( 150 );
6146              
6147             # Write the c:upBars element.
6148 3         35 $self->_write_up_bars( $up_down_bars->{_up} );
6149              
6150             # Write the c:downBars element.
6151 3         19 $self->_write_down_bars( $up_down_bars->{_down} );
6152              
6153 3         11 $self->xml_end_tag( 'c:upDownBars' );
6154             }
6155              
6156              
6157             ##############################################################################
6158             #
6159             # _write_gap_width()
6160             #
6161             # Write the element.
6162             #
6163             sub _write_gap_width {
6164              
6165 205     205   625 my $self = shift;
6166 205         672 my $val = shift;
6167              
6168 205 100       1020 return if !defined $val;
6169              
6170 10         32 my @attributes = ( 'val' => $val );
6171              
6172 10         62 $self->xml_empty_tag( 'c:gapWidth', @attributes );
6173             }
6174              
6175             ##############################################################################
6176             #
6177             # _write_up_bars()
6178             #
6179             # Write the element.
6180             #
6181             sub _write_up_bars {
6182              
6183 3     3   14 my $self = shift;
6184 3         6 my $format = shift;
6185              
6186 3 100 66     22 if ( $format->{_line}->{_defined} || $format->{_fill}->{_defined} ) {
6187              
6188 1         4 $self->xml_start_tag( 'c:upBars' );
6189              
6190             # Write the c:spPr element.
6191 1         4 $self->_write_sp_pr( $format );
6192              
6193 1         4 $self->xml_end_tag( 'c:upBars' );
6194             }
6195             else {
6196 2         8 $self->xml_empty_tag( 'c:upBars' );
6197             }
6198             }
6199              
6200              
6201             ##############################################################################
6202             #
6203             # _write_down_bars()
6204             #
6205             # Write the element.
6206             #
6207             sub _write_down_bars {
6208              
6209 3     3   12 my $self = shift;
6210 3         7 my $format = shift;
6211              
6212 3 100 66     45 if ( $format->{_line}->{_defined} || $format->{_fill}->{_defined} ) {
6213              
6214 1         13 $self->xml_start_tag( 'c:downBars' );
6215              
6216             # Write the c:spPr element.
6217 1         4 $self->_write_sp_pr( $format );
6218              
6219 1         4 $self->xml_end_tag( 'c:downBars' );
6220             }
6221             else {
6222 2         9 $self->xml_empty_tag( 'c:downBars' );
6223             }
6224             }
6225              
6226              
6227             ##############################################################################
6228             #
6229             # _write_c_smooth()
6230             #
6231             # Write the element.
6232             #
6233             sub _write_c_smooth {
6234              
6235 261     261   528 my $self = shift;
6236 261         511 my $smooth = shift;
6237              
6238 261 100       841 return unless $smooth;
6239              
6240 10         30 my @attributes = ( 'val' => 1 );
6241              
6242 10         31 $self->xml_empty_tag( 'c:smooth', @attributes );
6243             }
6244              
6245             ##############################################################################
6246             #
6247             # _write_disp_units()
6248             #
6249             # Write the element.
6250             #
6251             sub _write_disp_units {
6252              
6253 382     382   966 my $self = shift;
6254 382         846 my $units = shift;
6255 382         849 my $display = shift;
6256              
6257 382 100       1426 return if not $units;
6258              
6259 12         39 my @attributes = ( 'val' => $units );
6260              
6261 12         58 $self->xml_start_tag( 'c:dispUnits' );
6262              
6263 12         44 $self->xml_empty_tag( 'c:builtInUnit', @attributes );
6264              
6265 12 100       44 if ( $display ) {
6266 1         4 $self->xml_start_tag( 'c:dispUnitsLbl' );
6267 1         4 $self->xml_empty_tag( 'c:layout' );
6268 1         3 $self->xml_end_tag( 'c:dispUnitsLbl' );
6269             }
6270              
6271 12         63 $self->xml_end_tag( 'c:dispUnits' );
6272             }
6273              
6274              
6275             ##############################################################################
6276             #
6277             # _write_a_grad_fill()
6278             #
6279             # Write the element.
6280             #
6281             sub _write_a_grad_fill {
6282              
6283 13     13   45 my $self = shift;
6284 13         37 my $gradient = shift;
6285              
6286              
6287 13         76 my @attributes = (
6288             'flip' => 'none',
6289             'rotWithShape' => 1,
6290             );
6291              
6292              
6293 13 100       64 if ( $gradient->{_type} eq 'linear' ) {
6294 10         28 @attributes = ();
6295             }
6296              
6297 13         55 $self->xml_start_tag( 'a:gradFill', @attributes );
6298              
6299             # Write the a:gsLst element.
6300 13         120 $self->_write_a_gs_lst( $gradient );
6301              
6302 13 100       68 if ( $gradient->{_type} eq 'linear' ) {
6303             # Write the a:lin element.
6304 10         64 $self->_write_a_lin( $gradient->{_angle} );
6305             }
6306             else {
6307             # Write the a:path element.
6308 3         21 $self->_write_a_path( $gradient->{_type} );
6309              
6310             # Write the a:tileRect element.
6311 3         16 $self->_write_a_tile_rect( $gradient->{_type} );
6312             }
6313              
6314 13         77 $self->xml_end_tag( 'a:gradFill' );
6315             }
6316              
6317              
6318             ##############################################################################
6319             #
6320             # _write_a_gs_lst()
6321             #
6322             # Write the element.
6323             #
6324             sub _write_a_gs_lst {
6325              
6326 13     13   44 my $self = shift;
6327 13         28 my $gradient = shift;
6328 13         34 my $positions = $gradient->{_positions};
6329 13         27 my $colors = $gradient->{_colors};
6330              
6331 13         51 $self->xml_start_tag( 'a:gsLst' );
6332              
6333 13         77 for my $i ( 0 .. @$colors -1 ) {
6334              
6335 38         97 my $pos = int($positions->[$i] * 1000);
6336              
6337 38         91 my @attributes = ( 'pos' => $pos );
6338 38         161 $self->xml_start_tag( 'a:gs', @attributes );
6339              
6340 38         167 my $color = $self->_get_color( $colors->[$i] );
6341              
6342             # Write the a:srgbClr element.
6343             # TODO: Wait for a feature request to support transparency.
6344 38         217 $self->_write_a_srgb_clr( $color );
6345              
6346 38         134 $self->xml_end_tag( 'a:gs' );
6347             }
6348              
6349 13         52 $self->xml_end_tag( 'a:gsLst' );
6350             }
6351              
6352              
6353             ##############################################################################
6354             #
6355             # _write_a_lin()
6356             #
6357             # Write the element.
6358             #
6359             sub _write_a_lin {
6360              
6361 10     10   27 my $self = shift;
6362 10         20 my $angle = shift;
6363 10         23 my $scaled = 0;
6364              
6365 10         28 $angle = int( 60000 * $angle );
6366              
6367 10         34 my @attributes = (
6368             'ang' => $angle,
6369             'scaled' => $scaled,
6370             );
6371              
6372 10         43 $self->xml_empty_tag( 'a:lin', @attributes );
6373             }
6374              
6375             ##############################################################################
6376             #
6377             # _write_a_path()
6378             #
6379             # Write the element.
6380             #
6381             sub _write_a_path {
6382              
6383 3     3   8 my $self = shift;
6384 3         7 my $type = shift;
6385              
6386              
6387 3         9 my @attributes = ( 'path' => $type );
6388              
6389 3         12 $self->xml_start_tag( 'a:path', @attributes );
6390              
6391             # Write the a:fillToRect element.
6392 3         50 $self->_write_a_fill_to_rect( $type );
6393              
6394 3         10 $self->xml_end_tag( 'a:path' );
6395             }
6396              
6397              
6398             ##############################################################################
6399             #
6400             # _write_a_fill_to_rect()
6401             #
6402             # Write the element.
6403             #
6404             sub _write_a_fill_to_rect {
6405              
6406 3     3   7 my $self = shift;
6407 3         8 my $type = shift;
6408 3         17 my @attributes = ();
6409              
6410 3 100       13 if ( $type eq 'shape' ) {
6411 1         7 @attributes = (
6412             'l' => 50000,
6413             't' => 50000,
6414             'r' => 50000,
6415             'b' => 50000,
6416             );
6417              
6418             }
6419             else {
6420 2         8 @attributes = (
6421             'l' => 100000,
6422             't' => 100000,
6423             );
6424             }
6425              
6426              
6427 3         14 $self->xml_empty_tag( 'a:fillToRect', @attributes );
6428             }
6429              
6430              
6431             ##############################################################################
6432             #
6433             # _write_a_tile_rect()
6434             #
6435             # Write the element.
6436             #
6437             sub _write_a_tile_rect {
6438              
6439 3     3   8 my $self = shift;
6440 3         6 my $type = shift;
6441 3         7 my @attributes = ();
6442              
6443 3 100       9 if ( $type eq 'shape' ) {
6444 1         3 @attributes = ();
6445             }
6446             else {
6447 2         7 @attributes = (
6448             'r' => -100000,
6449             'b' => -100000,
6450             );
6451             }
6452              
6453 3         18 $self->xml_empty_tag( 'a:tileRect', @attributes );
6454             }
6455              
6456              
6457             ##############################################################################
6458             #
6459             # _write_a_patt_fill()
6460             #
6461             # Write the element.
6462             #
6463             sub _write_a_patt_fill {
6464              
6465 58     58   93 my $self = shift;
6466 58         105 my $pattern = shift;
6467              
6468 58         160 my @attributes = ( 'prst' => $pattern->{pattern} );
6469              
6470 58         160 $self->xml_start_tag( 'a:pattFill', @attributes );
6471              
6472             # Write the a:fgClr element.
6473 58         203 $self->_write_a_fg_clr( $pattern->{fg_color} );
6474              
6475             # Write the a:bgClr element.
6476 58         189 $self->_write_a_bg_clr( $pattern->{bg_color} );
6477              
6478 58         141 $self->xml_end_tag( 'a:pattFill' );
6479             }
6480              
6481              
6482             ##############################################################################
6483             #
6484             # _write_a_fg_clr()
6485             #
6486             # Write the element.
6487             #
6488             sub _write_a_fg_clr {
6489              
6490 58     58   96 my $self = shift;
6491 58         118 my $color = shift;
6492              
6493 58         166 $color = $self->_get_color( $color );
6494              
6495 58         197 $self->xml_start_tag( 'a:fgClr' );
6496              
6497             # Write the a:srgbClr element.
6498 58         221 $self->_write_a_srgb_clr( $color );
6499              
6500 58         215 $self->xml_end_tag( 'a:fgClr' );
6501             }
6502              
6503              
6504              
6505             ##############################################################################
6506             #
6507             # _write_a_bg_clr()
6508             #
6509             # Write the element.
6510             #
6511             sub _write_a_bg_clr {
6512              
6513 58     58   100 my $self = shift;
6514 58         89 my $color = shift;
6515              
6516 58         117 $color = $self->_get_color( $color );
6517              
6518 58         210 $self->xml_start_tag( 'a:bgClr' );
6519              
6520             # Write the a:srgbClr element.
6521 58         155 $self->_write_a_srgb_clr( $color );
6522              
6523 58         177 $self->xml_end_tag( 'a:bgClr' );
6524             }
6525              
6526              
6527             1;
6528              
6529             __END__