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-2019, 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 36     36   3338 use 5.008002;
  36         135  
19 36     36   195 use strict;
  36         76  
  36         710  
20 36     36   158 use warnings;
  36         72  
  36         932  
21 36     36   194 use Carp;
  36         71  
  36         2204  
22 36     36   226 use Excel::Writer::XLSX::Chart;
  36         67  
  36         36747  
23              
24             our @ISA = qw(Excel::Writer::XLSX::Chart);
25             our $VERSION = '1.03';
26              
27              
28             ###############################################################################
29             #
30             # new()
31             #
32             #
33             sub new {
34              
35 59     59 0 948 my $class = shift;
36 59         227 my $self = Excel::Writer::XLSX::Chart->new( @_ );
37              
38 59         121 $self->{_vary_data_color} = 1;
39 59         112 $self->{_rotation} = 0;
40              
41             # Set the available data label positions for this chart type.
42 59         112 $self->{_label_position_default} = 'best_fit';
43             $self->{_label_positions} = {
44 59         235 center => 'ctr',
45             inside_end => 'inEnd',
46             outside_end => 'outEnd',
47             best_fit => 'bestFit',
48             };
49              
50 59         147 bless $self, $class;
51 59         191 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 35 my $self = shift;
64 5         7 my $rotation = shift;
65              
66 5 50       14 return if !defined $rotation;
67              
68 5 50 33     28 if ( $rotation >= 0 && $rotation <= 360 ) {
69 5         13 $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 47     47   106 my $self = shift;
86              
87             # Write the c:pieChart element.
88 47         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 47     47   89 my $self = shift;
102              
103 47         163 $self->xml_start_tag( 'c:pieChart' );
104              
105             # Write the c:varyColors element.
106 47         160 $self->_write_vary_colors();
107              
108             # Write the series elements.
109 47         74 $self->_write_ser( $_ ) for @{ $self->{_series} };
  47         322  
110              
111             # Write the c:firstSliceAng element.
112 47         212 $self->_write_first_slice_ang();
113              
114 47         132 $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 56     56   98 my $self = shift;
130 56         118 my $second_chart = $self->{_combined};
131              
132 56         168 $self->xml_start_tag( 'c:plotArea' );
133              
134             # Write the c:layout element.
135 56         439 $self->_write_layout( $self->{_plotarea}->{_layout}, 'plot' );
136              
137             # Write the subclass chart type element.
138 56         205 $self->_write_chart_type();
139              
140             # Configure a combined chart if present.
141 56 100       159 if ( $second_chart ) {
142              
143             # Secondary axis has unique id otherwise use same as primary.
144 2 50       6 if ( $second_chart->{_is_secondary} ) {
145 0         0 $second_chart->{_id} = 1000 + $self->{_id};
146             }
147             else {
148 2         5 $second_chart->{_id} = $self->{_id};
149             }
150              
151             # Shart the same filehandle for writing.
152 2         4 $second_chart->{_fh} = $self->{_fh};
153              
154             # Share series index with primary chart.
155 2         4 $second_chart->{_series_index} = $self->{_series_index};
156              
157             # Write the subclass chart type elements for combined chart.
158 2         6 $second_chart->_write_chart_type();
159             }
160              
161             # Write the c:spPr element for the plotarea formatting.
162 56         219 $self->_write_sp_pr( $self->{_plotarea} );
163              
164 56         145 $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 56     56   155 my $self = shift;
179 56         125 my $legend = $self->{_legend};
180 56   100     275 my $position = $legend->{_position} || 'right';
181 56         132 my $font = $legend->{_font};
182 56         115 my @delete_series = ();
183 56         107 my $overlay = 0;
184              
185 56 100 66     261 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 56 100       242 if ( $position =~ s/^overlay_// ) {
192 1         3 $overlay = 1;
193             }
194              
195 56         379 my %allowed = (
196             right => 'r',
197             left => 'l',
198             top => 't',
199             bottom => 'b',
200             top_right => 'tr',
201             );
202              
203 56 100       181 return if $position eq 'none';
204 55 50       189 return unless exists $allowed{$position};
205              
206 55         109 $position = $allowed{$position};
207              
208 55         224 $self->xml_start_tag( 'c:legend' );
209              
210             # Write the c:legendPos element.
211 55         414 $self->_write_legend_pos( $position );
212              
213             # Remove series labels from the legend.
214 55         141 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 55         306 $self->_write_layout( $legend->{_layout}, 'legend' );
222              
223             # Write the c:overlay element.
224 55 100       202 $self->_write_overlay() if $overlay;
225              
226             # Write the c:spPr element.
227 55         212 $self->_write_sp_pr( $legend );
228              
229             # Write the c:txPr element. Over-ridden.
230 55         200 $self->_write_tx_pr_legend( 0, $font );
231              
232 55         159 $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 55     55   105 my $self = shift;
245 55         94 my $horiz = shift;
246 55         89 my $font = shift;
247 55         105 my $rotation = undef;
248              
249 55 50 66     169 if ( $font && exists $font->{_rotation} ) {
250 1         3 $rotation = $font->{_rotation};
251             }
252              
253 55         228 $self->xml_start_tag( 'c:txPr' );
254              
255             # Write the a:bodyPr element.
256 55         407 $self->_write_a_body_pr( $rotation, $horiz );
257              
258             # Write the a:lstStyle element.
259 55         293 $self->_write_a_lst_style();
260              
261             # Write the a:p element.
262 55         241 $self->_write_a_p_legend( $font );
263              
264 55         150 $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 55     55   108 my $self = shift;
277 55         108 my $font = shift;
278              
279 55         168 $self->xml_start_tag( 'a:p' );
280              
281             # Write the a:pPr element.
282 55         194 $self->_write_a_p_pr_legend( $font );
283              
284             # Write the a:endParaRPr element.
285 55         346 $self->_write_a_end_para_rpr();
286              
287 55         151 $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 55     55   109 my $self = shift;
300 55         88 my $font = shift;
301 55         115 my $rtl = 0;
302              
303 55         134 my @attributes = ( 'rtl' => $rtl );
304              
305 55         178 $self->xml_start_tag( 'a:pPr', @attributes );
306              
307             # Write the a:defRPr element.
308 55         389 $self->_write_a_def_rpr( $font );
309              
310 55         168 $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 58     58   102 my $self = shift;
323 58         104 my $val = 1;
324              
325 58         137 my @attributes = ( 'val' => $val );
326              
327 58         189 $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 58     58   119 my $self = shift;
340 58         137 my $val = $self->{_rotation};
341              
342 58         193 my @attributes = ( 'val' => $val );
343              
344 58         199 $self->xml_empty_tag( 'c:firstSliceAng', @attributes );
345             }
346              
347             1;
348              
349              
350             __END__