File Coverage

blib/lib/Excel/Writer/XLSX/Chart/Pie.pm
Criterion Covered Total %
statement 105 107 98.1
branch 15 20 75.0
condition 7 11 63.6
subroutine 16 16 100.0
pod 1 2 50.0
total 144 156 92.3


line stmt bran cond sub pod time code
1             package Excel::Writer::XLSX::Chart::Pie;
2              
3             ###############################################################################
4             #
5             # Pie - A class for writing Excel Pie charts.
6             #
7             # Used in conjunction with Excel::Writer::XLSX::Chart.
8             #
9             # See formatting note in Excel::Writer::XLSX::Chart.
10             #
11             # Copyright 2000-2020, John McNamara, jmcnamara@cpan.org
12             #
13             # Documentation after __END__
14             #
15              
16             # perltidy with the following options: -mbl=2 -pt=0 -nola
17              
18 37     37   2998 use 5.008002;
  37         126  
19 37     37   176 use strict;
  37         69  
  37         714  
20 37     37   169 use warnings;
  37         69  
  37         857  
21 37     37   168 use Carp;
  37         66  
  37         1956  
22 37     37   211 use Excel::Writer::XLSX::Chart;
  37         73  
  37         35576  
23              
24             our @ISA = qw(Excel::Writer::XLSX::Chart);
25             our $VERSION = '1.07';
26              
27              
28             ###############################################################################
29             #
30             # new()
31             #
32             #
33             sub new {
34              
35 60     60 0 838 my $class = shift;
36 60         212 my $self = Excel::Writer::XLSX::Chart->new( @_ );
37              
38 60         118 $self->{_vary_data_color} = 1;
39 60         112 $self->{_rotation} = 0;
40              
41             # Set the available data label positions for this chart type.
42 60         114 $self->{_label_position_default} = 'best_fit';
43             $self->{_label_positions} = {
44 60         234 center => 'ctr',
45             inside_end => 'inEnd',
46             outside_end => 'outEnd',
47             best_fit => 'bestFit',
48             };
49              
50 60         159 bless $self, $class;
51 60         187 return $self;
52             }
53              
54              
55             ###############################################################################
56             #
57             # set_rotation()
58             #
59             # Set the Pie/Doughnut chart rotation: the angle of the first slice.
60             #
61             sub set_rotation {
62              
63 5     5 1 33 my $self = shift;
64 5         7 my $rotation = shift;
65              
66 5 50       13 return if !defined $rotation;
67              
68 5 50 33     20 if ( $rotation >= 0 && $rotation <= 360 ) {
69 5         11 $self->{_rotation} = $rotation;
70             }
71             else {
72 0         0 carp "Chart rotation $rotation outside range: 0 <= rotation <= 360";
73             }
74             }
75              
76              
77             ##############################################################################
78             #
79             # _write_chart_type()
80             #
81             # Override the virtual superclass method with a chart specific method.
82             #
83             sub _write_chart_type {
84              
85 48     48   99 my $self = shift;
86              
87             # Write the c:pieChart element.
88 48         152 $self->_write_pie_chart( @_ );
89             }
90              
91              
92             ##############################################################################
93             #
94             # _write_pie_chart()
95             #
96             # Write the element. Over-ridden method to remove axis_id code
97             # since Pie charts don't require val and cat axes.
98             #
99             sub _write_pie_chart {
100              
101 48     48   90 my $self = shift;
102              
103 48         170 $self->xml_start_tag( 'c:pieChart' );
104              
105             # Write the c:varyColors element.
106 48         157 $self->_write_vary_colors();
107              
108             # Write the series elements.
109 48         100 $self->_write_ser( $_ ) for @{ $self->{_series} };
  48         345  
110              
111             # Write the c:firstSliceAng element.
112 48         208 $self->_write_first_slice_ang();
113              
114 48         131 $self->xml_end_tag( 'c:pieChart' );
115             }
116              
117              
118             ##############################################################################
119             #
120             # _write_plot_area().
121             #
122             # Over-ridden method to remove the cat_axis() and val_axis() code since
123             # Pie/Doughnut charts don't require those axes.
124             #
125             # Write the element.
126             #
127             sub _write_plot_area {
128              
129 57     57   117 my $self = shift;
130 57         129 my $second_chart = $self->{_combined};
131              
132 57         193 $self->xml_start_tag( 'c:plotArea' );
133              
134             # Write the c:layout element.
135 57         594 $self->_write_layout( $self->{_plotarea}->{_layout}, 'plot' );
136              
137             # Write the subclass chart type element.
138 57         270 $self->_write_chart_type();
139              
140             # Configure a combined chart if present.
141 57 100       184 if ( $second_chart ) {
142              
143             # Secondary axis has unique id otherwise use same as primary.
144 2 50       16 if ( $second_chart->{_is_secondary} ) {
145 0         0 $second_chart->{_id} = 1000 + $self->{_id};
146             }
147             else {
148 2         7 $second_chart->{_id} = $self->{_id};
149             }
150              
151             # Shart the same filehandle for writing.
152 2         5 $second_chart->{_fh} = $self->{_fh};
153              
154             # Share series index with primary chart.
155 2         6 $second_chart->{_series_index} = $self->{_series_index};
156              
157             # Write the subclass chart type elements for combined chart.
158 2         8 $second_chart->_write_chart_type();
159             }
160              
161             # Write the c:spPr element for the plotarea formatting.
162 57         223 $self->_write_sp_pr( $self->{_plotarea} );
163              
164 57         177 $self->xml_end_tag( 'c:plotArea' );
165             }
166              
167              
168             ##############################################################################
169             #
170             # _write_legend().
171             #
172             # Over-ridden method to add to legend.
173             #
174             # Write the element.
175             #
176             sub _write_legend {
177              
178 57     57   134 my $self = shift;
179 57         151 my $legend = $self->{_legend};
180 57   100     275 my $position = $legend->{_position} || 'right';
181 57         120 my $font = $legend->{_font};
182 57         124 my @delete_series = ();
183 57         187 my $overlay = 0;
184              
185 57 100 66     277 if ( defined $legend->{_delete_series}
186             && ref $legend->{_delete_series} eq 'ARRAY' )
187             {
188 1         3 @delete_series = @{ $legend->{_delete_series} };
  1         4  
189             }
190              
191 57 100       239 if ( $position =~ s/^overlay_// ) {
192 1         3 $overlay = 1;
193             }
194              
195 57         389 my %allowed = (
196             right => 'r',
197             left => 'l',
198             top => 't',
199             bottom => 'b',
200             top_right => 'tr',
201             );
202              
203 57 100       205 return if $position eq 'none';
204 56 50       187 return unless exists $allowed{$position};
205              
206 56         119 $position = $allowed{$position};
207              
208 56         206 $self->xml_start_tag( 'c:legend' );
209              
210             # Write the c:legendPos element.
211 56         393 $self->_write_legend_pos( $position );
212              
213             # Remove series labels from the legend.
214 56         136 for my $index ( @delete_series ) {
215              
216             # Write the c:legendEntry element.
217 1         6 $self->_write_legend_entry( $index );
218             }
219              
220             # Write the c:layout element.
221 56         274 $self->_write_layout( $legend->{_layout}, 'legend' );
222              
223             # Write the c:overlay element.
224 56 100       193 $self->_write_overlay() if $overlay;
225              
226             # Write the c:spPr element.
227 56         222 $self->_write_sp_pr( $legend );
228              
229             # Write the c:txPr element. Over-ridden.
230 56         223 $self->_write_tx_pr_legend( 0, $font );
231              
232 56         158 $self->xml_end_tag( 'c:legend' );
233             }
234              
235              
236             ##############################################################################
237             #
238             # _write_tx_pr_legend()
239             #
240             # Write the element for legends.
241             #
242             sub _write_tx_pr_legend {
243              
244 56     56   109 my $self = shift;
245 56         117 my $horiz = shift;
246 56         126 my $font = shift;
247 56         108 my $rotation = undef;
248              
249 56 50 66     170 if ( $font && exists $font->{_rotation} ) {
250 1         2 $rotation = $font->{_rotation};
251             }
252              
253 56         198 $self->xml_start_tag( 'c:txPr' );
254              
255             # Write the a:bodyPr element.
256 56         364 $self->_write_a_body_pr( $rotation, $horiz );
257              
258             # Write the a:lstStyle element.
259 56         314 $self->_write_a_lst_style();
260              
261             # Write the a:p element.
262 56         266 $self->_write_a_p_legend( $font );
263              
264 56         160 $self->xml_end_tag( 'c:txPr' );
265             }
266              
267              
268             ##############################################################################
269             #
270             # _write_a_p_legend()
271             #
272             # Write the element for legends.
273             #
274             sub _write_a_p_legend {
275              
276 56     56   107 my $self = shift;
277 56         92 my $font = shift;
278              
279 56         196 $self->xml_start_tag( 'a:p' );
280              
281             # Write the a:pPr element.
282 56         198 $self->_write_a_p_pr_legend( $font );
283              
284             # Write the a:endParaRPr element.
285 56         351 $self->_write_a_end_para_rpr();
286              
287 56         171 $self->xml_end_tag( 'a:p' );
288             }
289              
290              
291             ##############################################################################
292             #
293             # _write_a_p_pr_legend()
294             #
295             # Write the element for legends.
296             #
297             sub _write_a_p_pr_legend {
298              
299 56     56   111 my $self = shift;
300 56         89 my $font = shift;
301 56         107 my $rtl = 0;
302              
303 56         152 my @attributes = ( 'rtl' => $rtl );
304              
305 56         179 $self->xml_start_tag( 'a:pPr', @attributes );
306              
307             # Write the a:defRPr element.
308 56         343 $self->_write_a_def_rpr( $font );
309              
310 56         176 $self->xml_end_tag( 'a:pPr' );
311             }
312              
313              
314             ##############################################################################
315             #
316             # _write_vary_colors()
317             #
318             # Write the element.
319             #
320             sub _write_vary_colors {
321              
322 59     59   111 my $self = shift;
323 59         109 my $val = 1;
324              
325 59         168 my @attributes = ( 'val' => $val );
326              
327 59         200 $self->xml_empty_tag( 'c:varyColors', @attributes );
328             }
329              
330              
331             ##############################################################################
332             #
333             # _write_first_slice_ang()
334             #
335             # Write the element.
336             #
337             sub _write_first_slice_ang {
338              
339 59     59   125 my $self = shift;
340 59         150 my $val = $self->{_rotation};
341              
342 59         152 my @attributes = ( 'val' => $val );
343              
344 59         191 $self->xml_empty_tag( 'c:firstSliceAng', @attributes );
345             }
346              
347             1;
348              
349              
350             __END__