File Coverage

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