File Coverage

blib/lib/Spreadsheet/WriteExcel/Chart.pm
Criterion Covered Total %
statement 846 998 84.7
branch 62 126 49.2
condition 9 20 45.0
subroutine 70 83 84.3
pod 7 9 77.7
total 994 1236 80.4


line stmt bran cond sub pod time code
1             package Spreadsheet::WriteExcel::Chart;
2              
3             ###############################################################################
4             #
5             # Chart - A writer class for Excel Charts.
6             #
7             # Used in conjunction with Spreadsheet::WriteExcel.
8             #
9             # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
10             #
11             # Documentation after __END__
12             #
13              
14 32     32   2700 use Exporter;
  32         72  
  32         1407  
15 32     32   200 use strict;
  32         73  
  32         1231  
16 32     32   192 use Carp;
  32         78  
  32         3068  
17 32     32   2146 use FileHandle;
  32         31574  
  32         322  
18 32     32   18527 use Spreadsheet::WriteExcel::Worksheet;
  32         95  
  32         1475  
19              
20              
21 32     32   200 use vars qw($VERSION @ISA);
  32         70  
  32         64061  
22             @ISA = qw(Spreadsheet::WriteExcel::Worksheet);
23              
24             $VERSION = '2.40';
25              
26             ###############################################################################
27             #
28             # Formatting information.
29             #
30             # perltidy with options: -mbl=2 -pt=0 -nola
31             #
32             # Any camel case Hungarian notation style variable names in the BIFF record
33             # writing sub-routines below are for similarity with names used in the Excel
34             # documentation. Otherwise lowercase underscore style names are used.
35             #
36              
37              
38             ###############################################################################
39             #
40             # The chart class hierarchy is as follows. Chart.pm acts as a factory for the
41             # sub-classes.
42             #
43             #
44             # Spreadsheet::WriteExcel::BIFFwriter
45             # ^
46             # |
47             # Spreadsheet::WriteExcel::Worksheet
48             # ^
49             # |
50             # Spreadsheet::WriteExcel::Chart
51             # ^
52             # |
53             # Spreadsheet::WriteExcel::Chart::* (sub-types)
54             #
55              
56              
57             ###############################################################################
58             #
59             # factory()
60             #
61             # Factory method for returning chart objects based on their class type.
62             #
63             sub factory {
64              
65 9     9 0 5683 my $current_class = shift;
66 9         20 my $chart_subclass = shift;
67              
68 9         33 $chart_subclass = ucfirst lc $chart_subclass;
69              
70 9         27 my $module = "Spreadsheet::WriteExcel::Chart::" . $chart_subclass;
71              
72 9         792 eval "require $module";
73              
74             # TODO. Need to re-raise this error from Workbook::add_chart().
75 9 50       59 die "Chart type '$chart_subclass' not supported in add_chart()\n" if $@;
76              
77 9         70 return $module->new( @_ );
78             }
79              
80              
81             ###############################################################################
82             #
83             # new()
84             #
85             # Default constructor for sub-classes.
86             #
87             sub new {
88              
89 10     10 0 211 my $class = shift;
90 10         95 my $self = Spreadsheet::WriteExcel::Worksheet->new( @_ );
91              
92 10         23 $self->{_sheet_type} = 0x0200;
93 10         29 $self->{_orientation} = 0x0;
94 10         28 $self->{_series} = [];
95 10         24 $self->{_embedded} = 0;
96              
97 10         30 bless $self, $class;
98 10         44 $self->_set_default_properties();
99 10         35 $self->_set_default_config_data();
100 10         39 return $self;
101             }
102              
103              
104             ###############################################################################
105             #
106             # Public methods.
107             #
108             ###############################################################################
109              
110              
111             ###############################################################################
112             #
113             # add_series()
114             #
115             # Add a series and it's properties to a chart.
116             #
117             sub add_series {
118              
119 0     0 1 0 my $self = shift;
120 0         0 my %arg = @_;
121              
122 0 0       0 croak "Must specify 'values' in add_series()" if !exists $arg{values};
123              
124             # Parse the ranges to validate them and extract salient information.
125 0         0 my @value_data = $self->_parse_series_formula( $arg{values} );
126 0         0 my @category_data = $self->_parse_series_formula( $arg{categories} );
127 0         0 my $name_formula = $self->_parse_series_formula( $arg{name_formula} );
128              
129             # Default category count to the same as the value count if not defined.
130 0 0       0 if ( !defined $category_data[1] ) {
131 0         0 $category_data[1] = $value_data[1];
132             }
133              
134             # Add the parsed data to the user supplied data.
135             %arg = (
136 0         0 @_,
137             _values => \@value_data,
138             _categories => \@category_data,
139             _name_formula => $name_formula
140             );
141              
142             # Encode the Series name.
143 0         0 my ( $name, $encoding ) =
144             $self->_encode_utf16( $arg{name}, $arg{name_encoding} );
145              
146 0         0 $arg{name} = $name;
147 0         0 $arg{name_encoding} = $encoding;
148              
149 0         0 push @{ $self->{_series} }, \%arg;
  0         0  
150             }
151              
152              
153             ###############################################################################
154             #
155             # set_x_axis()
156             #
157             # Set the properties of the X-axis.
158             #
159             sub set_x_axis {
160              
161 0     0 1 0 my $self = shift;
162 0         0 my %arg = @_;
163              
164 0         0 my ( $name, $encoding ) =
165             $self->_encode_utf16( $arg{name}, $arg{name_encoding} );
166              
167 0         0 my $formula = $self->_parse_series_formula( $arg{name_formula} );
168              
169 0         0 $self->{_x_axis_name} = $name;
170 0         0 $self->{_x_axis_encoding} = $encoding;
171 0         0 $self->{_x_axis_formula} = $formula;
172             }
173              
174              
175             ###############################################################################
176             #
177             # set_y_axis()
178             #
179             # Set the properties of the Y-axis.
180             #
181             sub set_y_axis {
182              
183 0     0 1 0 my $self = shift;
184 0         0 my %arg = @_;
185              
186 0         0 my ( $name, $encoding ) =
187             $self->_encode_utf16( $arg{name}, $arg{name_encoding} );
188              
189 0         0 my $formula = $self->_parse_series_formula( $arg{name_formula} );
190              
191 0         0 $self->{_y_axis_name} = $name;
192 0         0 $self->{_y_axis_encoding} = $encoding;
193 0         0 $self->{_y_axis_formula} = $formula;
194             }
195              
196              
197             ###############################################################################
198             #
199             # set_title()
200             #
201             # Set the properties of the chart title.
202             #
203             sub set_title {
204              
205 0     0 1 0 my $self = shift;
206 0         0 my %arg = @_;
207              
208 0         0 my ( $name, $encoding ) =
209             $self->_encode_utf16( $arg{name}, $arg{name_encoding} );
210              
211 0         0 my $formula = $self->_parse_series_formula( $arg{name_formula} );
212              
213 0         0 $self->{_title_name} = $name;
214 0         0 $self->{_title_encoding} = $encoding;
215 0         0 $self->{_title_formula} = $formula;
216             }
217              
218              
219             ###############################################################################
220             #
221             # set_legend()
222             #
223             # Set the properties of the chart legend.
224             #
225             sub set_legend {
226              
227 0     0 1 0 my $self = shift;
228 0         0 my %arg = @_;
229              
230 0 0       0 if ( defined $arg{position} ) {
231 0 0       0 if ( lc $arg{position} eq 'none' ) {
232 0         0 $self->{_legend}->{_visible} = 0;
233             }
234             }
235             }
236              
237              
238             ###############################################################################
239             #
240             # set_plotarea()
241             #
242             # Set the properties of the chart plotarea.
243             #
244             sub set_plotarea {
245              
246 9     9 1 85 my $self = shift;
247 9         30 my %arg = @_;
248 9 100       31 return unless keys %arg;
249              
250 8         14 my $area = $self->{_plotarea};
251              
252             # Set the plotarea visibility.
253 8 50       21 if ( defined $arg{visible} ) {
254 0         0 $area->{_visible} = $arg{visible};
255 0 0       0 return if !$area->{_visible};
256             }
257              
258             # TODO. could move this out of if statement.
259 8         16 $area->{_bg_color_index} = 0x08;
260              
261             # Set the chart background colour.
262 8 100       20 if ( defined $arg{color} ) {
263 5         17 my ( $index, $rgb ) = $self->_get_color_indices( $arg{color} );
264 5 50       16 if ( defined $index ) {
265 5         10 $area->{_fg_color_index} = $index;
266 5         7 $area->{_fg_color_rgb} = $rgb;
267 5         6 $area->{_bg_color_index} = 0x08;
268 5         9 $area->{_bg_color_rgb} = 0x000000;
269             }
270             }
271              
272             # Set the border line colour.
273 8 100       24 if ( defined $arg{line_color} ) {
274 3         9 my ( $index, $rgb ) = $self->_get_color_indices( $arg{line_color} );
275 3 50       10 if ( defined $index ) {
276 3         6 $area->{_line_color_index} = $index;
277 3         6 $area->{_line_color_rgb} = $rgb;
278             }
279             }
280              
281             # Set the border line pattern.
282 8 100       22 if ( defined $arg{line_pattern} ) {
283 3         12 my $pattern = $self->_get_line_pattern( $arg{line_pattern} );
284 3         7 $area->{_line_pattern} = $pattern;
285             }
286              
287             # Set the border line weight.
288 8 100       35 if ( defined $arg{line_weight} ) {
289 3         12 my $weight = $self->_get_line_weight( $arg{line_weight} );
290 3         13 $area->{_line_weight} = $weight;
291             }
292             }
293              
294              
295             ###############################################################################
296             #
297             # set_chartarea()
298             #
299             # Set the properties of the chart chartarea.
300             #
301             sub set_chartarea {
302              
303 17     17 1 173 my $self = shift;
304 17         55 my %arg = @_;
305 17 100       52 return unless keys %arg;
306              
307 16         26 my $area = $self->{_chartarea};
308              
309             # Embedded automatic line weight has a different default value.
310 16 100       46 $area->{_line_weight} = 0xFFFF if $self->{_embedded};
311              
312              
313             # Set the chart background colour.
314 16 100       40 if ( defined $arg{color} ) {
315 10         36 my ( $index, $rgb ) = $self->_get_color_indices( $arg{color} );
316 10 50       29 if ( defined $index ) {
317 10         14 $area->{_fg_color_index} = $index;
318 10         17 $area->{_fg_color_rgb} = $rgb;
319 10         14 $area->{_bg_color_index} = 0x08;
320 10         16 $area->{_bg_color_rgb} = 0x000000;
321 10         13 $area->{_area_pattern} = 1;
322 10 100       30 $area->{_area_options} = 0x0000 if $self->{_embedded};
323 10         19 $area->{_visible} = 1;
324             }
325             }
326              
327             # Set the border line colour.
328 16 100       38 if ( defined $arg{line_color} ) {
329 6         17 my ( $index, $rgb ) = $self->_get_color_indices( $arg{line_color} );
330 6 50       22 if ( defined $index ) {
331 6         11 $area->{_line_color_index} = $index;
332 6         19 $area->{_line_color_rgb} = $rgb;
333 6         11 $area->{_line_pattern} = 0x00;
334 6         8 $area->{_line_options} = 0x0000;
335 6         14 $area->{_visible} = 1;
336             }
337             }
338              
339             # Set the border line pattern.
340 16 100       43 if ( defined $arg{line_pattern} ) {
341 6         24 my $pattern = $self->_get_line_pattern( $arg{line_pattern} );
342 6         9 $area->{_line_pattern} = $pattern;
343 6         11 $area->{_line_options} = 0x0000;
344 6 100       18 $area->{_line_color_index} = 0x4F if !defined $arg{line_color};
345 6         10 $area->{_visible} = 1;
346             }
347              
348             # Set the border line weight.
349 16 100       66 if ( defined $arg{line_weight} ) {
350 6         62 my $weight = $self->_get_line_weight( $arg{line_weight} );
351 6         12 $area->{_line_weight} = $weight;
352 6         10 $area->{_line_options} = 0x0000;
353 6 100       28 $area->{_line_pattern} = 0x00 if !defined $arg{line_pattern};
354 6 100       17 $area->{_line_color_index} = 0x4F if !defined $arg{line_color};
355 6         25 $area->{_visible} = 1;
356             }
357             }
358              
359              
360             ###############################################################################
361             #
362             # Internal methods. The following section of methods are used for the internal
363             # structuring of the Chart object and file format.
364             #
365             ###############################################################################
366              
367              
368             ###############################################################################
369             #
370             # _prepend(), overridden.
371             #
372             # The parent Worksheet class needs to store some data in memory and some in
373             # temporary files for efficiency. The Chart* classes don't need to do this
374             # since they are dealing with smaller amounts of data so we override
375             # _prepend() to turn it into an _append() method. This allows for a more
376             # natural method calling order.
377             #
378             sub _prepend {
379              
380 22     22   32 my $self = shift;
381              
382 22         206 $self->{_using_tmpfile} = 0;
383              
384 22         163 return $self->_append( @_ );
385             }
386              
387              
388             ###############################################################################
389             #
390             # _close(), overridden.
391             #
392             # Create and store the Chart data structures.
393             #
394             sub _close {
395              
396 2     2   6 my $self = shift;
397              
398             # Ignore any data that has been written so far since it is probably
399             # from unwanted Worksheet method calls.
400 2         7 $self->{_data} = '';
401              
402             # TODO. Check for charts without a series?
403              
404             # Store the chart BOF.
405 2         33 $self->_store_bof( 0x0020 );
406              
407             # Store the tab color.
408 2         23 $self->_store_tab_color();
409              
410             # Store the page header
411 2         20 $self->_store_header();
412              
413             # Store the page footer
414 2         21 $self->_store_footer();
415              
416             # Store the page horizontal centering
417 2         18 $self->_store_hcenter();
418              
419             # Store the page vertical centering
420 2         22 $self->_store_vcenter();
421              
422             # Store the left margin
423 2         21 $self->_store_margin_left();
424              
425             # Store the right margin
426 2         19 $self->_store_margin_right();
427              
428             # Store the top margin
429 2         20 $self->_store_margin_top();
430              
431             # Store the bottom margin
432 2         19 $self->_store_margin_bottom();
433              
434             # Store the page setup
435 2         19 $self->_store_setup();
436              
437             # Store the sheet password
438 2         24 $self->_store_password();
439              
440             # Start of Chart specific records.
441              
442             # Store the FBI font records.
443 2         2 $self->_store_fbi( @{ $self->{_config}->{_font_numbers} } );
  2         30  
444 2         3 $self->_store_fbi( @{ $self->{_config}->{_font_series} } );
  2         10  
445 2         3 $self->_store_fbi( @{ $self->{_config}->{_font_title} } );
  2         11  
446 2         4 $self->_store_fbi( @{ $self->{_config}->{_font_axes} } );
  2         10  
447              
448             # Ignore UNITS record.
449              
450             # Store the Chart sub-stream.
451 2         54 $self->_store_chart_stream();
452              
453             # Append the sheet dimensions
454 2         24 $self->_store_dimensions();
455              
456             # TODO add SINDEX and NUMBER records.
457              
458 2 50       11 if ( !$self->{_embedded} ) {
459 2         23 $self->_store_window2();
460             }
461              
462             # Store the sheet SCL record.
463 2 50       15 if ( !$self->{_embedded} ) {
464 2         10 $self->_store_zoom();
465             }
466              
467 2         22 $self->_store_eof();
468             }
469              
470              
471             ###############################################################################
472             #
473             # _store_window2(), overridden.
474             #
475             # Write BIFF record Window2. Note, this overrides the parent Worksheet
476             # record because the Chart version of the record is smaller and is used
477             # mainly to indicate if the chart tab is selected or not.
478             #
479             sub _store_window2 {
480              
481 32     32   297 use integer; # Avoid << shift bug in Perl 5.6.0 on HP-UX
  32         81  
  32         298  
482              
483 2     2   4 my $self = shift;
484              
485 2         4 my $record = 0x023E; # Record identifier
486 2         3 my $length = 0x000A; # Number of bytes to follow
487 2         4 my $grbit = 0x0000; # Option flags
488 2         3 my $rwTop = 0x0000; # Top visible row
489 2         4 my $colLeft = 0x0000; # Leftmost visible column
490 2         5 my $rgbHdr = 0x0000; # Row/col heading, grid color
491              
492             # The options flags that comprise $grbit
493 2         4 my $fDspFmla = 0; # 0 - bit
494 2         4 my $fDspGrid = 0; # 1
495 2         3 my $fDspRwCol = 0; # 2
496 2         3 my $fFrozen = 0; # 3
497 2         6 my $fDspZeros = 0; # 4
498 2         2 my $fDefaultHdr = 0; # 5
499 2         2 my $fArabic = 0; # 6
500 2         4 my $fDspGuts = 0; # 7
501 2         3 my $fFrozenNoSplit = 0; # 0 - bit
502 2         6 my $fSelected = $self->{_selected}; # 1
503 2         3 my $fPaged = 0; # 2
504 2         8 my $fBreakPreview = 0; # 3
505              
506             #<<< Perltidy ignore this.
507 2         4 $grbit = $fDspFmla;
508 2         5 $grbit |= $fDspGrid << 1;
509 2         4 $grbit |= $fDspRwCol << 2;
510 2         4 $grbit |= $fFrozen << 3;
511 2         3 $grbit |= $fDspZeros << 4;
512 2         4 $grbit |= $fDefaultHdr << 5;
513 2         4 $grbit |= $fArabic << 6;
514 2         3 $grbit |= $fDspGuts << 7;
515 2         4 $grbit |= $fFrozenNoSplit << 8;
516 2         5 $grbit |= $fSelected << 9;
517 2         3 $grbit |= $fPaged << 10;
518 2         4 $grbit |= $fBreakPreview << 11;
519             #>>>
520              
521 2         6 my $header = pack( "vv", $record, $length );
522 2         6 my $data = pack( "vvvV", $grbit, $rwTop, $colLeft, $rgbHdr );
523              
524 2         8 $self->_append( $header, $data );
525             }
526              
527              
528             ###############################################################################
529             #
530             # _parse_series_formula()
531             #
532             # Parse the formula used to define a series. We also extract some range
533             # information required for _store_series() and the SERIES record.
534             #
535             sub _parse_series_formula {
536              
537 0     0   0 my $self = shift;
538              
539 0         0 my $formula = $_[0];
540 0         0 my $encoding = 0;
541 0         0 my $length = 0;
542 0         0 my $count = 0;
543 0         0 my @tokens;
544              
545 0 0       0 return '' if !defined $formula;
546              
547             # Strip the = sign at the beginning of the formula string
548 0         0 $formula =~ s(^=)();
549              
550             # Parse the formula using the parser in Formula.pm
551 0         0 my $parser = $self->{_parser};
552              
553             # In order to raise formula errors from the point of view of the calling
554             # program we use an eval block and re-raise the error from here.
555             #
556 0         0 eval { @tokens = $parser->parse_formula( $formula ) };
  0         0  
557              
558 0 0       0 if ( $@ ) {
559 0         0 $@ =~ s/\n$//; # Strip the \n used in the Formula.pm die().
560 0         0 croak $@; # Re-raise the error.
561             }
562              
563             # Force ranges to be a reference class.
564 0         0 s/_ref3d/_ref3dR/ for @tokens;
565 0         0 s/_range3d/_range3dR/ for @tokens;
566 0         0 s/_name/_nameR/ for @tokens;
567              
568             # Parse the tokens into a formula string.
569 0         0 $formula = $parser->parse_tokens( @tokens );
570              
571             # Return formula for a single cell as used by title and series name.
572 0 0       0 if ( ord $formula == 0x3A ) {
573 0         0 return $formula;
574             }
575              
576             # Extract the range from the parse formula.
577 0 0       0 if ( ord $formula == 0x3B ) {
578 0         0 my ( $ptg, $ext_ref, $row_1, $row_2, $col_1, $col_2 ) = unpack 'Cv5',
579             $formula;
580              
581             # TODO. Remove high bit on relative references.
582 0         0 $count = $row_2 - $row_1 + 1;
583             }
584              
585 0         0 return ( $formula, $count );
586             }
587              
588             ###############################################################################
589             #
590             # _encode_utf16()
591             #
592             # Convert UTF8 strings used in the chart to UTF16.
593             #
594             sub _encode_utf16 {
595              
596 0     0   0 my $self = shift;
597              
598 0         0 my $string = shift;
599 0   0     0 my $encoding = shift || 0;
600              
601             # Exit if the $string isn't defined, i.e., hasn't been set by user.
602 0 0       0 return ( undef, undef ) if !defined $string;
603              
604             # Return if encoding is set, i.e., string has been manually encoded.
605             #return ( undef, undef ) if $string == 1;
606              
607             # Handle utf8 strings in perl 5.8.
608 0 0       0 if ( $] >= 5.008 ) {
609 0         0 require Encode;
610              
611 0 0       0 if ( Encode::is_utf8( $string ) ) {
612 0         0 $string = Encode::encode( "UTF-16BE", $string );
613 0         0 $encoding = 1;
614             }
615             }
616              
617             # Chart strings are limited to 255 characters.
618 0 0       0 my $limit = $encoding ? 255 * 2 : 255;
619              
620 0 0       0 if ( length $string >= $limit ) {
621              
622             # truncate the string and raise a warning.
623 0         0 $string = substr $string, 0, $limit;
624 0         0 carp 'Chart strings must be less than 256 characters. '
625             . 'String truncated';
626             }
627              
628 0         0 return ( $string, $encoding );
629             }
630              
631              
632             ###############################################################################
633             #
634             # _get_color_indices()
635             #
636             # Convert the user specified colour index or string to an colour index and
637             # RGB colour number.
638             #
639             sub _get_color_indices {
640              
641 32     32   8617 my $self = shift;
642 32         44 my $color = shift;
643 32         37 my $index;
644             my $rgb;
645              
646 32 100       85 return ( undef, undef ) if !defined $color;
647              
648 31         432 my %colors = (
649             aqua => 0x0F,
650             cyan => 0x0F,
651             black => 0x08,
652             blue => 0x0C,
653             brown => 0x10,
654             magenta => 0x0E,
655             fuchsia => 0x0E,
656             gray => 0x17,
657             grey => 0x17,
658             green => 0x11,
659             lime => 0x0B,
660             navy => 0x12,
661             orange => 0x35,
662             pink => 0x21,
663             purple => 0x14,
664             red => 0x0A,
665             silver => 0x16,
666             white => 0x09,
667             yellow => 0x0D,
668             );
669              
670              
671             # Check for the various supported colour index/name possibilities.
672 31 100 100     108 if ( exists $colors{$color} ) {
    100          
    100          
673              
674             # Colour matches one of the supported colour names.
675 27         44 $index = $colors{$color};
676             }
677             elsif ( $color =~ m/\D/ ) {
678              
679             # Return undef if $color is a string but not one of the supported ones.
680 1         23 return ( undef, undef );
681             }
682             elsif ( $color < 8 || $color > 63 ) {
683              
684             # Return undef if index is out of range.
685 2         11 return ( undef, undef );
686             }
687             else {
688              
689             # We should have a valid color index in a valid range.
690 1         3 $index = $color;
691             }
692              
693 28         78 $rgb = $self->_get_color_rbg( $index );
694 28         157 return ( $index, $rgb );
695             }
696              
697              
698             ###############################################################################
699             #
700             # _get_color_rbg()
701             #
702             # Get the RedGreenBlue number for the colour index from the Workbook palette.
703             #
704             sub _get_color_rbg {
705              
706 28     28   46 my $self = shift;
707 28         36 my $index = shift;
708              
709             # Adjust colour index from 8-63 (user range) to 0-55 (Excel range).
710 28         36 $index -= 8;
711              
712 28         37 my @red_green_blue = @{ $self->{_palette}->[$index] };
  28         110  
713 28         150 return unpack 'V', pack 'C*', @red_green_blue;
714             }
715              
716              
717             ###############################################################################
718             #
719             # _get_line_pattern()
720             #
721             # Get the Excel chart index for line pattern that corresponds to the user
722             # defined value.
723             #
724             sub _get_line_pattern {
725              
726 31     31   2212 my $self = shift;
727 31         62 my $value = lc shift;
728 31         36 my $default = 0;
729 31         32 my $pattern;
730              
731 31         297 my %patterns = (
732             0 => 5,
733             1 => 0,
734             2 => 1,
735             3 => 2,
736             4 => 3,
737             5 => 4,
738             6 => 7,
739             7 => 6,
740             8 => 8,
741             'solid' => 0,
742             'dash' => 1,
743             'dot' => 2,
744             'dash-dot' => 3,
745             'dash-dot-dot' => 4,
746             'none' => 5,
747             'dark-gray' => 6,
748             'medium-gray' => 7,
749             'light-gray' => 8,
750             );
751              
752 31 100       79 if ( exists $patterns{$value} ) {
753 28         41 $pattern = $patterns{$value};
754             }
755             else {
756 3         4 $pattern = $default;
757             }
758              
759 31         213 return $pattern;
760             }
761              
762              
763             ###############################################################################
764             #
765             # _get_line_weight()
766             #
767             # Get the Excel chart index for line weight that corresponds to the user
768             # defined value.
769             #
770             sub _get_line_weight {
771              
772 22     22   2215 my $self = shift;
773 22         45 my $value = lc shift;
774 22         33 my $default = 0;
775 22         29 my $weight;
776              
777 22         111 my %weights = (
778             1 => -1,
779             2 => 0,
780             3 => 1,
781             4 => 2,
782             'hairline' => -1,
783             'narrow' => 0,
784             'medium' => 1,
785             'wide' => 2,
786             );
787              
788 22 100       177 if ( exists $weights{$value} ) {
789 18         141 $weight = $weights{$value};
790             }
791             else {
792 4         7 $weight = $default;
793             }
794              
795 22         73 return $weight;
796             }
797              
798              
799             ###############################################################################
800             #
801             # _store_chart_stream()
802             #
803             # Store the CHART record and it's substreams.
804             #
805             sub _store_chart_stream {
806              
807 2     2   6 my $self = shift;
808              
809 2         3 $self->_store_chart( @{ $self->{_config}->{_chart} } );
  2         20  
810              
811 2         12 $self->_store_begin();
812              
813             # Store the chart SCL record.
814 2 50       9 if ( !$self->{_embedded} ) {
815 2         22 $self->_store_zoom();
816             }
817              
818 2         16 $self->_store_plotgrowth();
819              
820 2 50       16 if ( $self->{_chartarea}->{_visible} ) {
821 0         0 $self->_store_chartarea_frame_stream();
822             }
823              
824             # Store SERIES stream for each series.
825 2         5 my $index = 0;
826 2         3 for my $series ( @{ $self->{_series} } ) {
  2         8  
827              
828 0         0 $self->_store_series_stream(
829             _index => $index,
830             _value_formula => $series->{_values}->[0],
831             _value_count => $series->{_values}->[1],
832             _category_count => $series->{_categories}->[1],
833             _category_formula => $series->{_categories}->[0],
834             _name => $series->{name},
835             _name_encoding => $series->{name_encoding},
836             _name_formula => $series->{_name_formula},
837             );
838              
839 0         0 $index++;
840             }
841              
842 2         19 $self->_store_shtprops();
843              
844             # Write the TEXT streams.
845 2         8 for my $font_index ( 5 .. 6 ) {
846 4         33 $self->_store_defaulttext();
847 4         194 $self->_store_series_text_stream( $font_index );
848             }
849              
850 2         22 $self->_store_axesused( 1 );
851 2         18 $self->_store_axisparent_stream();
852              
853 2 50 33     20 if ( defined $self->{_title_name} || defined $self->{_title_formula} ) {
854 0         0 $self->_store_title_text_stream();
855             }
856              
857 2         1056 $self->_store_end();
858              
859             }
860              
861              
862             ###############################################################################
863             #
864             # _store_series_stream()
865             #
866             # Write the SERIES chart substream.
867             #
868             sub _store_series_stream {
869              
870 0     0   0 my $self = shift;
871 0         0 my %arg = @_;
872              
873 0 0       0 my $name_type = $arg{_name_formula} ? 2 : 1;
874 0 0       0 my $value_type = $arg{_value_formula} ? 2 : 0;
875 0 0       0 my $category_type = $arg{_category_formula} ? 2 : 0;
876              
877 0         0 $self->_store_series( $arg{_value_count}, $arg{_category_count} );
878              
879 0         0 $self->_store_begin();
880              
881             # Store the Series name AI record.
882 0         0 $self->_store_ai( 0, $name_type, $arg{_name_formula} );
883 0 0       0 if ( defined $arg{_name} ) {
884 0         0 $self->_store_seriestext( $arg{_name}, $arg{_name_encoding} );
885             }
886              
887 0         0 $self->_store_ai( 1, $value_type, $arg{_value_formula} );
888 0         0 $self->_store_ai( 2, $category_type, $arg{_category_formula} );
889 0         0 $self->_store_ai( 3, 1, '' );
890              
891 0         0 $self->_store_dataformat_stream( $arg{_index}, $arg{_index}, 0xFFFF );
892 0         0 $self->_store_sertocrt( 0 );
893 0         0 $self->_store_end();
894             }
895              
896              
897             ###############################################################################
898             #
899             # _store_dataformat_stream()
900             #
901             # Write the DATAFORMAT chart substream.
902             #
903             sub _store_dataformat_stream {
904              
905 0     0   0 my $self = shift;
906              
907 0         0 my $series_index = shift;
908              
909 0         0 $self->_store_dataformat( $series_index, $series_index, 0xFFFF );
910              
911 0         0 $self->_store_begin();
912 0         0 $self->_store_3dbarshape();
913 0         0 $self->_store_end();
914             }
915              
916              
917             ###############################################################################
918             #
919             # _store_series_text_stream()
920             #
921             # Write the series TEXT substream.
922             #
923             sub _store_series_text_stream {
924              
925 4     4   7 my $self = shift;
926              
927 4         7 my $font_index = shift;
928              
929 4         6 $self->_store_text( @{ $self->{_config}->{_series_text} } );
  4         30  
930              
931 4         13 $self->_store_begin();
932 4         7 $self->_store_pos( @{ $self->{_config}->{_series_text_pos} } );
  4         29  
933 4         114 $self->_store_fontx( $font_index );
934 4         23 $self->_store_ai( 0, 1, '' );
935 4         18 $self->_store_end();
936             }
937              
938              
939             ###############################################################################
940             #
941             # _store_x_axis_text_stream()
942             #
943             # Write the X-axis TEXT substream.
944             #
945             sub _store_x_axis_text_stream {
946              
947 0     0   0 my $self = shift;
948              
949 0         0 my $formula = $self->{_x_axis_formula};
950 0 0       0 my $ai_type = $formula ? 2 : 1;
951              
952 0         0 $self->_store_text( @{ $self->{_config}->{_x_axis_text} } );
  0         0  
953              
954 0         0 $self->_store_begin();
955 0         0 $self->_store_pos( @{ $self->{_config}->{_x_axis_text_pos} } );
  0         0  
956 0         0 $self->_store_fontx( 8 );
957 0         0 $self->_store_ai( 0, $ai_type, $formula );
958              
959 0 0       0 if ( defined $self->{_x_axis_name} ) {
960 0         0 $self->_store_seriestext( $self->{_x_axis_name},
961             $self->{_x_axis_encoding},
962             );
963             }
964              
965 0         0 $self->_store_objectlink( 3 );
966 0         0 $self->_store_end();
967             }
968              
969              
970             ###############################################################################
971             #
972             # _store_y_axis_text_stream()
973             #
974             # Write the Y-axis TEXT substream.
975             #
976             sub _store_y_axis_text_stream {
977              
978 0     0   0 my $self = shift;
979              
980 0         0 my $formula = $self->{_y_axis_formula};
981 0 0       0 my $ai_type = $formula ? 2 : 1;
982              
983 0         0 $self->_store_text( @{ $self->{_config}->{_y_axis_text} } );
  0         0  
984              
985 0         0 $self->_store_begin();
986 0         0 $self->_store_pos( @{ $self->{_config}->{_y_axis_text_pos} } );
  0         0  
987 0         0 $self->_store_fontx( 8 );
988 0         0 $self->_store_ai( 0, $ai_type, $formula );
989              
990 0 0       0 if ( defined $self->{_y_axis_name} ) {
991 0         0 $self->_store_seriestext( $self->{_y_axis_name},
992             $self->{_y_axis_encoding},
993             );
994             }
995              
996 0         0 $self->_store_objectlink( 2 );
997 0         0 $self->_store_end();
998             }
999              
1000              
1001             ###############################################################################
1002             #
1003             # _store_legend_text_stream()
1004             #
1005             # Write the legend TEXT substream.
1006             #
1007             sub _store_legend_text_stream {
1008              
1009 2     2   5 my $self = shift;
1010              
1011 2         4 $self->_store_text( @{ $self->{_config}->{_legend_text} } );
  2         11  
1012              
1013 2         9 $self->_store_begin();
1014 2         4 $self->_store_pos( @{ $self->{_config}->{_legend_text_pos} } );
  2         10  
1015 2         9 $self->_store_ai( 0, 1, '' );
1016              
1017 2         11 $self->_store_end();
1018             }
1019              
1020              
1021             ###############################################################################
1022             #
1023             # _store_title_text_stream()
1024             #
1025             # Write the title TEXT substream.
1026             #
1027             sub _store_title_text_stream {
1028              
1029 0     0   0 my $self = shift;
1030              
1031 0         0 my $formula = $self->{_title_formula};
1032 0 0       0 my $ai_type = $formula ? 2 : 1;
1033              
1034 0         0 $self->_store_text( @{ $self->{_config}->{_title_text} } );
  0         0  
1035              
1036 0         0 $self->_store_begin();
1037 0         0 $self->_store_pos( @{ $self->{_config}->{_title_text_pos} } );
  0         0  
1038 0         0 $self->_store_fontx( 7 );
1039 0         0 $self->_store_ai( 0, $ai_type, $formula );
1040              
1041 0 0       0 if ( defined $self->{_title_name} ) {
1042 0         0 $self->_store_seriestext( $self->{_title_name},
1043             $self->{_title_encoding},
1044             );
1045             }
1046              
1047 0         0 $self->_store_objectlink( 1 );
1048 0         0 $self->_store_end();
1049             }
1050              
1051              
1052             ###############################################################################
1053             #
1054             # _store_axisparent_stream()
1055             #
1056             # Write the AXISPARENT chart substream.
1057             #
1058             sub _store_axisparent_stream {
1059              
1060 2     2   4 my $self = shift;
1061              
1062 2         6 $self->_store_axisparent( @{ $self->{_config}->{_axisparent} } );
  2         21  
1063              
1064 2         7 $self->_store_begin();
1065 2         4 $self->_store_pos( @{ $self->{_config}->{_axisparent_pos} } );
  2         12  
1066 2         23 $self->_store_axis_category_stream();
1067 2         17 $self->_store_axis_values_stream();
1068              
1069 2 50 33     41 if ( defined $self->{_x_axis_name} || defined $self->{_x_axis_formula} ) {
1070 0         0 $self->_store_x_axis_text_stream();
1071             }
1072              
1073 2 50 33     21 if ( defined $self->{_y_axis_name} || defined $self->{_y_axis_formula} ) {
1074 0         0 $self->_store_y_axis_text_stream();
1075             }
1076              
1077 2 50       27 if ( $self->{_plotarea}->{_visible} ) {
1078 2         22 $self->_store_plotarea();
1079 2         10 $self->_store_plotarea_frame_stream();
1080             }
1081              
1082 2         26 $self->_store_chartformat_stream();
1083 2         5 $self->_store_end();
1084             }
1085              
1086              
1087             ###############################################################################
1088             #
1089             # _store_axis_category_stream()
1090             #
1091             # Write the AXIS chart substream for the chart category.
1092             #
1093             sub _store_axis_category_stream {
1094              
1095 2     2   6 my $self = shift;
1096              
1097 2         36 $self->_store_axis( 0 );
1098              
1099 2         7 $self->_store_begin();
1100 2         22 $self->_store_catserrange();
1101 2         19 $self->_store_axcext();
1102 2         17 $self->_store_tick();
1103 2         7 $self->_store_end();
1104             }
1105              
1106              
1107             ###############################################################################
1108             #
1109             # _store_axis_values_stream()
1110             #
1111             # Write the AXIS chart substream for the chart values.
1112             #
1113             sub _store_axis_values_stream {
1114              
1115 2     2   5 my $self = shift;
1116              
1117 2         7 $self->_store_axis( 1 );
1118              
1119 2         8 $self->_store_begin();
1120 2         16 $self->_store_valuerange();
1121 2         7 $self->_store_tick();
1122 2         19 $self->_store_axislineformat();
1123 2         14 $self->_store_lineformat( 0x00000000, 0x0000, 0xFFFF, 0x0009, 0x004D );
1124 2         7 $self->_store_end();
1125             }
1126              
1127              
1128             ###############################################################################
1129             #
1130             # _store_plotarea_frame_stream()
1131             #
1132             # Write the FRAME chart substream for the plotarea.
1133             #
1134             sub _store_plotarea_frame_stream {
1135              
1136 11     11   165 my $self = shift;
1137              
1138 11         21 my $area = $self->{_plotarea};
1139              
1140 11         32 $self->_store_frame( 0x00, 0x03 );
1141 11         33 $self->_store_begin();
1142              
1143 11         52 $self->_store_lineformat(
1144             $area->{_line_color_rgb}, $area->{_line_pattern},
1145             $area->{_line_weight}, $area->{_line_options},
1146             $area->{_line_color_index}
1147             );
1148              
1149 11         54 $self->_store_areaformat(
1150             $area->{_fg_color_rgb}, $area->{_bg_color_rgb},
1151             $area->{_area_pattern}, $area->{_area_options},
1152             $area->{_fg_color_index}, $area->{_bg_color_index}
1153             );
1154              
1155 11         27 $self->_store_end();
1156             }
1157              
1158              
1159             ###############################################################################
1160             #
1161             # _store_chartarea_frame_stream()
1162             #
1163             # Write the FRAME chart substream for the chartarea.
1164             #
1165             sub _store_chartarea_frame_stream {
1166              
1167 17     17   260 my $self = shift;
1168              
1169 17         34 my $area = $self->{_chartarea};
1170              
1171 17         47 $self->_store_frame( 0x00, 0x02 );
1172 17         46 $self->_store_begin();
1173              
1174 17         76 $self->_store_lineformat(
1175             $area->{_line_color_rgb}, $area->{_line_pattern},
1176             $area->{_line_weight}, $area->{_line_options},
1177             $area->{_line_color_index}
1178             );
1179              
1180 17         69 $self->_store_areaformat(
1181             $area->{_fg_color_rgb}, $area->{_bg_color_rgb},
1182             $area->{_area_pattern}, $area->{_area_options},
1183             $area->{_fg_color_index}, $area->{_bg_color_index}
1184             );
1185              
1186 17         49 $self->_store_end();
1187             }
1188              
1189             ###############################################################################
1190             #
1191             # _store_chartformat_stream()
1192             #
1193             # Write the CHARTFORMAT chart substream.
1194             #
1195             sub _store_chartformat_stream {
1196              
1197 2     2   3 my $self = shift;
1198              
1199             # The _vary_data_color is set by classes that need it, like Pie.
1200 2         22 $self->_store_chartformat( $self->{_vary_data_color} );
1201              
1202 2         12 $self->_store_begin();
1203              
1204             # Store the BIFF record that will define the chart type.
1205 2         12 $self->_store_chart_type();
1206              
1207             # Note, the CHARTFORMATLINK record is only written by Excel.
1208              
1209 2 50       12 if ( $self->{_legend}->{_visible} ) {
1210 2         17 $self->_store_legend_stream();
1211             }
1212              
1213 2         19 $self->_store_marker_dataformat_stream();
1214 2         6 $self->_store_end();
1215             }
1216              
1217              
1218             ###############################################################################
1219             #
1220             # _store_chart_type()
1221             #
1222             # This is an abstract method that is overridden by the sub-classes to define
1223             # the chart types such as Column, Line, Pie, etc.
1224             #
1225 0     0   0 sub _store_chart_type {
1226              
1227             }
1228              
1229              
1230             ###############################################################################
1231             #
1232             # _store_marker_dataformat_stream()
1233             #
1234             # This is an abstract method that is overridden by the sub-classes to define
1235             # properties of markers, linetypes, pie formats and other.
1236             #
1237 2     2   5 sub _store_marker_dataformat_stream {
1238              
1239             }
1240              
1241              
1242             ###############################################################################
1243             #
1244             # _store_legend_stream()
1245             #
1246             # Write the LEGEND chart substream.
1247             #
1248             sub _store_legend_stream {
1249              
1250 2     2   5 my $self = shift;
1251              
1252 2         13 $self->_store_legend( @{ $self->{_config}->{_legend} } );
  2         20  
1253              
1254 2         8 $self->_store_begin();
1255 2         4 $self->_store_pos( @{ $self->{_config}->{_legend_pos} } );
  2         11  
1256 2         23 $self->_store_legend_text_stream();
1257 2         8 $self->_store_end();
1258             }
1259              
1260              
1261             ###############################################################################
1262             #
1263             # BIFF Records.
1264             #
1265             ###############################################################################
1266              
1267              
1268             ###############################################################################
1269             #
1270             # _store_3dbarshape()
1271             #
1272             # Write the 3DBARSHAPE chart BIFF record.
1273             #
1274             sub _store_3dbarshape {
1275              
1276 1     1   2251 my $self = shift;
1277              
1278 1         3 my $record = 0x105F; # Record identifier.
1279 1         2 my $length = 0x0002; # Number of bytes to follow.
1280 1         2 my $riser = 0x00; # Shape of base.
1281 1         3 my $taper = 0x00; # Column taper type.
1282              
1283 1         4 my $header = pack 'vv', $record, $length;
1284 1         4 my $data = '';
1285 1         4 $data .= pack 'C', $riser;
1286 1         2 $data .= pack 'C', $taper;
1287              
1288 1         6 $self->_append( $header, $data );
1289             }
1290              
1291              
1292             ###############################################################################
1293             #
1294             # _store_ai()
1295             #
1296             # Write the AI chart BIFF record.
1297             #
1298             sub _store_ai {
1299              
1300 8     8   2740 my $self = shift;
1301              
1302 8         14 my $record = 0x1051; # Record identifier.
1303 8         13 my $length = 0x0008; # Number of bytes to follow.
1304 8         12 my $id = $_[0]; # Link index.
1305 8         20 my $type = $_[1]; # Reference type.
1306 8         14 my $formula = $_[2]; # Pre-parsed formula.
1307 8   50     69 my $format_index = $_[3] || 0; # Num format index.
1308 8         43 my $grbit = 0x0000; # Option flags.
1309              
1310 8         15 my $formula_length = length $formula;
1311              
1312 8         13 $length += $formula_length;
1313              
1314 8         27 my $header = pack 'vv', $record, $length;
1315 8         12 my $data = '';
1316 8         21 $data .= pack 'C', $id;
1317 8         15 $data .= pack 'C', $type;
1318 8         14 $data .= pack 'v', $grbit;
1319 8         144 $data .= pack 'v', $format_index;
1320 8         13 $data .= pack 'v', $formula_length;
1321 8         22 $data .= $formula;
1322              
1323 8         31 $self->_append( $header, $data );
1324             }
1325              
1326              
1327             ###############################################################################
1328             #
1329             # _store_areaformat()
1330             #
1331             # Write the AREAFORMAT chart BIFF record. Contains the patterns and colours
1332             # of a chart area.
1333             #
1334             sub _store_areaformat {
1335              
1336 29     29   460 my $self = shift;
1337              
1338 29         187 my $record = 0x100A; # Record identifier.
1339 29         33 my $length = 0x0010; # Number of bytes to follow.
1340 29         35 my $rgbFore = $_[0]; # Foreground RGB colour.
1341 29         38 my $rgbBack = $_[1]; # Background RGB colour.
1342 29         40 my $pattern = $_[2]; # Pattern.
1343 29         35 my $grbit = $_[3]; # Option flags.
1344 29         34 my $indexFore = $_[4]; # Index to Foreground colour.
1345 29         36 my $indexBack = $_[5]; # Index to Background colour.
1346              
1347 29         56 my $header = pack 'vv', $record, $length;
1348 29         36 my $data = '';
1349 29         51 $data .= pack 'V', $rgbFore;
1350 29         44 $data .= pack 'V', $rgbBack;
1351 29         50 $data .= pack 'v', $pattern;
1352 29         45 $data .= pack 'v', $grbit;
1353 29         44 $data .= pack 'v', $indexFore;
1354 29         43 $data .= pack 'v', $indexBack;
1355              
1356 29         91 $self->_append( $header, $data );
1357             }
1358              
1359              
1360             ###############################################################################
1361             #
1362             # _store_axcext()
1363             #
1364             # Write the AXCEXT chart BIFF record.
1365             #
1366             sub _store_axcext {
1367              
1368 3     3   4297 my $self = shift;
1369              
1370 3         10 my $record = 0x1062; # Record identifier.
1371 3         6 my $length = 0x0012; # Number of bytes to follow.
1372 3         7 my $catMin = 0x0000; # Minimum category on axis.
1373 3         5 my $catMax = 0x0000; # Maximum category on axis.
1374 3         6 my $catMajor = 0x0001; # Value of major unit.
1375 3         5 my $unitMajor = 0x0000; # Units of major unit.
1376 3         7 my $catMinor = 0x0001; # Value of minor unit.
1377 3         6 my $unitMinor = 0x0000; # Units of minor unit.
1378 3         7 my $unitBase = 0x0000; # Base unit of axis.
1379 3         5 my $catCrossDate = 0x0000; # Crossing point.
1380 3         7 my $grbit = 0x00EF; # Option flags.
1381              
1382 3         17 my $header = pack 'vv', $record, $length;
1383 3         8 my $data = '';
1384 3         10 $data .= pack 'v', $catMin;
1385 3         8 $data .= pack 'v', $catMax;
1386 3         8 $data .= pack 'v', $catMajor;
1387 3         8 $data .= pack 'v', $unitMajor;
1388 3         12 $data .= pack 'v', $catMinor;
1389 3         6 $data .= pack 'v', $unitMinor;
1390 3         8 $data .= pack 'v', $unitBase;
1391 3         8 $data .= pack 'v', $catCrossDate;
1392 3         17 $data .= pack 'v', $grbit;
1393              
1394 3         16 $self->_append( $header, $data );
1395             }
1396              
1397              
1398             ###############################################################################
1399             #
1400             # _store_axesused()
1401             #
1402             # Write the AXESUSED chart BIFF record.
1403             #
1404             sub _store_axesused {
1405              
1406 3     3   640 my $self = shift;
1407              
1408 3         6 my $record = 0x1046; # Record identifier.
1409 3         7 my $length = 0x0002; # Number of bytes to follow.
1410 3         6 my $num_axes = $_[0]; # Number of axes used.
1411              
1412 3         12 my $header = pack 'vv', $record, $length;
1413 3         111 my $data = pack 'v', $num_axes;
1414              
1415 3         15 $self->_append( $header, $data );
1416             }
1417              
1418              
1419             ###############################################################################
1420             #
1421             # _store_axis()
1422             #
1423             # Write the AXIS chart BIFF record to define the axis type.
1424             #
1425             sub _store_axis {
1426              
1427 5     5   728 my $self = shift;
1428              
1429 5         9 my $record = 0x101D; # Record identifier.
1430 5         7 my $length = 0x0012; # Number of bytes to follow.
1431 5         8 my $type = $_[0]; # Axis type.
1432 5         8 my $reserved1 = 0x00000000; # Reserved.
1433 5         8 my $reserved2 = 0x00000000; # Reserved.
1434 5         8 my $reserved3 = 0x00000000; # Reserved.
1435 5         8 my $reserved4 = 0x00000000; # Reserved.
1436              
1437 5         14 my $header = pack 'vv', $record, $length;
1438 5         7 my $data = '';
1439 5         12 $data .= pack 'v', $type;
1440 5         12 $data .= pack 'V', $reserved1;
1441 5         9 $data .= pack 'V', $reserved2;
1442 5         11 $data .= pack 'V', $reserved3;
1443 5         9 $data .= pack 'V', $reserved4;
1444              
1445 5         18 $self->_append( $header, $data );
1446             }
1447              
1448              
1449             ###############################################################################
1450             #
1451             # _store_axislineformat()
1452             #
1453             # Write the AXISLINEFORMAT chart BIFF record.
1454             #
1455             sub _store_axislineformat {
1456              
1457 3     3   449 my $self = shift;
1458              
1459 3         8 my $record = 0x1021; # Record identifier.
1460 3         6 my $length = 0x0002; # Number of bytes to follow.
1461 3         6 my $line_format = 0x0001; # Axis line format.
1462              
1463 3         10 my $header = pack 'vv', $record, $length;
1464 3         8 my $data = pack 'v', $line_format;
1465              
1466 3         13 $self->_append( $header, $data );
1467             }
1468              
1469              
1470             ###############################################################################
1471             #
1472             # _store_axisparent()
1473             #
1474             # Write the AXISPARENT chart BIFF record.
1475             #
1476             sub _store_axisparent {
1477              
1478 3     3   763 my $self = shift;
1479              
1480 3         7 my $record = 0x1041; # Record identifier.
1481 3         5 my $length = 0x0012; # Number of bytes to follow.
1482 3         5 my $iax = $_[0]; # Axis index.
1483 3         8 my $x = $_[1]; # X-coord.
1484 3         12 my $y = $_[2]; # Y-coord.
1485 3         5 my $dx = $_[3]; # Length of x axis.
1486 3         6 my $dy = $_[4]; # Length of y axis.
1487              
1488 3         10 my $header = pack 'vv', $record, $length;
1489 3         6 my $data = '';
1490 3         10 $data .= pack 'v', $iax;
1491 3         17 $data .= pack 'V', $x;
1492 3         16 $data .= pack 'V', $y;
1493 3         14 $data .= pack 'V', $dx;
1494 3         9 $data .= pack 'V', $dy;
1495              
1496 3         18 $self->_append( $header, $data );
1497             }
1498              
1499              
1500             ###############################################################################
1501             #
1502             # _store_begin()
1503             #
1504             # Write the BEGIN chart BIFF record to indicate the start of a sub stream.
1505             #
1506             sub _store_begin {
1507              
1508 47     47   1526 my $self = shift;
1509              
1510 47         62 my $record = 0x1033; # Record identifier.
1511 47         52 my $length = 0x0000; # Number of bytes to follow.
1512              
1513 47         170 my $header = pack 'vv', $record, $length;
1514              
1515 47         159 $self->_append( $header );
1516             }
1517              
1518              
1519             ###############################################################################
1520             #
1521             # _store_catserrange()
1522             #
1523             # Write the CATSERRANGE chart BIFF record.
1524             #
1525             sub _store_catserrange {
1526              
1527 3     3   981 my $self = shift;
1528              
1529 3         7 my $record = 0x1020; # Record identifier.
1530 3         7 my $length = 0x0008; # Number of bytes to follow.
1531 3         5 my $catCross = 0x0001; # Value/category crossing.
1532 3         7 my $catLabel = 0x0001; # Frequency of labels.
1533 3         8 my $catMark = 0x0001; # Frequency of ticks.
1534 3         16 my $grbit = 0x0001; # Option flags.
1535              
1536 3         12 my $header = pack 'vv', $record, $length;
1537 3         6 my $data = '';
1538 3         9 $data .= pack 'v', $catCross;
1539 3         9 $data .= pack 'v', $catLabel;
1540 3         8 $data .= pack 'v', $catMark;
1541 3         7 $data .= pack 'v', $grbit;
1542              
1543 3         42 $self->_append( $header, $data );
1544             }
1545              
1546              
1547             ###############################################################################
1548             #
1549             # _store_chart()
1550             #
1551             # Write the CHART BIFF record. This indicates the start of the chart sub-stream
1552             # and contains dimensions of the chart on the display. Units are in 1/72 inch
1553             # and are 2 byte integer with 2 byte fraction.
1554             #
1555             sub _store_chart {
1556              
1557 3     3   640 my $self = shift;
1558              
1559 3         6 my $record = 0x1002; # Record identifier.
1560 3         7 my $length = 0x0010; # Number of bytes to follow.
1561 3         7 my $x_pos = $_[0]; # X pos of top left corner.
1562 3         11 my $y_pos = $_[1]; # Y pos of top left corner.
1563 3         7 my $dx = $_[2]; # X size.
1564 3         3 my $dy = $_[3]; # Y size.
1565              
1566 3         12 my $header = pack 'vv', $record, $length;
1567 3         6 my $data = '';
1568 3         10 $data .= pack 'V', $x_pos;
1569 3         10 $data .= pack 'V', $y_pos;
1570 3         9 $data .= pack 'V', $dx;
1571 3         7 $data .= pack 'V', $dy;
1572              
1573 3         12 $self->_append( $header, $data );
1574             }
1575              
1576              
1577             ###############################################################################
1578             #
1579             # _store_chartformat()
1580             #
1581             # Write the CHARTFORMAT chart BIFF record. The parent record for formatting
1582             # of a chart group.
1583             #
1584             sub _store_chartformat {
1585              
1586 3     3   408 my $self = shift;
1587              
1588 3         7 my $record = 0x1014; # Record identifier.
1589 3         5 my $length = 0x0014; # Number of bytes to follow.
1590 3         6 my $reserved1 = 0x00000000; # Reserved.
1591 3         6 my $reserved2 = 0x00000000; # Reserved.
1592 3         5 my $reserved3 = 0x00000000; # Reserved.
1593 3         6 my $reserved4 = 0x00000000; # Reserved.
1594 3   50     39 my $grbit = $_[0] || 0; # Option flags.
1595 3         15 my $icrt = 0x0000; # Drawing order.
1596              
1597 3         12 my $header = pack 'vv', $record, $length;
1598 3         14 my $data = '';
1599 3         9 $data .= pack 'V', $reserved1;
1600 3         7 $data .= pack 'V', $reserved2;
1601 3         10 $data .= pack 'V', $reserved3;
1602 3         10 $data .= pack 'V', $reserved4;
1603 3         8 $data .= pack 'v', $grbit;
1604 3         10 $data .= pack 'v', $icrt;
1605              
1606 3         13 $self->_append( $header, $data );
1607             }
1608              
1609              
1610             ###############################################################################
1611             #
1612             # _store_chartline()
1613             #
1614             # Write the CHARTLINE chart BIFF record.
1615             #
1616             sub _store_chartline {
1617              
1618 1     1   452 my $self = shift;
1619              
1620 1         3 my $record = 0x101C; # Record identifier.
1621 1         3 my $length = 0x0002; # Number of bytes to follow.
1622 1         2 my $type = 0x0001; # Drop/hi-lo line type.
1623              
1624 1         3 my $header = pack 'vv', $record, $length;
1625 1         5 my $data = pack 'v', $type;
1626              
1627 1         5 $self->_append( $header, $data );
1628             }
1629              
1630              
1631             ###############################################################################
1632             #
1633             # _store_charttext()
1634             #
1635             # Write the TEXT chart BIFF record.
1636             #
1637             sub _store_charttext {
1638              
1639 1     1   963 my $self = shift;
1640              
1641 1         4 my $record = 0x1025; # Record identifier.
1642 1         2 my $length = 0x0020; # Number of bytes to follow.
1643 1         2 my $horz_align = 0x02; # Horizontal alignment.
1644 1         3 my $vert_align = 0x02; # Vertical alignment.
1645 1         3 my $bg_mode = 0x0001; # Background display.
1646 1         2 my $text_color_rgb = 0x00000000; # Text RGB colour.
1647 1         2 my $text_x = 0xFFFFFF46; # Text x-pos.
1648 1         4 my $text_y = 0xFFFFFF06; # Text y-pos.
1649 1         1 my $text_dx = 0x00000000; # Width.
1650 1         3 my $text_dy = 0x00000000; # Height.
1651 1         1 my $grbit1 = 0x00B1; # Options
1652 1         4 my $text_color_index = 0x004D; # Auto Colour.
1653 1         2 my $grbit2 = 0x0000; # Data label placement.
1654 1         3 my $rotation = 0x0000; # Text rotation.
1655              
1656 1         4 my $header = pack 'vv', $record, $length;
1657 1         3 my $data = '';
1658 1         3 $data .= pack 'C', $horz_align;
1659 1         3 $data .= pack 'C', $vert_align;
1660 1         3 $data .= pack 'v', $bg_mode;
1661 1         3 $data .= pack 'V', $text_color_rgb;
1662 1         3 $data .= pack 'V', $text_x;
1663 1         3 $data .= pack 'V', $text_y;
1664 1         3 $data .= pack 'V', $text_dx;
1665 1         3 $data .= pack 'V', $text_dy;
1666 1         2 $data .= pack 'v', $grbit1;
1667 1         2 $data .= pack 'v', $text_color_index;
1668 1         3 $data .= pack 'v', $grbit2;
1669 1         2 $data .= pack 'v', $rotation;
1670              
1671 1         5 $self->_append( $header, $data );
1672             }
1673              
1674              
1675             ###############################################################################
1676             #
1677             # _store_dataformat()
1678             #
1679             # Write the DATAFORMAT chart BIFF record. This record specifies the series
1680             # that the subsequent sub stream refers to.
1681             #
1682             sub _store_dataformat {
1683              
1684 2     2   3480 my $self = shift;
1685              
1686 2         110 my $record = 0x1006; # Record identifier.
1687 2         5 my $length = 0x0008; # Number of bytes to follow.
1688 2         3 my $series_index = $_[0]; # Series index.
1689 2         3 my $series_number = $_[1]; # Series number. (Same as index).
1690 2         4 my $point_number = $_[2]; # Point number.
1691 2         3 my $grbit = 0x0000; # Format flags.
1692              
1693 2         8 my $header = pack 'vv', $record, $length;
1694 2         398 my $data = '';
1695 2         6 $data .= pack 'v', $point_number;
1696 2         5 $data .= pack 'v', $series_index;
1697 2         4 $data .= pack 'v', $series_number;
1698 2         3 $data .= pack 'v', $grbit;
1699              
1700 2         9 $self->_append( $header, $data );
1701             }
1702              
1703              
1704             ###############################################################################
1705             #
1706             # _store_defaulttext()
1707             #
1708             # Write the DEFAULTTEXT chart BIFF record. Identifier for subsequent TEXT
1709             # record.
1710             #
1711             sub _store_defaulttext {
1712              
1713 5     5   1431 my $self = shift;
1714              
1715 5         9 my $record = 0x1024; # Record identifier.
1716 5         9 my $length = 0x0002; # Number of bytes to follow.
1717 5         9 my $type = 0x0002; # Type.
1718              
1719 5         22 my $header = pack 'vv', $record, $length;
1720 5         10 my $data = pack 'v', $type;
1721              
1722 5         26 $self->_append( $header, $data );
1723             }
1724              
1725              
1726             ###############################################################################
1727             #
1728             # _store_dropbar()
1729             #
1730             # Write the DROPBAR chart BIFF record.
1731             #
1732             sub _store_dropbar {
1733              
1734 1     1   577 my $self = shift;
1735              
1736 1         3 my $record = 0x103D; # Record identifier.
1737 1         2 my $length = 0x0002; # Number of bytes to follow.
1738 1         3 my $percent_gap = 0x0096; # Drop bar width gap (%).
1739              
1740 1         4 my $header = pack 'vv', $record, $length;
1741 1         3 my $data = pack 'v', $percent_gap;
1742              
1743 1         7 $self->_append( $header, $data );
1744             }
1745              
1746              
1747             ###############################################################################
1748             #
1749             # _store_end()
1750             #
1751             # Write the END chart BIFF record to indicate the end of a sub stream.
1752             #
1753             sub _store_end {
1754              
1755 47     47   1089 my $self = shift;
1756              
1757 47         172 my $record = 0x1034; # Record identifier.
1758 47         51 my $length = 0x0000; # Number of bytes to follow.
1759              
1760 47         100 my $header = pack 'vv', $record, $length;
1761              
1762 47         135 $self->_append( $header );
1763             }
1764              
1765              
1766             ###############################################################################
1767             #
1768             # _store_fbi()
1769             #
1770             # Write the FBI chart BIFF record. Specifies the font information at the time
1771             # it was applied to the chart.
1772             #
1773             sub _store_fbi {
1774              
1775 10     10   1031 my $self = shift;
1776              
1777 10         14 my $record = 0x1060; # Record identifier.
1778 10         13 my $length = 0x000A; # Number of bytes to follow.
1779 10         12 my $index = $_[0]; # Font index.
1780 10         14 my $height = $_[1] * 20; # Default font height in twips.
1781 10         21 my $width_basis = $_[2]; # Width basis, in twips.
1782 10         11 my $height_basis = $_[3]; # Height basis, in twips.
1783 10         13 my $scale_basis = $_[4]; # Scale by chart area or plot area.
1784              
1785 10         24 my $header = pack 'vv', $record, $length;
1786 10         21 my $data = '';
1787 10         21 $data .= pack 'v', $width_basis;
1788 10         14 $data .= pack 'v', $height_basis;
1789 10         15 $data .= pack 'v', $height;
1790 10         16 $data .= pack 'v', $scale_basis;
1791 10         15 $data .= pack 'v', $index;
1792              
1793 10         41 $self->_append( $header, $data );
1794             }
1795              
1796              
1797             ###############################################################################
1798             #
1799             # _store_fontx()
1800             #
1801             # Write the FONTX chart BIFF record which contains the index of the FONT
1802             # record in the Workbook.
1803             #
1804             sub _store_fontx {
1805              
1806 5     5   1039 my $self = shift;
1807              
1808 5         9 my $record = 0x1026; # Record identifier.
1809 5         262 my $length = 0x0002; # Number of bytes to follow.
1810 5         11 my $index = $_[0]; # Font index.
1811              
1812 5         14 my $header = pack 'vv', $record, $length;
1813 5         12 my $data = pack 'v', $index;
1814              
1815 5         88 $self->_append( $header, $data );
1816             }
1817              
1818              
1819             ###############################################################################
1820             #
1821             # _store_frame()
1822             #
1823             # Write the FRAME chart BIFF record.
1824             #
1825             sub _store_frame {
1826              
1827 29     29   802 my $self = shift;
1828              
1829 29         35 my $record = 0x1032; # Record identifier.
1830 29         34 my $length = 0x0004; # Number of bytes to follow.
1831 29         42 my $frame_type = $_[0]; # Frame type.
1832 29         44 my $grbit = $_[1]; # Option flags.
1833              
1834 29         74 my $header = pack 'vv', $record, $length;
1835 29         41 my $data = '';
1836 29         54 $data .= pack 'v', $frame_type;
1837 29         52 $data .= pack 'v', $grbit;
1838              
1839 29         147 $self->_append( $header, $data );
1840             }
1841              
1842              
1843             ###############################################################################
1844             #
1845             # _store_legend()
1846             #
1847             # Write the LEGEND chart BIFF record. The Marcus Horan method.
1848             #
1849             sub _store_legend {
1850              
1851 3     3   393 my $self = shift;
1852              
1853 3         14 my $record = 0x1015; # Record identifier.
1854 3         4 my $length = 0x0014; # Number of bytes to follow.
1855 3         8 my $x = $_[0]; # X-position.
1856 3         6 my $y = $_[1]; # Y-position.
1857 3         6 my $width = $_[2]; # Width.
1858 3         5 my $height = $_[3]; # Height.
1859 3         7 my $wType = $_[4]; # Type.
1860 3         7 my $wSpacing = $_[5]; # Spacing.
1861 3         6 my $grbit = $_[6]; # Option flags.
1862              
1863 3         11 my $header = pack 'vv', $record, $length;
1864 3         8 my $data = '';
1865 3         8 $data .= pack 'V', $x;
1866 3         8 $data .= pack 'V', $y;
1867 3         6 $data .= pack 'V', $width;
1868 3         8 $data .= pack 'V', $height;
1869 3         8 $data .= pack 'C', $wType;
1870 3         6 $data .= pack 'C', $wSpacing;
1871 3         14 $data .= pack 'v', $grbit;
1872              
1873 3         12 $self->_append( $header, $data );
1874             }
1875              
1876              
1877             ###############################################################################
1878             #
1879             # _store_lineformat()
1880             #
1881             # Write the LINEFORMAT chart BIFF record.
1882             #
1883             sub _store_lineformat {
1884              
1885 31     31   425 my $self = shift;
1886              
1887 31         43 my $record = 0x1007; # Record identifier.
1888 31         38 my $length = 0x000C; # Number of bytes to follow.
1889 31         40 my $rgb = $_[0]; # Line RGB colour.
1890 31         38 my $lns = $_[1]; # Line pattern.
1891 31         35 my $we = $_[2]; # Line weight.
1892 31         39 my $grbit = $_[3]; # Option flags.
1893 31         38 my $index = $_[4]; # Index to colour of line.
1894              
1895 31         95 my $header = pack 'vv', $record, $length;
1896 31         48 my $data = '';
1897 31         61 $data .= pack 'V', $rgb;
1898 31         47 $data .= pack 'v', $lns;
1899 31         46 $data .= pack 'v', $we;
1900 31         42 $data .= pack 'v', $grbit;
1901 31         43 $data .= pack 'v', $index;
1902              
1903 31         93 $self->_append( $header, $data );
1904             }
1905              
1906              
1907             ###############################################################################
1908             #
1909             # _store_markerformat()
1910             #
1911             # Write the MARKERFORMAT chart BIFF record.
1912             #
1913             sub _store_markerformat {
1914              
1915 1     1   676 my $self = shift;
1916              
1917 1         2 my $record = 0x1009; # Record identifier.
1918 1         4 my $length = 0x0014; # Number of bytes to follow.
1919 1         3 my $rgbFore = $_[0]; # Foreground RGB color.
1920 1         2 my $rgbBack = $_[1]; # Background RGB color.
1921 1         2 my $marker = $_[2]; # Type of marker.
1922 1         2 my $grbit = $_[3]; # Format flags.
1923 1         2 my $icvFore = $_[4]; # Color index marker border.
1924 1         4 my $icvBack = $_[5]; # Color index marker fill.
1925 1         2 my $miSize = $_[6]; # Size of line markers.
1926              
1927 1         5 my $header = pack 'vv', $record, $length;
1928 1         3 my $data = '';
1929 1         3 $data .= pack 'V', $rgbFore;
1930 1         2 $data .= pack 'V', $rgbBack;
1931 1         2 $data .= pack 'v', $marker;
1932 1         3 $data .= pack 'v', $grbit;
1933 1         2 $data .= pack 'v', $icvFore;
1934 1         2 $data .= pack 'v', $icvBack;
1935 1         2 $data .= pack 'V', $miSize;
1936              
1937 1         6 $self->_append( $header, $data );
1938             }
1939              
1940              
1941             ###############################################################################
1942             #
1943             # _store_objectlink()
1944             #
1945             # Write the OBJECTLINK chart BIFF record.
1946             #
1947             sub _store_objectlink {
1948              
1949 1     1   696 my $self = shift;
1950              
1951 1         2 my $record = 0x1027; # Record identifier.
1952 1         3 my $length = 0x0006; # Number of bytes to follow.
1953 1         2 my $link_type = $_[0]; # Object text link type.
1954 1         2 my $link_index1 = 0x0000; # Link index 1.
1955 1         6070 my $link_index2 = 0x0000; # Link index 2.
1956              
1957 1         27 my $header = pack 'vv', $record, $length;
1958 1         4 my $data = '';
1959 1         5 $data .= pack 'v', $link_type;
1960 1         3 $data .= pack 'v', $link_index1;
1961 1         3 $data .= pack 'v', $link_index2;
1962              
1963 1         13 $self->_append( $header, $data );
1964             }
1965              
1966              
1967             ###############################################################################
1968             #
1969             # _store_pieformat()
1970             #
1971             # Write the PIEFORMAT chart BIFF record.
1972             #
1973             sub _store_pieformat {
1974              
1975 1     1   1098 my $self = shift;
1976              
1977 1         4 my $record = 0x100B; # Record identifier.
1978 1         2 my $length = 0x0002; # Number of bytes to follow.
1979 1         2 my $percent = 0x0000; # Distance % from center.
1980              
1981 1         4 my $header = pack 'vv', $record, $length;
1982 1         3 my $data = '';
1983 1         3 $data .= pack 'v', $percent;
1984              
1985 1         5 $self->_append( $header, $data );
1986             }
1987              
1988              
1989             ###############################################################################
1990             #
1991             # _store_plotarea()
1992             #
1993             # Write the PLOTAREA chart BIFF record. This indicates that the subsequent
1994             # FRAME record belongs to a plot area.
1995             #
1996             sub _store_plotarea {
1997              
1998 2     2   5 my $self = shift;
1999              
2000 2         6 my $record = 0x1035; # Record identifier.
2001 2         3 my $length = 0x0000; # Number of bytes to follow.
2002              
2003 2         8 my $header = pack 'vv', $record, $length;
2004              
2005 2         8 $self->_append( $header );
2006             }
2007              
2008              
2009             ###############################################################################
2010             #
2011             # _store_plotgrowth()
2012             #
2013             # Write the PLOTGROWTH chart BIFF record.
2014             #
2015             sub _store_plotgrowth {
2016              
2017 3     3   419 my $self = shift;
2018              
2019 3         6 my $record = 0x1064; # Record identifier.
2020 3         16 my $length = 0x0008; # Number of bytes to follow.
2021 3         7 my $dx_plot = 0x00010000; # Horz growth for font scale.
2022 3         11 my $dy_plot = 0x00010000; # Vert growth for font scale.
2023              
2024 3         9 my $header = pack 'vv', $record, $length;
2025 3         7 my $data = '';
2026 3         9 $data .= pack 'V', $dx_plot;
2027 3         12 $data .= pack 'V', $dy_plot;
2028              
2029 3         19 $self->_append( $header, $data );
2030             }
2031              
2032              
2033             ###############################################################################
2034             #
2035             # _store_pos()
2036             #
2037             # Write the POS chart BIFF record. Generally not required when using
2038             # automatic positioning.
2039             #
2040             sub _store_pos {
2041              
2042 11     11   420 my $self = shift;
2043              
2044 11         18 my $record = 0x104F; # Record identifier.
2045 11         13 my $length = 0x0014; # Number of bytes to follow.
2046 11         15 my $mdTopLt = $_[0]; # Top left.
2047 11         20 my $mdBotRt = $_[1]; # Bottom right.
2048 11         27 my $x1 = $_[2]; # X coordinate.
2049 11         14 my $y1 = $_[3]; # Y coordinate.
2050 11         19 my $x2 = $_[4]; # Width.
2051 11         13 my $y2 = $_[5]; # Height.
2052              
2053 11         28 my $header = pack 'vv', $record, $length;
2054 11         14 my $data = '';
2055 11         22 $data .= pack 'v', $mdTopLt;
2056 11         17 $data .= pack 'v', $mdBotRt;
2057 11         21 $data .= pack 'V', $x1;
2058 11         17 $data .= pack 'V', $y1;
2059 11         19 $data .= pack 'V', $x2;
2060 11         17 $data .= pack 'V', $y2;
2061              
2062 11         34 $self->_append( $header, $data );
2063             }
2064              
2065              
2066             ###############################################################################
2067             #
2068             # _store_serauxtrend()
2069             #
2070             # Write the SERAUXTREND chart BIFF record.
2071             #
2072             sub _store_serauxtrend {
2073              
2074 1     1   455 my $self = shift;
2075              
2076 1         2 my $record = 0x104B; # Record identifier.
2077 1         2 my $length = 0x001C; # Number of bytes to follow.
2078 1         2 my $reg_type = $_[0]; # Regression type.
2079 1         2 my $poly_order = $_[1]; # Polynomial order.
2080 1         3 my $equation = $_[2]; # Display equation.
2081 1         3 my $r_squared = $_[3]; # Display R-squared.
2082 1         2 my $intercept; # Forced intercept.
2083             my $forecast; # Forecast forward.
2084 0         0 my $backcast; # Forecast backward.
2085              
2086             # TODO. When supported, intercept needs to be NAN if not used.
2087             # Also need to reverse doubles.
2088 1         3 $intercept = pack 'H*', 'FFFFFFFF0001FFFF';
2089 1         1 $forecast = pack 'H*', '0000000000000000';
2090 1         2 $backcast = pack 'H*', '0000000000000000';
2091              
2092              
2093 1         4 my $header = pack 'vv', $record, $length;
2094 1         2 my $data = '';
2095 1         4 $data .= pack 'C', $reg_type;
2096 1         3 $data .= pack 'C', $poly_order;
2097 1         1 $data .= $intercept;
2098 1         3 $data .= pack 'C', $equation;
2099 1         4 $data .= pack 'C', $r_squared;
2100 1         2 $data .= $forecast;
2101 1         2 $data .= $backcast;
2102              
2103 1         15 $self->_append( $header, $data );
2104             }
2105              
2106              
2107             ###############################################################################
2108             #
2109             # _store_series()
2110             #
2111             # Write the SERIES chart BIFF record.
2112             #
2113             sub _store_series {
2114              
2115 1     1   1298 my $self = shift;
2116              
2117 1         3 my $record = 0x1003; # Record identifier.
2118 1         3 my $length = 0x000C; # Number of bytes to follow.
2119 1         2 my $category_type = 0x0001; # Type: category.
2120 1         1 my $value_type = 0x0001; # Type: value.
2121 1         2 my $category_count = $_[0]; # Num of categories.
2122 1         3 my $value_count = $_[1]; # Num of values.
2123 1         2 my $bubble_type = 0x0001; # Type: bubble.
2124 1         2 my $bubble_count = 0x0000; # Num of bubble values.
2125              
2126 1         5 my $header = pack 'vv', $record, $length;
2127 1         3 my $data = '';
2128 1         7 $data .= pack 'v', $category_type;
2129 1         18 $data .= pack 'v', $value_type;
2130 1         3 $data .= pack 'v', $category_count;
2131 1         3 $data .= pack 'v', $value_count;
2132 1         3 $data .= pack 'v', $bubble_type;
2133 1         3 $data .= pack 'v', $bubble_count;
2134              
2135 1         8 $self->_append( $header, $data );
2136             }
2137              
2138              
2139             ###############################################################################
2140             #
2141             # _store_seriestext()
2142             #
2143             # Write the SERIESTEXT chart BIFF record.
2144             #
2145             sub _store_seriestext {
2146              
2147 2     2   1479 my $self = shift;
2148              
2149 2         5 my $record = 0x100D; # Record identifier.
2150 2         4 my $length = 0x0000; # Number of bytes to follow.
2151 2         2 my $id = 0x0000; # Text id.
2152 2         4 my $str = $_[0]; # Text.
2153 2         4 my $encoding = $_[1]; # String encoding.
2154 2         4 my $cch = length $str; # String length.
2155              
2156             # Character length is num of chars not num of bytes
2157 2 100       7 $cch /= 2 if $encoding;
2158              
2159             # Change the UTF-16 name from BE to LE
2160 2 100       8 $str = pack 'n*', unpack 'v*', $str if $encoding;
2161              
2162 2         3 $length = 4 + length( $str );
2163              
2164 2         6 my $header = pack 'vv', $record, $length;
2165 2         3 my $data = '';
2166 2         3 $data .= pack 'v', $id;
2167 2         4 $data .= pack 'C', $cch;
2168 2         4 $data .= pack 'C', $encoding;
2169              
2170 2         7 $self->_append( $header, $data, $str );
2171             }
2172              
2173              
2174             ###############################################################################
2175             #
2176             # _store_serparent()
2177             #
2178             # Write the SERPARENT chart BIFF record.
2179             #
2180             sub _store_serparent {
2181              
2182 1     1   580 my $self = shift;
2183              
2184 1         2 my $record = 0x104A; # Record identifier.
2185 1         45 my $length = 0x0002; # Number of bytes to follow.
2186 1         3 my $series = $_[0]; # Series parent.
2187              
2188 1         5 my $header = pack 'vv', $record, $length;
2189 1         2 my $data = pack 'v', $series;
2190              
2191 1         4 $self->_append( $header, $data );
2192             }
2193              
2194              
2195             ###############################################################################
2196             #
2197             # _store_sertocrt()
2198             #
2199             # Write the SERTOCRT chart BIFF record to indicate the chart group index.
2200             #
2201             sub _store_sertocrt {
2202              
2203 1     1   2613 my $self = shift;
2204              
2205 1         3 my $record = 0x1045; # Record identifier.
2206 1         3 my $length = 0x0002; # Number of bytes to follow.
2207 1         3 my $chartgroup = 0x0000; # Chart group index.
2208              
2209 1         5 my $header = pack 'vv', $record, $length;
2210 1         3 my $data = pack 'v', $chartgroup;
2211              
2212 1         72 $self->_append( $header, $data );
2213             }
2214              
2215              
2216             ###############################################################################
2217             #
2218             # _store_shtprops()
2219             #
2220             # Write the SHTPROPS chart BIFF record.
2221             #
2222             sub _store_shtprops {
2223              
2224 3     3   1081 my $self = shift;
2225              
2226 3         8 my $record = 0x1044; # Record identifier.
2227 3         19 my $length = 0x0004; # Number of bytes to follow.
2228 3         7 my $grbit = 0x000E; # Option flags.
2229 3         6 my $empty_cells = 0x0000; # Empty cell handling.
2230              
2231 3 50       35 $grbit = 0x000A if $self->{_embedded};
2232              
2233 3         11 my $header = pack 'vv', $record, $length;
2234 3         6 my $data = '';
2235 3         9 $data .= pack 'v', $grbit;
2236 3         8 $data .= pack 'v', $empty_cells;
2237              
2238 3         13 $self->_append( $header, $data );
2239             }
2240              
2241              
2242             ###############################################################################
2243             #
2244             # _store_text()
2245             #
2246             # Write the TEXT chart BIFF record.
2247             #
2248             sub _store_text {
2249              
2250 7     7   410 my $self = shift;
2251              
2252 7         14 my $record = 0x1025; # Record identifier.
2253 7         10 my $length = 0x0020; # Number of bytes to follow.
2254 7         10 my $at = 0x02; # Horizontal alignment.
2255 7         9 my $vat = 0x02; # Vertical alignment.
2256 7         11 my $wBkgMode = 0x0001; # Background display.
2257 7         10 my $rgbText = 0x0000; # Text RGB colour.
2258 7         9 my $x = $_[0]; # Text x-pos.
2259 7         13 my $y = $_[1]; # Text y-pos.
2260 7         8 my $dx = $_[2]; # Width.
2261 7         19 my $dy = $_[3]; # Height.
2262 7         11 my $grbit1 = $_[4]; # Option flags.
2263 7         11 my $icvText = 0x004D; # Auto Colour.
2264 7         10 my $grbit2 = $_[5]; # Show legend.
2265 7   50     33 my $rotation = $_[6] || 0x00; # Show value.
2266              
2267              
2268 7         19 my $header = pack 'vv', $record, $length;
2269 7         13 my $data = '';
2270 7         14 $data .= pack 'C', $at;
2271 7         15 $data .= pack 'C', $vat;
2272 7         16 $data .= pack 'v', $wBkgMode;
2273 7         12 $data .= pack 'V', $rgbText;
2274 7         13 $data .= pack 'V', $x;
2275 7         13 $data .= pack 'V', $y;
2276 7         22 $data .= pack 'V', $dx;
2277 7         12 $data .= pack 'V', $dy;
2278 7         14 $data .= pack 'v', $grbit1;
2279 7         12 $data .= pack 'v', $icvText;
2280 7         12 $data .= pack 'v', $grbit2;
2281 7         13 $data .= pack 'v', $rotation;
2282              
2283 7         26 $self->_append( $header, $data );
2284             }
2285              
2286             ###############################################################################
2287             #
2288             # _store_tick()
2289             #
2290             # Write the TICK chart BIFF record.
2291             #
2292             sub _store_tick {
2293              
2294 5     5   688 my $self = shift;
2295              
2296 5         11 my $record = 0x101E; # Record identifier.
2297 5         7 my $length = 0x001E; # Number of bytes to follow.
2298 5         6 my $tktMajor = 0x02; # Type of major tick mark.
2299 5         9 my $tktMinor = 0x00; # Type of minor tick mark.
2300 5         8 my $tlt = 0x03; # Tick label position.
2301 5         8 my $wBkgMode = 0x01; # Background mode.
2302 5         169 my $rgb = 0x00000000; # Tick-label RGB colour.
2303 5         18 my $reserved1 = 0x00000000; # Reserved.
2304 5         11 my $reserved2 = 0x00000000; # Reserved.
2305 5         16 my $reserved3 = 0x00000000; # Reserved.
2306 5         8 my $reserved4 = 0x00000000; # Reserved.
2307 5         15 my $grbit = 0x0023; # Option flags.
2308 5         8 my $index = 0x004D; # Colour index.
2309 5         8 my $reserved5 = 0x0000; # Reserved.
2310              
2311 5         15 my $header = pack 'vv', $record, $length;
2312 5         8 my $data = '';
2313 5         13 $data .= pack 'C', $tktMajor;
2314 5         12 $data .= pack 'C', $tktMinor;
2315 5         12 $data .= pack 'C', $tlt;
2316 5         142 $data .= pack 'C', $wBkgMode;
2317 5         14 $data .= pack 'V', $rgb;
2318 5         11 $data .= pack 'V', $reserved1;
2319 5         10 $data .= pack 'V', $reserved2;
2320 5         8 $data .= pack 'V', $reserved3;
2321 5         9 $data .= pack 'V', $reserved4;
2322 5         9 $data .= pack 'v', $grbit;
2323 5         10 $data .= pack 'v', $index;
2324 5         9 $data .= pack 'v', $reserved5;
2325              
2326 5         20 $self->_append( $header, $data );
2327             }
2328              
2329              
2330             ###############################################################################
2331             #
2332             # _store_valuerange()
2333             #
2334             # Write the VALUERANGE chart BIFF record.
2335             #
2336             sub _store_valuerange {
2337              
2338 3     3   455 my $self = shift;
2339              
2340 3         5 my $record = 0x101F; # Record identifier.
2341 3         6 my $length = 0x002A; # Number of bytes to follow.
2342 3         6 my $numMin = 0x00000000; # Minimum value on axis.
2343 3         6 my $numMax = 0x00000000; # Maximum value on axis.
2344 3         5 my $numMajor = 0x00000000; # Value of major increment.
2345 3         6 my $numMinor = 0x00000000; # Value of minor increment.
2346 3         6 my $numCross = 0x00000000; # Value where category axis crosses.
2347 3         12 my $grbit = 0x011F; # Format flags.
2348              
2349             # TODO. Reverse doubles when they are handled.
2350              
2351 3         11 my $header = pack 'vv', $record, $length;
2352 3         42 my $data = '';
2353 3         12 $data .= pack 'd', $numMin;
2354 3         7 $data .= pack 'd', $numMax;
2355 3         10 $data .= pack 'd', $numMajor;
2356 3         8 $data .= pack 'd', $numMinor;
2357 3         8 $data .= pack 'd', $numCross;
2358 3         7 $data .= pack 'v', $grbit;
2359              
2360 3         15 $self->_append( $header, $data );
2361             }
2362              
2363              
2364             ###############################################################################
2365             #
2366             # Config data.
2367             #
2368             ###############################################################################
2369              
2370              
2371             ###############################################################################
2372             #
2373             # _set_default_properties()
2374             #
2375             # Setup the default properties for a chart.
2376             #
2377             sub _set_default_properties {
2378              
2379 36     36   30082 my $self = shift;
2380              
2381 36         215 $self->{_legend} = {
2382             _visible => 1,
2383             _position => 0,
2384             _vertical => 0,
2385             };
2386              
2387 36         447 $self->{_chartarea} = {
2388             _visible => 0,
2389             _fg_color_index => 0x4E,
2390             _fg_color_rgb => 0xFFFFFF,
2391             _bg_color_index => 0x4D,
2392             _bg_color_rgb => 0x000000,
2393             _area_pattern => 0x0000,
2394             _area_options => 0x0000,
2395             _line_pattern => 0x0005,
2396             _line_weight => 0xFFFF,
2397             _line_color_index => 0x4D,
2398             _line_color_rgb => 0x000000,
2399             _line_options => 0x0008,
2400             };
2401              
2402 36         340 $self->{_plotarea} = {
2403             _visible => 1,
2404             _fg_color_index => 0x16,
2405             _fg_color_rgb => 0xC0C0C0,
2406             _bg_color_index => 0x4F,
2407             _bg_color_rgb => 0x000000,
2408             _area_pattern => 0x0001,
2409             _area_options => 0x0000,
2410             _line_pattern => 0x0000,
2411             _line_weight => 0x0000,
2412             _line_color_index => 0x17,
2413             _line_color_rgb => 0x808080,
2414             _line_options => 0x0000,
2415             };
2416             }
2417              
2418              
2419             ###############################################################################
2420             #
2421             # _set_default_config_data()
2422             #
2423             # Setup the default configuration data for a chart.
2424             #
2425             sub _set_default_config_data {
2426              
2427 10     10   19 my $self = shift;
2428              
2429             #<<< Perltidy ignore this.
2430 10         354 $self->{_config} = {
2431             _axisparent => [ 0, 0x00F8, 0x01F5, 0x0E7F, 0x0B36 ],
2432             _axisparent_pos => [ 2, 2, 0x008C, 0x01AA, 0x0EEA, 0x0C52 ],
2433             _chart => [ 0x0000, 0x0000, 0x02DD51E0, 0x01C2B838 ],
2434             _font_numbers => [ 5, 10, 0x38B8, 0x22A1, 0x0000 ],
2435             _font_series => [ 6, 10, 0x38B8, 0x22A1, 0x0001 ],
2436             _font_title => [ 7, 12, 0x38B8, 0x22A1, 0x0000 ],
2437             _font_axes => [ 8, 10, 0x38B8, 0x22A1, 0x0001 ],
2438             _legend => [ 0x05F9, 0x0EE9, 0x047D, 0x9C, 0x00, 0x01, 0x0F ],
2439             _legend_pos => [ 5, 2, 0x05F9, 0x0EE9, 0, 0 ],
2440             _legend_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x0000 ],
2441             _legend_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2442             _series_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x1020 ],
2443             _series_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2444             _title_text => [ 0x06E4, 0x0051, 0x01DB, 0x00C4, 0x0081, 0x1030 ],
2445             _title_text_pos => [ 2, 2, 0, 0, 0x73, 0x1D ],
2446             _x_axis_text => [ 0x07E1, 0x0DFC, 0xB2, 0x9C, 0x0081, 0x0000 ],
2447             _x_axis_text_pos => [ 2, 2, 0, 0, 0x2B, 0x17 ],
2448             _y_axis_text => [ 0x002D, 0x06AA, 0x5F, 0x1CC, 0x0281, 0x00, 90 ],
2449             _y_axis_text_pos => [ 2, 2, 0, 0, 0x17, 0x44 ],
2450             }; #>>>
2451              
2452              
2453             }
2454              
2455              
2456             ###############################################################################
2457             #
2458             # _set_embedded_config_data()
2459             #
2460             # Setup the default configuration data for an embedded chart.
2461             #
2462             sub _set_embedded_config_data {
2463              
2464 9     9   66 my $self = shift;
2465              
2466 9         17 $self->{_embedded} = 1;
2467              
2468 9         61 $self->{_chartarea} = {
2469             _visible => 1,
2470             _fg_color_index => 0x4E,
2471             _fg_color_rgb => 0xFFFFFF,
2472             _bg_color_index => 0x4D,
2473             _bg_color_rgb => 0x000000,
2474             _area_pattern => 0x0001,
2475             _area_options => 0x0001,
2476             _line_pattern => 0x0000,
2477             _line_weight => 0x0000,
2478             _line_color_index => 0x4D,
2479             _line_color_rgb => 0x000000,
2480             _line_options => 0x0009,
2481             };
2482              
2483              
2484             #<<< Perltidy ignore this.
2485 9         326 $self->{_config} = {
2486             _axisparent => [ 0, 0x01D8, 0x031D, 0x0D79, 0x07E9 ],
2487             _axisparent_pos => [ 2, 2, 0x010C, 0x0292, 0x0E46, 0x09FD ],
2488             _chart => [ 0x0000, 0x0000, 0x01847FE8, 0x00F47FE8 ],
2489             _font_numbers => [ 5, 10, 0x1DC4, 0x1284, 0x0000 ],
2490             _font_series => [ 6, 10, 0x1DC4, 0x1284, 0x0001 ],
2491             _font_title => [ 7, 12, 0x1DC4, 0x1284, 0x0000 ],
2492             _font_axes => [ 8, 10, 0x1DC4, 0x1284, 0x0001 ],
2493             _legend => [ 0x044E, 0x0E4A, 0x088D, 0x0123, 0x0, 0x1, 0xF ],
2494             _legend_pos => [ 5, 2, 0x044E, 0x0E4A, 0, 0 ],
2495             _legend_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x0000 ],
2496             _legend_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2497             _series_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x1020 ],
2498             _series_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2499             _title_text => [ 0x060F, 0x004C, 0x038A, 0x016F, 0x0081, 0x1030 ],
2500             _title_text_pos => [ 2, 2, 0, 0, 0x73, 0x1D ],
2501             _x_axis_text => [ 0x07EF, 0x0C8F, 0x153, 0x123, 0x81, 0x00 ],
2502             _x_axis_text_pos => [ 2, 2, 0, 0, 0x2B, 0x17 ],
2503             _y_axis_text => [ 0x0057, 0x0564, 0xB5, 0x035D, 0x0281, 0x00, 90 ],
2504             _y_axis_text_pos => [ 2, 2, 0, 0, 0x17, 0x44 ],
2505             }; #>>>
2506             }
2507              
2508              
2509              
2510             1;
2511              
2512              
2513             __END__