writeexcel 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/.gitattributes +1 -1
  2. data/.gitignore +24 -24
  3. data/README.rdoc +34 -55
  4. data/VERSION +1 -1
  5. data/charts/chartex.rb +316 -316
  6. data/charts/demo1.rb +46 -46
  7. data/charts/demo2.rb +65 -65
  8. data/charts/demo3.rb +117 -117
  9. data/charts/demo4.rb +119 -119
  10. data/charts/demo5.rb +48 -48
  11. data/examples/a_simple.rb +43 -43
  12. data/examples/autofilter.rb +265 -265
  13. data/examples/bigfile.rb +30 -30
  14. data/examples/chart_area.rb +121 -121
  15. data/examples/chart_bar.rb +120 -120
  16. data/examples/chart_column.rb +120 -120
  17. data/examples/chart_line.rb +120 -120
  18. data/examples/chart_pie.rb +108 -108
  19. data/examples/chart_scatter.rb +121 -121
  20. data/examples/chart_stock.rb +148 -148
  21. data/examples/chess.rb +142 -142
  22. data/examples/colors.rb +129 -129
  23. data/examples/comments1.rb +27 -27
  24. data/examples/comments2.rb +352 -352
  25. data/examples/copyformat.rb +52 -52
  26. data/examples/data_validate.rb +279 -279
  27. data/examples/date_time.rb +87 -87
  28. data/examples/defined_name.rb +32 -32
  29. data/examples/demo.rb +124 -124
  30. data/examples/diag_border.rb +36 -36
  31. data/examples/formats.rb +490 -490
  32. data/examples/formula_result.rb +30 -30
  33. data/examples/header.rb +137 -137
  34. data/examples/hide_sheet.rb +29 -29
  35. data/examples/hyperlink.rb +43 -43
  36. data/examples/images.rb +63 -63
  37. data/examples/indent.rb +31 -31
  38. data/examples/merge1.rb +40 -40
  39. data/examples/merge2.rb +45 -45
  40. data/examples/merge3.rb +66 -66
  41. data/examples/merge4.rb +83 -83
  42. data/examples/merge5.rb +80 -80
  43. data/examples/merge6.rb +67 -67
  44. data/examples/outline.rb +255 -255
  45. data/examples/outline_collapsed.rb +209 -209
  46. data/examples/panes.rb +113 -113
  47. data/examples/properties.rb +34 -34
  48. data/examples/properties_jp.rb +33 -33
  49. data/examples/protection.rb +47 -47
  50. data/examples/regions.rb +53 -53
  51. data/examples/repeat.rb +43 -43
  52. data/examples/right_to_left.rb +27 -27
  53. data/examples/row_wrap.rb +53 -53
  54. data/examples/stats.rb +74 -74
  55. data/examples/stocks.rb +81 -81
  56. data/examples/tab_colors.rb +31 -31
  57. data/examples/utf8.rb +15 -15
  58. data/examples/write_arrays.rb +83 -83
  59. data/lib/writeexcel/biffwriter.rb +232 -232
  60. data/lib/writeexcel/caller_info.rb +12 -12
  61. data/lib/writeexcel/chart.rb +2190 -2177
  62. data/lib/writeexcel/charts/area.rb +154 -154
  63. data/lib/writeexcel/charts/bar.rb +177 -177
  64. data/lib/writeexcel/charts/column.rb +156 -156
  65. data/lib/writeexcel/charts/external.rb +66 -66
  66. data/lib/writeexcel/charts/line.rb +154 -154
  67. data/lib/writeexcel/charts/pie.rb +169 -169
  68. data/lib/writeexcel/charts/scatter.rb +192 -192
  69. data/lib/writeexcel/charts/stock.rb +213 -213
  70. data/lib/writeexcel/colors.rb +64 -64
  71. data/lib/writeexcel/compatibility.rb +0 -255
  72. data/lib/writeexcel/debug_info.rb +37 -33
  73. data/lib/writeexcel/excelformulaparser.rb +587 -587
  74. data/lib/writeexcel/format.rb +13 -4
  75. data/lib/writeexcel/formula.rb +26 -9
  76. data/lib/writeexcel/helper.rb +68 -64
  77. data/lib/writeexcel/olewriter.rb +311 -311
  78. data/lib/writeexcel/properties.rb +242 -240
  79. data/lib/writeexcel/storage_lite.rb +984 -978
  80. data/lib/writeexcel/workbook.rb +3210 -3192
  81. data/lib/writeexcel/worksheet.rb +143 -51
  82. data/lib/writeexcel/write_file.rb +44 -40
  83. data/lib/writeexcel.rb +1159 -1159
  84. data/test/helper.rb +31 -28
  85. data/test/perl_output/README +31 -31
  86. data/test/test_00_IEEE_double.rb +13 -13
  87. data/test/test_01_add_worksheet.rb +10 -10
  88. data/test/test_02_merge_formats.rb +53 -53
  89. data/test/test_04_dimensions.rb +392 -392
  90. data/test/test_05_rows.rb +179 -179
  91. data/test/test_06_extsst.rb +77 -77
  92. data/test/test_11_date_time.rb +479 -479
  93. data/test/test_12_date_only.rb +501 -501
  94. data/test/test_13_date_seconds.rb +481 -481
  95. data/test/test_21_escher.rb +637 -637
  96. data/test/test_22_mso_drawing_group.rb +745 -745
  97. data/test/test_23_note.rb +73 -73
  98. data/test/test_24_txo.rb +75 -75
  99. data/test/test_25_position_object.rb +84 -84
  100. data/test/test_26_autofilter.rb +314 -314
  101. data/test/test_27_autofilter.rb +131 -131
  102. data/test/test_28_autofilter.rb +161 -161
  103. data/test/test_29_process_jpg.rb +683 -683
  104. data/test/test_30_validation_dval.rb +77 -77
  105. data/test/test_31_validation_dv_strings.rb +126 -126
  106. data/test/test_32_validation_dv_formula.rb +206 -206
  107. data/test/test_40_property_types.rb +188 -188
  108. data/test/test_41_properties.rb +235 -235
  109. data/test/test_42_set_properties.rb +437 -437
  110. data/test/test_50_name_stored.rb +299 -299
  111. data/test/test_51_name_print_area.rb +357 -357
  112. data/test/test_52_name_print_titles.rb +454 -454
  113. data/test/test_53_autofilter.rb +203 -203
  114. data/test/test_60_chart_generic.rb +578 -578
  115. data/test/test_61_chart_subclasses.rb +95 -95
  116. data/test/test_62_chart_formats.rb +272 -272
  117. data/test/test_63_chart_area_formats.rb +649 -649
  118. data/test/test_biff.rb +75 -75
  119. data/test/test_compatibility.rb +12 -627
  120. data/test/test_example_match.rb +3144 -3144
  121. data/test/test_formula.rb +61 -61
  122. data/test/test_ole.rb +106 -106
  123. data/test/test_storage_lite.rb +125 -125
  124. data/test/test_workbook.rb +139 -139
  125. data/test/test_worksheet.rb +110 -110
  126. data/utils/add_magic_comment.rb +80 -80
  127. data/writeexcel.gemspec +4 -6
  128. data/writeexcel.rdoc +58 -15
  129. metadata +9 -6
  130. data/test/test_new_encoding.rb +0 -205
@@ -1,2177 +1,2190 @@
1
- # -*- coding: utf-8 -*-
2
- ###############################################################################
3
- #
4
- # Chart - A writer class for Excel Charts.
5
- #
6
- #
7
- # Used in conjunction with WriteExcel
8
- #
9
- # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
10
- #
11
- # original written in Perl by John McNamara
12
- # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
13
- #
14
-
15
- require 'writeexcel/worksheet'
16
- require 'writeexcel/colors'
17
-
18
- ###############################################################################
19
- #
20
- # Formatting information.
21
- #
22
- # perltidy with options: -mbl=2 -pt=0 -nola
23
- #
24
- # Any camel case Hungarian notation style variable names in the BIFF record
25
- # writing sub-routines below are for similarity with names used in the Excel
26
- # documentation. Otherwise lowercase underscore style names are used.
27
- #
28
-
29
-
30
- ###############################################################################
31
- #
32
- # The chart class hierarchy is as follows. Chart.pm acts as a factory for the
33
- # sub-classes.
34
- #
35
- #
36
- # BIFFwriter
37
- # ^
38
- # |
39
- # Writeexcel::Worksheet
40
- # ^
41
- # |
42
- # Writeexcel::Chart
43
- # ^
44
- # |
45
- # Writeexcel::Chart::* (sub-types)
46
- #
47
-
48
- #
49
- # = Chart
50
- # Chart - A writer class for Excel Charts.
51
- #
52
- module Writeexcel
53
-
54
- class Chart < Worksheet
55
- require 'writeexcel/helper'
56
- private :convert_to_ascii_if_ascii
57
-
58
- ###############################################################################
59
- #
60
- # factory()
61
- #
62
- # Factory method for returning chart objects based on their class type.
63
- #
64
- def self.factory(type, *args) #:nodoc:
65
- klass =
66
- case type
67
- when 'Chart::Column'
68
- Chart::Column
69
- when 'Chart::Bar'
70
- Chart::Bar
71
- when 'Chart::Line'
72
- Chart::Line
73
- when 'Chart::Area'
74
- Chart::Area
75
- when 'Chart::Pie'
76
- Chart::Pie
77
- when 'Chart::Scatter'
78
- Chart::Scatter
79
- when 'Chart::Stock'
80
- Chart::Stock
81
- end
82
-
83
- klass.new(*args)
84
- end
85
-
86
- ###############################################################################
87
- #
88
- # :call-seq:
89
- # new(filename, name, index, encoding, activesheet, firstsheet, external_bin = nil)
90
- #
91
- # Default constructor for sub-classes.
92
- #
93
- def initialize(*args) #:nodoc:
94
- super
95
-
96
- @sheet_type = 0x0200
97
- @orientation = 0x0
98
- @series = []
99
- @embedded = false
100
-
101
- @external_bin = false
102
- @x_axis_formula = nil
103
- @x_axis_name = nil
104
- @y_axis_formula = nil
105
- @y_axis_name = nil
106
- @title_name = nil
107
- @title_formula = nil
108
- @vary_data_color = 0
109
- set_default_properties
110
- set_default_config_data
111
- end
112
-
113
- #
114
- # Add a series and it's properties to a chart.
115
- #
116
- # In an Excel chart a "series" is a collection of information such as values,
117
- # x-axis labels and the name that define which data is plotted. These
118
- # settings are displayed when you select the Chart -> Source Data... menu
119
- # option.
120
- #
121
- # With a WriteExcel chart object the add_series() method is used to set the
122
- # properties for a series:
123
- #
124
- # chart.add_series(
125
- # :categories => '=Sheet1!$A$2:$A$10',
126
- # :values => '=Sheet1!$B$2:$B$10',
127
- # :name => 'Series name',
128
- # :name_formula => '=Sheet1!$B$1'
129
- # )
130
- #
131
- # The properties that can be set are:
132
- #
133
- # :values (required)
134
- # :categories (optional for most chart types)
135
- # :name (optional)
136
- # :name_formula (optional)
137
- #
138
- # * :values
139
- #
140
- # This is the most important property of a series and must be set for
141
- # every chart object. It links the chart with the worksheet data that
142
- # it displays.
143
- #
144
- # chart.add_series(:values => '=Sheet1!$B$2:$B$10')
145
- #
146
- # Note the format that should be used for the formula. It is the same
147
- # as is used in Excel. You must also add the worksheet that you are
148
- # referring to before you link to it, via the workbook
149
- # add_worksheet() method.
150
- #
151
- # * :categories
152
- #
153
- # This sets the chart category labels. The category is more or less
154
- # the same as the X-axis. In most chart types the categories property
155
- # is optional and the chart will just assume a sequential series
156
- # from 1 .. n.
157
- #
158
- # chart.add_series(
159
- # :categories => '=Sheet1!$A$2:$A$10',
160
- # :values => '=Sheet1!$B$2:$B$10'
161
- # )
162
- #
163
- # * :name
164
- #
165
- # Set the name for the series. The name is displayed in the chart
166
- # legend and in the formula bar. The name property is optional and
167
- # if it isn't supplied will default to Series 1 .. n.
168
- #
169
- # chart.add_series(
170
- # ...
171
- # :name => 'Series name'
172
- # )
173
- #
174
- # * :name_formula
175
- #
176
- # Optional, can be used to link the name to a worksheet cell.
177
- # See "Chart names and links".
178
- #
179
- # chart.add_series(
180
- # ...
181
- # :name => 'Series name',
182
- # :name_formula => '=Sheet1!$B$1'
183
- # )
184
- #
185
- # You can add more than one series to a chart. The series numbering and
186
- # order in the final chart is the same as the order in which that are added.
187
- #
188
- # # Add the first series.
189
- # chart.add_series(
190
- # :categories => '=Sheet1!$A$2:$A$7',
191
- # :values => '=Sheet1!$B$2:$B$7',
192
- # :name => 'Test data series 1'
193
- # )
194
- #
195
- # # Add another series. Category is the same but values are different.
196
- # chart.add_series(
197
- # :categories => '=Sheet1!$A$2:$A$7',
198
- # :values => '=Sheet1!$C$2:$C$7',
199
- # :name => 'Test data series 2'
200
- # )
201
- #
202
- def add_series(params)
203
- raise "Must specify 'values' in add_series()" if params[:values].nil?
204
-
205
- # Parse the ranges to validate them and extract salient information.
206
- value_data = parse_series_formula(params[:values])
207
- category_data = parse_series_formula(params[:categories])
208
- name_formula = parse_series_formula(params[:name_formula])
209
-
210
- # Default category count to the same as the value count if not defined.
211
- category_data[1] = value_data[1] if category_data.size < 2
212
-
213
- # Add the parsed data to the user supplied data.
214
- params[:values] = value_data
215
- params[:categories] = category_data
216
- params[:name_formula] = name_formula
217
-
218
- # Encode the Series name.
219
- name, encoding = encode_utf16(params[:name], params[:name_encoding])
220
-
221
- params[:name] = name
222
- params[:name_encoding] = encoding
223
-
224
- @series << params
225
- end
226
-
227
- #
228
- # Set the properties of the X-axis.
229
- #
230
- # The set_x_axis() method is used to set properties of the X axis.
231
- #
232
- # chart.set_x_axis(:name => 'Sample length (m)' )
233
- #
234
- # The properties that can be set are:
235
- #
236
- # :name (optional)
237
- # :name_formula (optional)
238
- #
239
- # * :name
240
- #
241
- # Set the name (title or caption) for the axis. The name is displayed
242
- # below the X axis. This property is optional. The default is to have
243
- # no axis name.
244
- #
245
- # chart.set_x_axis( :name => 'Sample length (m)' )
246
- #
247
- # * :name_formula
248
- #
249
- # Optional, can be used to link the name to a worksheet cell.
250
- # See "Chart names and links".
251
- #
252
- # chart.set_x_axis(
253
- # :name => 'Sample length (m)',
254
- # :name_formula => '=Sheet1!$A$1'
255
- # )
256
- #
257
- # Additional axis properties such as range, divisions and ticks will be made
258
- # available in later releases.
259
- def set_x_axis(params)
260
- name, encoding = encode_utf16(params[:name], params[:name_encoding])
261
- formula = parse_series_formula(params[:name_formula])
262
-
263
- @x_axis_name = name
264
- @x_axis_encoding = encoding
265
- @x_axis_formula = formula
266
- end
267
-
268
- #
269
- # Set the properties of the Y-axis.
270
- #
271
- # The set_y_axis() method is used to set properties of the Y axis.
272
- #
273
- # chart.set_y_axis(:name => 'Sample weight (kg)' )
274
- #
275
- # The properties that can be set are:
276
- #
277
- # :name (optional)
278
- # :name_formula (optional)
279
- #
280
- # * :name
281
- #
282
- # Set the name (title or caption) for the axis. The name is displayed
283
- # to the left of the Y axis. This property is optional. The default
284
- # is to have no axis name.
285
- #
286
- # chart.set_y_axis(:name => 'Sample weight (kg)' )
287
- #
288
- # * :name_formula
289
- #
290
- # Optional, can be used to link the name to a worksheet cell.
291
- # See "Chart names and links".
292
- #
293
- # chart.set_y_axis(
294
- # :name => 'Sample weight (kg)',
295
- # :name_formula => '=Sheet1!$B$1'
296
- # )
297
- #
298
- # Additional axis properties such as range, divisions and ticks will be made
299
- # available in later releases.
300
- #
301
- def set_y_axis(params)
302
- name, encoding = encode_utf16(params[:name], params[:name_encoding])
303
- formula = parse_series_formula(params[:name_formula])
304
-
305
- @y_axis_name = name
306
- @y_axis_encoding = encoding
307
- @y_axis_formula = formula
308
- end
309
-
310
- #
311
- # The set_title() method is used to set properties of the chart title.
312
- #
313
- # chart.set_title(:name => 'Year End Results')
314
- #
315
- # The properties that can be set are:
316
- #
317
- # :name (optional)
318
- # :name_formula (optional)
319
- #
320
- # * :name
321
- #
322
- # Set the name (title) for the chart. The name is displayed above the
323
- # chart. This property is optional. The default is to have no chart
324
- # title.
325
- #
326
- # chart.set_title(:name => 'Year End Results')
327
- #
328
- # * :name_formula
329
- #
330
- # Optional, can be used to link the name to a worksheet cell.
331
- # See "Chart names and links".
332
- #
333
- # chart.set_title(
334
- # :name => 'Year End Results',
335
- # :name_formula => '=Sheet1!$C$1'
336
- # )
337
- #
338
- def set_title(params)
339
- name, encoding = encode_utf16( params[:name], params[:name_encoding])
340
-
341
- formula = parse_series_formula(params[:name_formula])
342
-
343
- @title_name = name
344
- @title_encoding = encoding
345
- @title_formula = formula
346
- end
347
-
348
- ###############################################################################
349
- #
350
- # set_legend()
351
- #
352
- # Set the properties of the chart legend.
353
- #
354
- def set_legend(params = {})
355
- if params.has_key?(:position)
356
- if params[:position].downcase == 'none'
357
- legend[:visible] = 0
358
- end
359
- end
360
- end
361
-
362
- ###############################################################################
363
- #
364
- # set_plotarea()
365
- #
366
- # Set the properties of the chart plotarea.
367
- #
368
- def set_plotarea(params = {})
369
- return if params.empty?
370
-
371
- area = @plotarea
372
-
373
- # Set the plotarea visibility.
374
- if params.has_key?(:visible)
375
- area[:visible] = params[:visible]
376
- return if area[:visible] == 0
377
- end
378
-
379
- # TODO. could move this out of if statement.
380
- area[:bg_color_index] = 0x08
381
-
382
- # Set the chart background colour.
383
- if params.has_key?(:color)
384
- index, rgb = get_color_indices(params[:color])
385
- if !index.nil?
386
- area[:fg_color_index] = index
387
- area[:fg_color_rgb] = rgb
388
- area[:bg_color_index] = 0x08
389
- area[:bg_color_rgb] = 0x000000
390
- end
391
- end
392
-
393
- # Set the border line colour.
394
- if params.has_key?(:line_color)
395
- index, rgb = get_color_indices(params[:line_color])
396
- if !index.nil?
397
- area[:line_color_index] = index
398
- area[:line_color_rgb] = rgb
399
- end
400
- end
401
-
402
- # Set the border line pattern.
403
- if params.has_key?(:line_pattern)
404
- pattern = get_line_pattern(params[:line_pattern])
405
- area[:line_pattern] = pattern
406
- end
407
-
408
- # Set the border line weight.
409
- if params.has_key?(:line_weight)
410
- weight = get_line_weight(params[:line_weight])
411
- area[:line_weight] = weight
412
- end
413
- end
414
-
415
- ###############################################################################
416
- #
417
- # set_chartarea()
418
- #
419
- # Set the properties of the chart chartarea.
420
- #
421
- def set_chartarea(params = {})
422
- return if params.empty?
423
-
424
- area = @chartarea
425
-
426
- # Embedded automatic line weight has a different default value.
427
- area[:line_weight] = 0xFFFF if @embedded
428
-
429
- # Set the chart background colour.
430
- if params.has_key?(:color)
431
- index, rgb = get_color_indices(params[:color])
432
- if !index.nil?
433
- area[:fg_color_index] = index
434
- area[:fg_color_rgb] = rgb
435
- area[:bg_color_index] = 0x08
436
- area[:bg_color_rgb] = 0x000000
437
- area[:area_pattern] = 1
438
- area[:area_options] = 0x0000 if @embedded
439
- area[:visible] = 1
440
- end
441
- end
442
-
443
- # Set the border line colour.
444
- if params.has_key?(:line_color)
445
- index, rgb = get_color_indices(params[:line_color])
446
- if !index.nil?
447
- area[:line_color_index] = index
448
- area[:line_color_rgb] = rgb
449
- area[:line_pattern] = 0x00
450
- area[:line_options] = 0x0000
451
- area[:visible] = 1
452
- end
453
- end
454
-
455
- # Set the border line pattern.
456
- if params.has_key?(:line_pattern)
457
- pattern = get_line_pattern(params[:line_pattern])
458
- area[:line_pattern] = pattern
459
- area[:line_options] = 0x0000
460
- area[:line_color_index] = 0x4F unless params.has_key?(:line_color)
461
- area[:visible] = 1
462
- end
463
-
464
- # Set the border line weight.
465
- if params.has_key?(:line_weight)
466
- weight = get_line_weight(params[:line_weight])
467
- area[:line_weight] = weight
468
- area[:line_options] = 0x0000
469
- area[:line_pattern] = 0x00 unless params.has_key?(:line_pattern)
470
- area[:line_color_index] = 0x4F unless params.has_key?(:line_color)
471
- area[:visible] = 1
472
- end
473
- end
474
-
475
-
476
-
477
- def using_tmpfile=(val) # :nodoc:
478
- @using_tmpfile = val
479
- end
480
-
481
- def data=(val) # :nodoc:
482
- @data = val
483
- end
484
-
485
- def embedded # :nodoc:
486
- @embedded
487
- end
488
-
489
- def embedded=(val) # :nodoc:
490
- @embedded = val
491
- end
492
-
493
- ###############################################################################
494
- #
495
- # _prepend(), overridden.
496
- #
497
- # The parent Worksheet class needs to store some data in memory and some in
498
- # temporary files for efficiency. The Chart* classes don't need to do this
499
- # since they are dealing with smaller amounts of data so we override
500
- # _prepend() to turn it into an _append() method. This allows for a more
501
- # natural method calling order.
502
- #
503
- def prepend(*args) # :nodoc:
504
- @using_tmpfile = false
505
- append(*args)
506
- end
507
-
508
- ###############################################################################
509
- #
510
- # _close(), overridden.
511
- #
512
- # Create and store the Chart data structures.
513
- #
514
- def close # :nodoc:
515
- # Ignore any data that has been written so far since it is probably
516
- # from unwanted Worksheet method calls.
517
- @data = ''
518
-
519
- # TODO. Check for charts without a series?
520
-
521
- # Store the chart BOF.
522
- store_bof(0x0020)
523
-
524
- # Store the page header
525
- store_header
526
-
527
- # Store the page footer
528
- store_footer
529
-
530
- # Store the page horizontal centering
531
- store_hcenter
532
-
533
- # Store the page vertical centering
534
- store_vcenter
535
-
536
- # Store the left margin
537
- store_margin_left
538
-
539
- # Store the right margin
540
- store_margin_right
541
-
542
- # Store the top margin
543
- store_margin_top
544
-
545
- # Store the bottom margin
546
- store_margin_bottom
547
-
548
- # Store the page setup
549
- store_setup
550
-
551
- # Store the sheet password
552
- store_password
553
-
554
- # Start of Chart specific records.
555
-
556
- # Store the FBI font records.
557
- store_fbi(*@config[:font_numbers])
558
- store_fbi(*@config[:font_series])
559
- store_fbi(*@config[:font_title])
560
- store_fbi(*@config[:font_axes])
561
-
562
- # Ignore UNITS record.
563
-
564
- # Store the Chart sub-stream.
565
- store_chart_stream
566
-
567
- # Append the sheet dimensions
568
- store_dimensions
569
-
570
- # TODO add SINDEX and NUMBER records.
571
-
572
- store_window2 unless @embedded
573
-
574
- store_eof
575
- end
576
-
577
- ###############################################################################
578
- #
579
- # _store_window2(), overridden.
580
- #
581
- # Write BIFF record Window2. Note, this overrides the parent Worksheet
582
- # record because the Chart version of the record is smaller and is used
583
- # mainly to indicate if the chart tab is selected or not.
584
- #
585
- def store_window2 # :nodoc:
586
- record = 0x023E # Record identifier
587
- length = 0x000A # Number of bytes to follow
588
- grbit = 0x0000 # Option flags
589
- rwTop = 0x0000 # Top visible row
590
- colLeft = 0x0000 # Leftmost visible column
591
- rgbHdr = 0x0000 # Row/col heading, grid color
592
-
593
- # The options flags that comprise grbit
594
- fDspFmla = 0 # 0 - bit
595
- fDspGrid = 0 # 1
596
- fDspRwCol = 0 # 2
597
- fFrozen = 0 # 3
598
- fDspZeros = 0 # 4
599
- fDefaultHdr = 0 # 5
600
- fArabic = 0 # 6
601
- fDspGuts = 0 # 7
602
- fFrozenNoSplit = 0 # 0 - bit
603
- fSelected = @selected # 1
604
- fPaged = 0 # 2
605
- fBreakPreview = 0 # 3
606
-
607
- #<<< Perltidy ignore this.
608
- grbit = fDspFmla
609
- grbit |= fDspGrid << 1
610
- grbit |= fDspRwCol << 2
611
- grbit |= fFrozen << 3
612
- grbit |= fDspZeros << 4
613
- grbit |= fDefaultHdr << 5
614
- grbit |= fArabic << 6
615
- grbit |= fDspGuts << 7
616
- grbit |= fFrozenNoSplit << 8
617
- grbit |= fSelected << 9
618
- grbit |= fPaged << 10
619
- grbit |= fBreakPreview << 11
620
- #>>>
621
-
622
- header = [record, length].pack("vv")
623
- data = [grbit, rwTop, colLeft, rgbHdr].pack("vvvV")
624
-
625
- append(header, data)
626
- end
627
-
628
- ###############################################################################
629
- #
630
- # _parse_series_formula()
631
- #
632
- # Parse the formula used to define a series. We also extract some range
633
- # information required for _store_series() and the SERIES record.
634
- #
635
- def parse_series_formula(formula) # :nodoc:
636
- encoding = 0
637
- length = 0
638
- count = 0
639
- tokens = []
640
-
641
- return [''] if formula.nil?
642
-
643
- # Strip the = sign at the beginning of the formula string
644
- formula = formula.sub(/^=/, '')
645
-
646
- # Parse the formula using the parser in Formula.pm
647
- parser = @parser
648
-
649
- # In order to raise formula errors from the point of view of the calling
650
- # program we use an eval block and re-raise the error from here.
651
- #
652
- tokens = parser.parse_formula(formula)
653
-
654
- # Force ranges to be a reference class.
655
- tokens.collect! { |t| t.gsub(/_ref3d/, '_ref3dR') }
656
- tokens.collect! { |t| t.gsub(/_range3d/, '_range3dR') }
657
- tokens.collect! { |t| t.gsub(/_name/, '_nameR') }
658
-
659
- # Parse the tokens into a formula string.
660
- formula = parser.parse_tokens(tokens)
661
-
662
- # Return formula for a single cell as used by title and series name.
663
- return formula if formula.ord == 0x3A
664
-
665
- # Extract the range from the parse formula.
666
- if formula.ord == 0x3B
667
- ptg, ext_ref, row_1, row_2, col_1, col_2 = formula.unpack('Cv5')
668
-
669
- # TODO. Remove high bit on relative references.
670
- count = row_2 - row_1 + 1
671
- end
672
-
673
- [formula, count]
674
- end
675
-
676
- ###############################################################################
677
- #
678
- # _encode_utf16()
679
- #
680
- # Convert UTF8 strings used in the chart to UTF16.
681
- #
682
- def encode_utf16(str, encoding = 0) # :nodoc:
683
- # Exit if the $string isn't defined, i.e., hasn't been set by user.
684
- return [nil, nil] if str.nil?
685
-
686
- string = str.dup
687
- # Return if encoding is set, i.e., string has been manually encoded.
688
- #return ( undef, undef ) if $string == 1;
689
-
690
- string = convert_to_ascii_if_ascii(string)
691
-
692
- # Handle utf8 strings.
693
- if string.encoding == Encoding::UTF_8
694
- utf8_to_16be(string)
695
- encoding = 1
696
- end
697
-
698
- # Chart strings are limited to 255 characters.
699
- limit = encoding != 0 ? 255 * 2 : 255
700
-
701
- if string.bytesize >= limit
702
- # truncate the string and raise a warning.
703
- string = string[0, limit]
704
- end
705
-
706
- [string, encoding]
707
- end
708
-
709
- ###############################################################################
710
- #
711
- # _get_color_indices()
712
- #
713
- # Convert the user specified colour index or string to an colour index and
714
- # RGB colour number.
715
- #
716
- def get_color_indices(color) # :nodoc:
717
- invalid = 0x7FFF # return from Colors#get_color when color is invalid
718
-
719
- index = Colors.new.get_color(color)
720
- index = invalid if color.respond_to?(:coerce) && (color < 8 || color > 63)
721
- if index == invalid
722
- [nil, nil]
723
- else
724
- [index, get_color_rbg(index)]
725
- end
726
- end
727
-
728
- ###############################################################################
729
- #
730
- # _get_color_rbg()
731
- #
732
- # Get the RedGreenBlue number for the colour index from the Workbook palette.
733
- #
734
- def get_color_rbg(index) # :nodoc:
735
- # Adjust colour index from 8-63 (user range) to 0-55 (Excel range).
736
- index -= 8
737
-
738
- red_green_blue = @palette[index]
739
- red_green_blue.pack('C*').unpack('V')[0]
740
- end
741
-
742
- ###############################################################################
743
- #
744
- # _get_line_pattern()
745
- #
746
- # Get the Excel chart index for line pattern that corresponds to the user
747
- # defined value.
748
- #
749
- def get_line_pattern(value) # :nodoc:
750
- value = value.downcase if value.respond_to?(:to_str)
751
- default = 0
752
-
753
- patterns = {
754
- 0 => 5,
755
- 1 => 0,
756
- 2 => 1,
757
- 3 => 2,
758
- 4 => 3,
759
- 5 => 4,
760
- 6 => 7,
761
- 7 => 6,
762
- 8 => 8,
763
- 'solid' => 0,
764
- 'dash' => 1,
765
- 'dot' => 2,
766
- 'dash-dot' => 3,
767
- 'dash-dot-dot' => 4,
768
- 'none' => 5,
769
- 'dark-gray' => 6,
770
- 'medium-gray' => 7,
771
- 'light-gray' => 8,
772
- }
773
-
774
- if patterns.has_key?(value)
775
- patterns[value]
776
- else
777
- default
778
- end
779
- end
780
-
781
- ###############################################################################
782
- #
783
- # _get_line_weight()
784
- #
785
- # Get the Excel chart index for line weight that corresponds to the user
786
- # defined value.
787
- #
788
- def get_line_weight(value) # :nodoc:
789
- value = value.downcase if value.respond_to?(:to_str)
790
- default = 0
791
-
792
- weights = {
793
- 1 => -1,
794
- 2 => 0,
795
- 3 => 1,
796
- 4 => 2,
797
- 'hairline' => -1,
798
- 'narrow' => 0,
799
- 'medium' => 1,
800
- 'wide' => 2,
801
- }
802
-
803
- if weights.has_key?(value)
804
- weights[value]
805
- else
806
- default
807
- end
808
- end
809
-
810
- ###############################################################################
811
- #
812
- # _store_chart_stream()
813
- #
814
- # Store the CHART record and it's substreams.
815
- #
816
- def store_chart_stream # :nodoc:
817
- store_chart(*@config[:chart])
818
- store_begin
819
-
820
- # Store the chart SCL record.
821
- store_plotgrowth
822
-
823
- if @chartarea[:visible] != 0
824
- store_chartarea_frame_stream
825
- end
826
-
827
- # Store SERIES stream for each series.
828
- index = 0
829
- @series.each do |series|
830
- store_series_stream(
831
- :index => index,
832
- :value_formula => series[:values][0],
833
- :value_count => series[:values][1],
834
- :category_count => series[:categories][1],
835
- :category_formula => series[:categories][0],
836
- :name => series[:name],
837
- :name_encoding => series[:name_encoding],
838
- :name_formula => series[:name_formula]
839
- )
840
- index += 1
841
- end
842
-
843
- store_shtprops
844
-
845
- # Write the TEXT streams.
846
- (5..6).each do |font_index|
847
- store_defaulttext
848
- store_series_text_stream(font_index)
849
- end
850
-
851
- store_axesused(1)
852
- store_axisparent_stream
853
-
854
- if !@title_name.nil? || !@title_formula.nil?
855
- store_title_text_stream
856
- end
857
-
858
- store_end
859
- end
860
-
861
- def _formula_type_from_param(t, f, params, key) # :nodoc:
862
- if params.has_key?(key)
863
- v = params[key]
864
- (v.nil? || v == [""] || v == '' || v == 0) ? f : t
865
- end
866
- end
867
- private :_formula_type_from_param
868
-
869
- ###############################################################################
870
- #
871
- # _store_series_stream()
872
- #
873
- # Write the SERIES chart substream.
874
- #
875
- def store_series_stream(params) # :nodoc:
876
- name_type = _formula_type_from_param(2, 1, params, :name_formula)
877
- value_type = _formula_type_from_param(2, 0, params, :value_formula)
878
- category_type = _formula_type_from_param(2, 0, params, :category_formula)
879
-
880
- store_series(params[:value_count], params[:category_count])
881
-
882
- store_begin
883
-
884
- # Store the Series name AI record.
885
- store_ai(0, name_type, params[:name_formula])
886
- unless params[:name].nil?
887
- store_seriestext(params[:name], params[:name_encoding])
888
- end
889
-
890
- store_ai(1, value_type, params[:value_formula])
891
- store_ai(2, category_type, params[:category_formula])
892
- store_ai(3, 1, '' )
893
-
894
- store_dataformat_stream(params[:index])
895
- store_sertocrt
896
- store_end
897
- end
898
-
899
- ###############################################################################
900
- #
901
- # _store_dataformat_stream()
902
- #
903
- # Write the DATAFORMAT chart substream.
904
- #
905
- def store_dataformat_stream(series_index) # :nodoc:
906
- store_dataformat(series_index, series_index, 0xFFFF)
907
-
908
- store_begin
909
- store_3dbarshape
910
- store_end
911
- end
912
-
913
- ###############################################################################
914
- #
915
- # _store_series_text_stream()
916
- #
917
- # Write the series TEXT substream.
918
- #
919
- def store_series_text_stream(font_index) # :nodoc:
920
- store_text(*@config[:series_text])
921
-
922
- store_begin
923
- store_pos(*@config[:series_text_pos])
924
- store_fontx( font_index )
925
- store_ai( 0, 1, '' )
926
- store_end
927
- end
928
-
929
- def _formula_type(t, f, formula) # :nodoc:
930
- (formula.nil? || formula == [""] || formula == '' || formula == 0) ? f : t
931
- end
932
- private :_formula_type
933
-
934
- ###############################################################################
935
- #
936
- # _store_x_axis_text_stream()
937
- #
938
- # Write the X-axis TEXT substream.
939
- #
940
- def store_x_axis_text_stream # :nodoc:
941
- formula = @x_axis_formula.nil? ? '' : @x_axis_formula
942
- ai_type = _formula_type(2, 1, formula)
943
-
944
- store_text(*@config[:x_axis_text])
945
-
946
- store_begin
947
- store_pos(*@config[:x_axis_text_pos])
948
- store_fontx(8)
949
- store_ai(0, ai_type, formula)
950
-
951
- unless @x_axis_name.nil?
952
- store_seriestext(@x_axis_name, @x_axis_encoding)
953
- end
954
-
955
- store_objectlink(3)
956
- store_end
957
- end
958
-
959
- ###############################################################################
960
- #
961
- # _store_y_axis_text_stream()
962
- #
963
- # Write the Y-axis TEXT substream.
964
- #
965
- def store_y_axis_text_stream # :nodoc:
966
- formula = @y_axis_formula
967
- ai_type = _formula_type(2, 1, formula)
968
-
969
- store_text(*@config[:y_axis_text])
970
-
971
- store_begin
972
- store_pos(*@config[:y_axis_text_pos])
973
- store_fontx(8)
974
- store_ai(0, ai_type, formula)
975
-
976
- unless @y_axis_name.nil?
977
- store_seriestext(@y_axis_name, @y_axis_encoding)
978
- end
979
-
980
- store_objectlink(2)
981
- store_end
982
- end
983
-
984
- ###############################################################################
985
- #
986
- # _store_legend_text_stream()
987
- #
988
- # Write the legend TEXT substream.
989
- #
990
- def store_legend_text_stream # :nodoc:
991
- store_text(*@config[:legend_text])
992
-
993
- store_begin
994
- store_pos(*@config[:legend_text_pos])
995
- store_ai(0, 1, '')
996
-
997
- store_end
998
- end
999
-
1000
- ###############################################################################
1001
- #
1002
- # _store_title_text_stream()
1003
- #
1004
- # Write the title TEXT substream.
1005
- #
1006
- def store_title_text_stream # :nodoc:
1007
- formula = @title_formula
1008
- ai_type = _formula_type(2, 1, formula)
1009
-
1010
- store_text(*@config[:title_text])
1011
-
1012
- store_begin
1013
- store_pos(*@config[:title_text_pos])
1014
- store_fontx(7)
1015
- store_ai(0, ai_type, formula)
1016
-
1017
- unless @title_name.nil?
1018
- store_seriestext(@title_name, @title_encoding)
1019
- end
1020
-
1021
- store_objectlink(1)
1022
- store_end
1023
- end
1024
-
1025
- ###############################################################################
1026
- #
1027
- # _store_axisparent_stream()
1028
- #
1029
- # Write the AXISPARENT chart substream.
1030
- #
1031
- def store_axisparent_stream # :nodoc:
1032
- store_axisparent(*@config[:axisparent])
1033
-
1034
- store_begin
1035
- store_pos(*@config[:axisparent_pos])
1036
- store_axis_category_stream
1037
- store_axis_values_stream
1038
-
1039
- if !@x_axis_name.nil? || !@x_axis_formula.nil?
1040
- store_x_axis_text_stream
1041
- end
1042
-
1043
- if !@y_axis_name.nil? || !@y_axis_formula.nil?
1044
- store_y_axis_text_stream();
1045
- end
1046
-
1047
- if @plotarea[:visible] != 0
1048
- store_plotarea
1049
- store_plotarea_frame_stream
1050
- end
1051
- store_chartformat_stream
1052
- store_end
1053
- end
1054
-
1055
- ###############################################################################
1056
- #
1057
- # _store_axis_category_stream()
1058
- #
1059
- # Write the AXIS chart substream for the chart category.
1060
- #
1061
- def store_axis_category_stream # :nodoc:
1062
- store_axis(0)
1063
-
1064
- store_begin
1065
- store_catserrange
1066
- store_axcext
1067
- store_tick
1068
- store_end
1069
- end
1070
-
1071
- ###############################################################################
1072
- #
1073
- # _store_axis_values_stream()
1074
- #
1075
- # Write the AXIS chart substream for the chart values.
1076
- #
1077
- def store_axis_values_stream # :nodoc:
1078
- store_axis(1)
1079
-
1080
- store_begin
1081
- store_valuerange
1082
- store_tick
1083
- store_axislineformat
1084
- store_lineformat(0x00000000, 0x0000, 0xFFFF, 0x0009, 0x004D)
1085
- store_end
1086
- end
1087
-
1088
- ###############################################################################
1089
- #
1090
- # _store_plotarea_frame_stream()
1091
- #
1092
- # Write the FRAME chart substream.
1093
- #
1094
- def store_plotarea_frame_stream # :nodoc:
1095
- store_area_frame_stream_common(:plot)
1096
- end
1097
-
1098
- ###############################################################################
1099
- #
1100
- # _store_chartarea_frame_stream()
1101
- #
1102
- # Write the FRAME chart substream for and embedded chart.
1103
- #
1104
- def store_chartarea_frame_stream # :nodoc:
1105
- store_area_frame_stream_common(:chart)
1106
- end
1107
-
1108
- def store_area_frame_stream_common(type)
1109
- if type == :plot
1110
- area = @plotarea
1111
- grbit = 0x03
1112
- else
1113
- area = @chartarea
1114
- grbit = 0x02
1115
- end
1116
-
1117
- store_frame(0x00, grbit)
1118
- store_begin
1119
-
1120
- store_lineformat(
1121
- area[:line_color_rgb], area[:line_pattern],
1122
- area[:line_weight], area[:line_options],
1123
- area[:line_color_index]
1124
- )
1125
-
1126
- store_areaformat(
1127
- area[:fg_color_rgb], area[:bg_color_rgb],
1128
- area[:area_pattern], area[:area_options],
1129
- area[:fg_color_index], area[:bg_color_index]
1130
- )
1131
-
1132
- store_end
1133
- end
1134
- private :store_area_frame_stream_common
1135
-
1136
- ###############################################################################
1137
- #
1138
- # _store_chartformat_stream()
1139
- #
1140
- # Write the CHARTFORMAT chart substream.
1141
- #
1142
- def store_chartformat_stream # :nodoc:
1143
- # The _vary_data_color is set by classes that need it, like Pie.
1144
- store_chartformat(@vary_data_color)
1145
-
1146
- store_begin
1147
-
1148
- # Store the BIFF record that will define the chart type.
1149
- store_chart_type
1150
-
1151
- # Note, the CHARTFORMATLINK record is only written by Excel.
1152
-
1153
- if @legend[:visible]
1154
- store_legend_stream
1155
- end
1156
-
1157
- store_marker_dataformat_stream
1158
- store_end
1159
- end
1160
-
1161
- ###############################################################################
1162
- #
1163
- # _store_chart_type()
1164
- #
1165
- # This is an abstract method that is overridden by the sub-classes to define
1166
- # the chart types such as Column, Line, Pie, etc.
1167
- #
1168
- def store_chart_type # :nodoc:
1169
-
1170
- end
1171
-
1172
- ###############################################################################
1173
- #
1174
- # _store_marker_dataformat_stream()
1175
- #
1176
- # This is an abstract method that is overridden by the sub-classes to define
1177
- # properties of markers, linetypes, pie formats and other.
1178
- #
1179
- def store_marker_dataformat_stream # :nodoc:
1180
-
1181
- end
1182
-
1183
- ###############################################################################
1184
- #
1185
- # _store_legend_stream()
1186
- #
1187
- # Write the LEGEND chart substream.
1188
- #
1189
- def store_legend_stream # :nodoc:
1190
- store_legend(*@config[:legend])
1191
-
1192
- store_begin
1193
- store_pos(*@config[:legend_pos])
1194
- store_legend_text_stream
1195
- store_end
1196
- end
1197
-
1198
- ###############################################################################
1199
- #
1200
- # BIFF Records.
1201
- #
1202
- ###############################################################################
1203
-
1204
- ###############################################################################
1205
- #
1206
- # _store_3dbarshape()
1207
- #
1208
- # Write the 3DBARSHAPE chart BIFF record.
1209
- #
1210
- def store_3dbarshape # :nodoc:
1211
- record = 0x105F # Record identifier.
1212
- length = 0x0002 # Number of bytes to follow.
1213
- riser = 0x00 # Shape of base.
1214
- taper = 0x00 # Column taper type.
1215
-
1216
- header = [record, length].pack('vv')
1217
- data = [riser].pack('C')
1218
- data += [taper].pack('C')
1219
-
1220
- append(header, data)
1221
- end
1222
-
1223
- ###############################################################################
1224
- #
1225
- # _store_ai()
1226
- #
1227
- # Write the AI chart BIFF record.
1228
- #
1229
- def store_ai(id, type, formula, format_index = 0) # :nodoc:
1230
- formula = '' if formula == [""]
1231
-
1232
- record = 0x1051 # Record identifier.
1233
- length = 0x0008 # Number of bytes to follow.
1234
- # id # Link index.
1235
- # type # Reference type.
1236
- # formula # Pre-parsed formula.
1237
- # format_index # Num format index.
1238
- grbit = 0x0000 # Option flags.
1239
-
1240
- formula = convert_to_ascii_if_ascii(formula)
1241
-
1242
- formula_length = formula.bytesize
1243
- length += formula_length
1244
-
1245
- header = [record, length].pack('vv')
1246
- data = [id].pack('C')
1247
- data += [type].pack('C')
1248
- data += [grbit].pack('v')
1249
- data += [format_index].pack('v')
1250
- data += [formula_length].pack('v')
1251
- if formula.respond_to?(:to_array)
1252
- data += formula[0].encode('BINARY')
1253
- else
1254
- data += formula.encode('BINARY') unless formula.nil?
1255
- end
1256
-
1257
- append(header, data)
1258
- end
1259
-
1260
- ###############################################################################
1261
- #
1262
- # _store_areaformat()
1263
- #
1264
- # Write the AREAFORMAT chart BIFF record. Contains the patterns and colours
1265
- # of a chart area.
1266
- #
1267
- def store_areaformat(rgbFore, rgbBack, pattern, grbit, indexFore, indexBack) # :nodoc:
1268
- record = 0x100A # Record identifier.
1269
- length = 0x0010 # Number of bytes to follow.
1270
- # rgbFore # Foreground RGB colour.
1271
- # rgbBack # Background RGB colour.
1272
- # pattern # Pattern.
1273
- # grbit # Option flags.
1274
- # indexFore # Index to Foreground colour.
1275
- # indexBack # Index to Background colour.
1276
-
1277
- header = [record, length].pack('vv')
1278
- data = [rgbFore].pack('V')
1279
- data += [rgbBack].pack('V')
1280
- data += [pattern].pack('v')
1281
- data += [grbit].pack('v')
1282
- data += [indexFore].pack('v')
1283
- data += [indexBack].pack('v')
1284
-
1285
- append(header, data)
1286
- end
1287
-
1288
- ###############################################################################
1289
- #
1290
- # _store_axcext()
1291
- #
1292
- # Write the AXCEXT chart BIFF record.
1293
- #
1294
- def store_axcext # :nodoc:
1295
- record = 0x1062 # Record identifier.
1296
- length = 0x0012 # Number of bytes to follow.
1297
- catMin = 0x0000 # Minimum category on axis.
1298
- catMax = 0x0000 # Maximum category on axis.
1299
- catMajor = 0x0001 # Value of major unit.
1300
- unitMajor = 0x0000 # Units of major unit.
1301
- catMinor = 0x0001 # Value of minor unit.
1302
- unitMinor = 0x0000 # Units of minor unit.
1303
- unitBase = 0x0000 # Base unit of axis.
1304
- catCrossDate = 0x0000 # Crossing point.
1305
- grbit = 0x00EF # Option flags.
1306
-
1307
- store_simple(record, length, catMin, catMax, catMajor, unitMajor,
1308
- catMinor, unitMinor, unitBase, catCrossDate, grbit)
1309
- end
1310
-
1311
- ###############################################################################
1312
- #
1313
- # _store_axesused()
1314
- #
1315
- # Write the AXESUSED chart BIFF record.
1316
- #
1317
- def store_axesused(num_axes) # :nodoc:
1318
- record = 0x1046 # Record identifier.
1319
- length = 0x0002 # Number of bytes to follow.
1320
- # num_axes # Number of axes used.
1321
-
1322
- store_simple(record, length, num_axes)
1323
- end
1324
-
1325
- ###############################################################################
1326
- #
1327
- # _store_axis()
1328
- #
1329
- # Write the AXIS chart BIFF record to define the axis type.
1330
- #
1331
- def store_axis(type) # :nodoc:
1332
- record = 0x101D # Record identifier.
1333
- length = 0x0012 # Number of bytes to follow.
1334
- # type # Axis type.
1335
- reserved1 = 0x00000000 # Reserved.
1336
- reserved2 = 0x00000000 # Reserved.
1337
- reserved3 = 0x00000000 # Reserved.
1338
- reserved4 = 0x00000000 # Reserved.
1339
-
1340
- header = [record, length].pack('vv')
1341
- data = [type].pack('v')
1342
- data += [reserved1].pack('V')
1343
- data += [reserved2].pack('V')
1344
- data += [reserved3].pack('V')
1345
- data += [reserved4].pack('V')
1346
-
1347
- append(header, data)
1348
- end
1349
-
1350
- ###############################################################################
1351
- #
1352
- # _store_axislineformat()
1353
- #
1354
- # Write the AXISLINEFORMAT chart BIFF record.
1355
- #
1356
- def store_axislineformat # :nodoc:
1357
- record = 0x1021 # Record identifier.
1358
- length = 0x0002 # Number of bytes to follow.
1359
- line_format = 0x0001 # Axis line format.
1360
-
1361
- store_simple(record, length, line_format)
1362
- end
1363
-
1364
- ###############################################################################
1365
- #
1366
- # _store_axisparent()
1367
- #
1368
- # Write the AXISPARENT chart BIFF record.
1369
- #
1370
- def store_axisparent(iax, x, y, dx, dy) # :nodoc:
1371
- record = 0x1041 # Record identifier.
1372
- length = 0x0012 # Number of bytes to follow.
1373
- # iax # Axis index.
1374
- # x # X-coord.
1375
- # y # Y-coord.
1376
- # dx # Length of x axis.
1377
- # dy # Length of y axis.
1378
-
1379
- header = [record, length].pack('vv')
1380
- data = [iax].pack('v')
1381
- data += [x].pack('V')
1382
- data += [y].pack('V')
1383
- data += [dx].pack('V')
1384
- data += [dy].pack('V')
1385
-
1386
- append(header, data)
1387
- end
1388
-
1389
- ###############################################################################
1390
- #
1391
- # _store_begin()
1392
- #
1393
- # Write the BEGIN chart BIFF record to indicate the start of a sub stream.
1394
- #
1395
- def store_begin # :nodoc:
1396
- record = 0x1033 # Record identifier.
1397
- length = 0x0000 # Number of bytes to follow.
1398
-
1399
- store_simple(record, length)
1400
- end
1401
-
1402
- ###############################################################################
1403
- #
1404
- # _store_catserrange()
1405
- #
1406
- # Write the CATSERRANGE chart BIFF record.
1407
- #
1408
- def store_catserrange # :nodoc:
1409
- record = 0x1020 # Record identifier.
1410
- length = 0x0008 # Number of bytes to follow.
1411
- catCross = 0x0001 # Value/category crossing.
1412
- catLabel = 0x0001 # Frequency of labels.
1413
- catMark = 0x0001 # Frequency of ticks.
1414
- grbit = 0x0001 # Option flags.
1415
-
1416
- store_simple(record, length, catCross, catLabel, catMark, grbit)
1417
- end
1418
-
1419
- ###############################################################################
1420
- #
1421
- # _store_chart()
1422
- #
1423
- # Write the CHART BIFF record. This indicates the start of the chart sub-stream
1424
- # and contains dimensions of the chart on the display. Units are in 1/72 inch
1425
- # and are 2 byte integer with 2 byte fraction.
1426
- #
1427
- def store_chart(x_pos, y_pos, dx, dy) # :nodoc:
1428
- record = 0x1002 # Record identifier.
1429
- length = 0x0010 # Number of bytes to follow.
1430
- # x_pos # X pos of top left corner.
1431
- # y_pos # Y pos of top left corner.
1432
- # dx # X size.
1433
- # dy # Y size.
1434
-
1435
- header = [record, length].pack('vv')
1436
- data = [x_pos].pack('V')
1437
- data += [y_pos].pack('V')
1438
- data += [dx].pack('V')
1439
- data += [dy].pack('V')
1440
-
1441
- append(header, data)
1442
- end
1443
-
1444
- ###############################################################################
1445
- #
1446
- # _store_chartformat()
1447
- #
1448
- # Write the CHARTFORMAT chart BIFF record. The parent record for formatting
1449
- # of a chart group.
1450
- #
1451
- def store_chartformat(grbit = 0) # :nodoc:
1452
- record = 0x1014 # Record identifier.
1453
- length = 0x0014 # Number of bytes to follow.
1454
- reserved1 = 0x00000000 # Reserved.
1455
- reserved2 = 0x00000000 # Reserved.
1456
- reserved3 = 0x00000000 # Reserved.
1457
- reserved4 = 0x00000000 # Reserved.
1458
- # grbit # Option flags.
1459
- icrt = 0x0000 # Drawing order.
1460
-
1461
- header = [record, length].pack('vv')
1462
- data = [reserved1].pack('V')
1463
- data += [reserved2].pack('V')
1464
- data += [reserved3].pack('V')
1465
- data += [reserved4].pack('V')
1466
- data += [grbit].pack('v')
1467
- data += [icrt].pack('v')
1468
-
1469
- append(header, data)
1470
- end
1471
-
1472
- ###############################################################################
1473
- #
1474
- # _store_chartline()
1475
- #
1476
- # Write the CHARTLINE chart BIFF record.
1477
- #
1478
- def store_chartline # :nodoc:
1479
- record = 0x101C # Record identifier.
1480
- length = 0x0002 # Number of bytes to follow.
1481
- type = 0x0001 # Drop/hi-lo line type.
1482
-
1483
- store_simple(record, length, type)
1484
- end
1485
-
1486
- ###############################################################################
1487
- #
1488
- # _store_charttext()
1489
- #
1490
- # Write the TEXT chart BIFF record.
1491
- #
1492
- def store_charttext # :nodoc:
1493
- record = 0x1025 # Record identifier.
1494
- length = 0x0020 # Number of bytes to follow.
1495
- horz_align = 0x02 # Horizontal alignment.
1496
- vert_align = 0x02 # Vertical alignment.
1497
- bg_mode = 0x0001 # Background display.
1498
- text_color_rgb = 0x00000000 # Text RGB colour.
1499
- text_x = 0xFFFFFF46 # Text x-pos.
1500
- text_y = 0xFFFFFF06 # Text y-pos.
1501
- text_dx = 0x00000000 # Width.
1502
- text_dy = 0x00000000 # Height.
1503
- grbit1 = 0x00B1 # Options
1504
- text_color_index = 0x004D # Auto Colour.
1505
- grbit2 = 0x0000 # Data label placement.
1506
- rotation = 0x0000 # Text rotation.
1507
-
1508
- header = [record, length].pack('vv')
1509
- data = [horz_align].pack('C')
1510
- data += [vert_align].pack('C')
1511
- data += [bg_mode].pack('v')
1512
- data += [text_color_rgb].pack('V')
1513
- data += [text_x].pack('V')
1514
- data += [text_y].pack('V')
1515
- data += [text_dx].pack('V')
1516
- data += [text_dy].pack('V')
1517
- data += [grbit1].pack('v')
1518
- data += [text_color_index].pack('v')
1519
- data += [grbit2].pack('v')
1520
- data += [rotation].pack('v')
1521
-
1522
- append(header, data)
1523
- end
1524
-
1525
- ###############################################################################
1526
- #
1527
- # _store_dataformat()
1528
- #
1529
- # Write the DATAFORMAT chart BIFF record. This record specifies the series
1530
- # that the subsequent sub stream refers to.
1531
- #
1532
- def store_dataformat(series_index, series_number, point_number) # :nodoc:
1533
- record = 0x1006 # Record identifier.
1534
- length = 0x0008 # Number of bytes to follow.
1535
- # series_index # Series index.
1536
- # series_number # Series number. (Same as index).
1537
- # point_number # Point number.
1538
- grbit = 0x0000 # Format flags.
1539
-
1540
- store_simple(record, length, point_number, series_index, series_number, grbit)
1541
- end
1542
-
1543
- ###############################################################################
1544
- #
1545
- # _store_defaulttext()
1546
- #
1547
- # Write the DEFAULTTEXT chart BIFF record. Identifier for subsequent TEXT
1548
- # record.
1549
- #
1550
- def store_defaulttext # :nodoc:
1551
- record = 0x1024 # Record identifier.
1552
- length = 0x0002 # Number of bytes to follow.
1553
- type = 0x0002 # Type.
1554
-
1555
- store_simple(record, length, type)
1556
- end
1557
-
1558
- ###############################################################################
1559
- #
1560
- # _store_dropbar()
1561
- #
1562
- # Write the DROPBAR chart BIFF record.
1563
- #
1564
- def store_dropbar # :nodoc:
1565
- record = 0x103D # Record identifier.
1566
- length = 0x0002 # Number of bytes to follow.
1567
- percent_gap = 0x0096 # Drop bar width gap (%).
1568
-
1569
- store_simple(record, length, percent_gap)
1570
- end
1571
-
1572
- ###############################################################################
1573
- #
1574
- # _store_end()
1575
- #
1576
- # Write the END chart BIFF record to indicate the end of a sub stream.
1577
- #
1578
- def store_end # :nodoc:
1579
- record = 0x1034 # Record identifier.
1580
- length = 0x0000 # Number of bytes to follow.
1581
-
1582
- store_simple(record, length)
1583
- end
1584
-
1585
- ###############################################################################
1586
- # _store_fbi()
1587
- #
1588
- # Write the FBI chart BIFF record. Specifies the font information at the time
1589
- # it was applied to the chart.
1590
- #
1591
- def store_fbi(index, height, width_basis, height_basis, scale_basis) # :nodoc:
1592
- record = 0x1060 # Record identifier.
1593
- length = 0x000A # Number of bytes to follow.
1594
- # index # Font index.
1595
- height = height * 20 # Default font height in twips.
1596
- # width_basis # Width basis, in twips.
1597
- # height_basis # Height basis, in twips.
1598
- # scale_basis # Scale by chart area or plot area.
1599
-
1600
- store_simple(record, length, width_basis, height_basis, height, scale_basis, index)
1601
- end
1602
-
1603
- ###############################################################################
1604
- #
1605
- # _store_fontx()
1606
- #
1607
- # Write the FONTX chart BIFF record which contains the index of the FONT
1608
- # record in the Workbook.
1609
- #
1610
- def store_fontx(index) # :nodoc:
1611
- record = 0x1026 # Record identifier.
1612
- length = 0x0002 # Number of bytes to follow.
1613
- # index # Font index.
1614
-
1615
- store_simple(record, length, index)
1616
- end
1617
-
1618
- ###############################################################################
1619
- #
1620
- # _store_frame()
1621
- #
1622
- # Write the FRAME chart BIFF record.
1623
- #
1624
- def store_frame(frame_type, grbit) # :nodoc:
1625
- record = 0x1032 # Record identifier.
1626
- length = 0x0004 # Number of bytes to follow.
1627
- # frame_type # Frame type.
1628
- # grbit # Option flags.
1629
-
1630
- store_simple(record, length, frame_type, grbit)
1631
- end
1632
-
1633
- ###############################################################################
1634
- #
1635
- # _store_legend()
1636
- #
1637
- # Write the LEGEND chart BIFF record. The Marcus Horan method.
1638
- #
1639
- def store_legend(x, y, width, height, wType, wSpacing, grbit) # :nodoc:
1640
- record = 0x1015 # Record identifier.
1641
- length = 0x0014 # Number of bytes to follow.
1642
- # x # X-position.
1643
- # y # Y-position.
1644
- # width # Width.
1645
- # height # Height.
1646
- # wType # Type.
1647
- # wSpacing # Spacing.
1648
- # grbit # Option flags.
1649
-
1650
- header = [record, length].pack('vv')
1651
- data = [x].pack('V')
1652
- data += [y].pack('V')
1653
- data += [width].pack('V')
1654
- data += [height].pack('V')
1655
- data += [wType].pack('C')
1656
- data += [wSpacing].pack('C')
1657
- data += [grbit].pack('v')
1658
-
1659
- append(header, data)
1660
- end
1661
-
1662
- ###############################################################################
1663
- #
1664
- # _store_lineformat()
1665
- #
1666
- # Write the LINEFORMAT chart BIFF record.
1667
- #
1668
- def store_lineformat(rgb, lns, we, grbit, index) # :nodoc:
1669
- record = 0x1007 # Record identifier.
1670
- length = 0x000C # Number of bytes to follow.
1671
- # rgb # Line RGB colour.
1672
- # lns # Line pattern.
1673
- # we # Line weight.
1674
- # grbit # Option flags.
1675
- # index # Index to colour of line.
1676
-
1677
- header = [record, length].pack('vv')
1678
- data = [rgb].pack('V')
1679
- data += [lns].pack('v')
1680
- data += [we].pack('v')
1681
- data += [grbit].pack('v')
1682
- data += [index].pack('v')
1683
-
1684
- append(header, data)
1685
- end
1686
-
1687
- ###############################################################################
1688
- #
1689
- # _store_markerformat()
1690
- #
1691
- # Write the MARKERFORMAT chart BIFF record.
1692
- #
1693
- def store_markerformat(rgbFore, rgbBack, marker, grbit, icvFore, icvBack, miSize)# :nodoc:
1694
- record = 0x1009 # Record identifier.
1695
- length = 0x0014 # Number of bytes to follow.
1696
- # rgbFore # Foreground RGB color.
1697
- # rgbBack # Background RGB color.
1698
- # marker # Type of marker.
1699
- # grbit # Format flags.
1700
- # icvFore # Color index marker border.
1701
- # icvBack # Color index marker fill.
1702
- # miSize # Size of line markers.
1703
-
1704
- header = [record, length].pack('vv')
1705
- data = [rgbFore].pack('V')
1706
- data += [rgbBack].pack('V')
1707
- data += [marker].pack('v')
1708
- data += [grbit].pack('v')
1709
- data += [icvFore].pack('v')
1710
- data += [icvBack].pack('v')
1711
- data += [miSize].pack('V')
1712
-
1713
- append(header, data)
1714
- end
1715
-
1716
- ###############################################################################
1717
- #
1718
- # _store_objectlink()
1719
- #
1720
- # Write the OBJECTLINK chart BIFF record.
1721
- #
1722
- def store_objectlink(link_type) # :nodoc:
1723
- record = 0x1027 # Record identifier.
1724
- length = 0x0006 # Number of bytes to follow.
1725
- # link_type # Object text link type.
1726
- link_index1 = 0x0000 # Link index 1.
1727
- link_index2 = 0x0000 # Link index 2.
1728
-
1729
- store_simple(record, length, link_type, link_index1, link_index2)
1730
- end
1731
-
1732
- ###############################################################################
1733
- #
1734
- # _store_pieformat()
1735
- #
1736
- # Write the PIEFORMAT chart BIFF record.
1737
- #
1738
- def store_pieformat # :nodoc:
1739
- record = 0x100B # Record identifier.
1740
- length = 0x0002 # Number of bytes to follow.
1741
- percent = 0x0000 # Distance % from center.
1742
-
1743
- store_simple(record, length, percent)
1744
- end
1745
-
1746
- ###############################################################################
1747
- #
1748
- # _store_plotarea()
1749
- #
1750
- # Write the PLOTAREA chart BIFF record. This indicates that the subsequent
1751
- # FRAME record belongs to a plot area.
1752
- #
1753
- def store_plotarea # :nodoc:
1754
- record = 0x1035 # Record identifier.
1755
- length = 0x0000 # Number of bytes to follow.
1756
-
1757
- store_simple(record, length)
1758
- end
1759
-
1760
- ###############################################################################
1761
- #
1762
- # _store_plotgrowth()
1763
- #
1764
- # Write the PLOTGROWTH chart BIFF record.
1765
- #
1766
- def store_plotgrowth # :nodoc:
1767
- record = 0x1064 # Record identifier.
1768
- length = 0x0008 # Number of bytes to follow.
1769
- dx_plot = 0x00010000 # Horz growth for font scale.
1770
- dy_plot = 0x00010000 # Vert growth for font scale.
1771
-
1772
- header = [record, length].pack('vv')
1773
- data = [dx_plot].pack('V')
1774
- data += [dy_plot].pack('V')
1775
-
1776
- append(header, data)
1777
- end
1778
-
1779
- ###############################################################################
1780
- #
1781
- # _store_pos()
1782
- #
1783
- # Write the POS chart BIFF record. Generally not required when using
1784
- # automatic positioning.
1785
- #
1786
- def store_pos(mdTopLt, mdBotRt, x1, y1, x2, y2) # :nodoc:
1787
- record = 0x104F # Record identifier.
1788
- length = 0x0014 # Number of bytes to follow.
1789
- # mdTopLt # Top left.
1790
- # mdBotRt # Bottom right.
1791
- # x1 # X coordinate.
1792
- # y1 # Y coordinate.
1793
- # x2 # Width.
1794
- # y2 # Height.
1795
-
1796
- header = [record, length].pack('vv')
1797
- data = [mdTopLt].pack('v')
1798
- data += [mdBotRt].pack('v')
1799
- data += [x1].pack('V')
1800
- data += [y1].pack('V')
1801
- data += [x2].pack('V')
1802
- data += [y2].pack('V')
1803
-
1804
- append(header, data)
1805
- end
1806
-
1807
- ###############################################################################
1808
- #
1809
- # _store_serauxtrend()
1810
- #
1811
- # Write the SERAUXTREND chart BIFF record.
1812
- #
1813
- def store_serauxtrend(reg_type, poly_order, equation, r_squared) # :nodoc:
1814
- record = 0x104B # Record identifier.
1815
- length = 0x001C # Number of bytes to follow.
1816
- # reg_type # Regression type.
1817
- # poly_order # Polynomial order.
1818
- # equation # Display equation.
1819
- # r_squared # Display R-squared.
1820
- # intercept # Forced intercept.
1821
- # forecast # Forecast forward.
1822
- # backcast # Forecast backward.
1823
-
1824
- # TODO. When supported, intercept needs to be NAN if not used.
1825
- # Also need to reverse doubles.
1826
- intercept = ['FFFFFFFF0001FFFF'].pack('H*')
1827
- forecast = ['0000000000000000'].pack('H*')
1828
- backcast = ['0000000000000000'].pack('H*')
1829
-
1830
- header = [record, length].pack('vv')
1831
- data = [reg_type].pack('C')
1832
- data += [poly_order].pack('C')
1833
- data += intercept
1834
- data += [equation].pack('C')
1835
- data += [r_squared].pack('C')
1836
- data += forecast
1837
- data += backcast
1838
-
1839
- append(header, data)
1840
- end
1841
-
1842
- ###############################################################################
1843
- #
1844
- # _store_series()
1845
- #
1846
- # Write the SERIES chart BIFF record.
1847
- #
1848
- def store_series(category_count, value_count) # :nodoc:
1849
- record = 0x1003 # Record identifier.
1850
- length = 0x000C # Number of bytes to follow.
1851
- category_type = 0x0001 # Type: category.
1852
- value_type = 0x0001 # Type: value.
1853
- # category_count # Num of categories.
1854
- # value_count # Num of values.
1855
- bubble_type = 0x0001 # Type: bubble.
1856
- bubble_count = 0x0000 # Num of bubble values.
1857
-
1858
- store_simple(record, length, category_type, value_type,
1859
- category_count, value_count, bubble_type, bubble_count)
1860
- end
1861
-
1862
- ###############################################################################
1863
- #
1864
- # _store_seriestext()
1865
- #
1866
- # Write the SERIESTEXT chart BIFF record.
1867
- #
1868
- def store_seriestext(str, encoding) # :nodoc:
1869
- str = convert_to_ascii_if_ascii(str)
1870
-
1871
- record = 0x100D # Record identifier.
1872
- length = 0x0000 # Number of bytes to follow.
1873
- id = 0x0000 # Text id.
1874
- # str # Text.
1875
- # encoding # String encoding.
1876
- cch = str.bytesize # String length.
1877
-
1878
- encoding ||= 0
1879
-
1880
- # Character length is num of chars not num of bytes
1881
- cch /= 2 if encoding != 0
1882
-
1883
- # Change the UTF-16 name from BE to LE
1884
- str = str.unpack('v*').pack('n*') if encoding != 0
1885
-
1886
- length = 4 + str.bytesize
1887
-
1888
- header = [record, length].pack('vv')
1889
- data = [id].pack('v')
1890
- data += [cch].pack('C')
1891
- data += [encoding].pack('C')
1892
-
1893
- append(header, data, str)
1894
- end
1895
-
1896
- ###############################################################################
1897
- #
1898
- # _store_serparent()
1899
- #
1900
- # Write the SERPARENT chart BIFF record.
1901
- #
1902
- def store_serparent(series) # :nodoc:
1903
- record = 0x104A # Record identifier.
1904
- length = 0x0002 # Number of bytes to follow.
1905
- # series # Series parent.
1906
-
1907
- store_simple(record, length, series)
1908
- end
1909
-
1910
- ###############################################################################
1911
- #
1912
- # _store_sertocrt()
1913
- #
1914
- # Write the SERTOCRT chart BIFF record to indicate the chart group index.
1915
- #
1916
- def store_sertocrt # :nodoc:
1917
- record = 0x1045 # Record identifier.
1918
- length = 0x0002 # Number of bytes to follow.
1919
- chartgroup = 0x0000 # Chart group index.
1920
-
1921
- store_simple(record, length, chartgroup)
1922
- end
1923
-
1924
- ###############################################################################
1925
- #
1926
- # _store_shtprops()
1927
- #
1928
- # Write the SHTPROPS chart BIFF record.
1929
- #
1930
- def store_shtprops # :nodoc:
1931
- record = 0x1044 # Record identifier.
1932
- length = 0x0004 # Number of bytes to follow.
1933
- grbit = 0x000E # Option flags.
1934
- empty_cells = 0x0000 # Empty cell handling.
1935
-
1936
- grbit = 0x000A if @embedded
1937
-
1938
- store_simple(record, length, grbit, empty_cells)
1939
- end
1940
-
1941
- ###############################################################################
1942
- #
1943
- # _store_text()
1944
- #
1945
- # Write the TEXT chart BIFF record.
1946
- #
1947
- def store_text(x, y, dx, dy, grbit1, grbit2, rotation = 0x00)# :nodoc:
1948
- record = 0x1025 # Record identifier.
1949
- length = 0x0020 # Number of bytes to follow.
1950
- at = 0x02 # Horizontal alignment.
1951
- vat = 0x02 # Vertical alignment.
1952
- wBkgMode = 0x0001 # Background display.
1953
- rgbText = 0x0000 # Text RGB colour.
1954
- # x # Text x-pos.
1955
- # y # Text y-pos.
1956
- # dx # Width.
1957
- # dy # Height.
1958
- # grbit1 # Option flags.
1959
- icvText = 0x004D # Auto Colour.
1960
- # grbit2 # Show legend.
1961
- # rotation # Show value.
1962
-
1963
- header = [record, length].pack('vv')
1964
- data = [at].pack('C')
1965
- data += [vat].pack('C')
1966
- data += [wBkgMode].pack('v')
1967
- data += [rgbText].pack('V')
1968
- data += [x].pack('V')
1969
- data += [y].pack('V')
1970
- data += [dx].pack('V')
1971
- data += [dy].pack('V')
1972
- data += [grbit1].pack('v')
1973
- data += [icvText].pack('v')
1974
- data += [grbit2].pack('v')
1975
- data += [rotation].pack('v')
1976
-
1977
- append(header, data)
1978
- end
1979
-
1980
- ###############################################################################
1981
- #
1982
- # _store_tick()
1983
- #
1984
- # Write the TICK chart BIFF record.
1985
- #
1986
- def store_tick # :nodoc:
1987
- record = 0x101E # Record identifier.
1988
- length = 0x001E # Number of bytes to follow.
1989
- tktMajor = 0x02 # Type of major tick mark.
1990
- tktMinor = 0x00 # Type of minor tick mark.
1991
- tlt = 0x03 # Tick label position.
1992
- wBkgMode = 0x01 # Background mode.
1993
- rgb = 0x00000000 # Tick-label RGB colour.
1994
- reserved1 = 0x00000000 # Reserved.
1995
- reserved2 = 0x00000000 # Reserved.
1996
- reserved3 = 0x00000000 # Reserved.
1997
- reserved4 = 0x00000000 # Reserved.
1998
- grbit = 0x0023 # Option flags.
1999
- index = 0x004D # Colour index.
2000
- reserved5 = 0x0000 # Reserved.
2001
-
2002
- header = [record, length].pack('vv')
2003
- data = [tktMajor].pack('C')
2004
- data += [tktMinor].pack('C')
2005
- data += [tlt].pack('C')
2006
- data += [wBkgMode].pack('C')
2007
- data += [rgb].pack('V')
2008
- data += [reserved1].pack('V')
2009
- data += [reserved2].pack('V')
2010
- data += [reserved3].pack('V')
2011
- data += [reserved4].pack('V')
2012
- data += [grbit].pack('v')
2013
- data += [index].pack('v')
2014
- data += [reserved5].pack('v')
2015
-
2016
- append(header, data)
2017
- end
2018
-
2019
- ###############################################################################
2020
- #
2021
- # _store_valuerange()
2022
- #
2023
- # Write the VALUERANGE chart BIFF record.
2024
- #
2025
- def store_valuerange # :nodoc:
2026
- record = 0x101F # Record identifier.
2027
- length = 0x002A # Number of bytes to follow.
2028
- numMin = 0x00000000 # Minimum value on axis.
2029
- numMax = 0x00000000 # Maximum value on axis.
2030
- numMajor = 0x00000000 # Value of major increment.
2031
- numMinor = 0x00000000 # Value of minor increment.
2032
- numCross = 0x00000000 # Value where category axis crosses.
2033
- grbit = 0x011F # Format flags.
2034
-
2035
- # TODO. Reverse doubles when they are handled.
2036
-
2037
- header = [record, length].pack('vv')
2038
- data = [numMin].pack('d')
2039
- data += [numMax].pack('d')
2040
- data += [numMajor].pack('d')
2041
- data += [numMinor].pack('d')
2042
- data += [numCross].pack('d')
2043
- data += [grbit].pack('v')
2044
-
2045
- append(header, data)
2046
- end
2047
-
2048
-
2049
- ###############################################################################
2050
- #
2051
- # Config data.
2052
- #
2053
- ###############################################################################
2054
-
2055
- ###############################################################################
2056
- #
2057
- # _set_default_properties()
2058
- #
2059
- # Setup the default properties for a chart.
2060
- #
2061
- def set_default_properties # :nodoc:
2062
- @legend = {
2063
- :visible => 1,
2064
- :position => 0,
2065
- :vertical => 0,
2066
- }
2067
-
2068
- @chartarea = {
2069
- :visible => 0,
2070
- :fg_color_index => 0x4E,
2071
- :fg_color_rgb => 0xFFFFFF,
2072
- :bg_color_index => 0x4D,
2073
- :bg_color_rgb => 0x000000,
2074
- :area_pattern => 0x0000,
2075
- :area_options => 0x0000,
2076
- :line_pattern => 0x0005,
2077
- :line_weight => 0xFFFF,
2078
- :line_color_index => 0x4D,
2079
- :line_color_rgb => 0x000000,
2080
- :line_options => 0x0008,
2081
- }
2082
-
2083
- @plotarea = {
2084
- :visible => 1,
2085
- :fg_color_index => 0x16,
2086
- :fg_color_rgb => 0xC0C0C0,
2087
- :bg_color_index => 0x4F,
2088
- :bg_color_rgb => 0x000000,
2089
- :area_pattern => 0x0001,
2090
- :area_options => 0x0000,
2091
- :line_pattern => 0x0000,
2092
- :line_weight => 0x0000,
2093
- :line_color_index => 0x17,
2094
- :line_color_rgb => 0x808080,
2095
- :line_options => 0x0000,
2096
- }
2097
- end
2098
-
2099
- ###############################################################################
2100
- #
2101
- # _set_default_config_data()
2102
- #
2103
- # Setup the default configuration data for a chart.
2104
- #
2105
- def set_default_config_data # :nodoc:
2106
- @config = default_config_data
2107
- end
2108
-
2109
- def default_config_data # :nodoc:
2110
- {
2111
- :axisparent => [ 0, 0x00F8, 0x01F5, 0x0E7F, 0x0B36 ],
2112
- :axisparent_pos => [ 2, 2, 0x008C, 0x01AA, 0x0EEA, 0x0C52 ],
2113
- :chart => [ 0x0000, 0x0000, 0x02DD51E0, 0x01C2B838 ],
2114
- :font_numbers => [ 5, 10, 0x38B8, 0x22A1, 0x0000 ],
2115
- :font_series => [ 6, 10, 0x38B8, 0x22A1, 0x0001 ],
2116
- :font_title => [ 7, 12, 0x38B8, 0x22A1, 0x0000 ],
2117
- :font_axes => [ 8, 10, 0x38B8, 0x22A1, 0x0001 ],
2118
- :legend => [ 0x05F9, 0x0EE9, 0x047D, 0x9C, 0x00, 0x01, 0x0F ],
2119
- :legend_pos => [ 5, 2, 0x05F9, 0x0EE9, 0, 0 ],
2120
- :legend_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x0000 ],
2121
- :legend_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2122
- :series_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x1020 ],
2123
- :series_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2124
- :title_text => [ 0x06E4, 0x0051, 0x01DB, 0x00C4, 0x0081, 0x1030 ],
2125
- :title_text_pos => [ 2, 2, 0, 0, 0x73, 0x1D ],
2126
- :x_axis_text => [ 0x07E1, 0x0DFC, 0xB2, 0x9C, 0x0081, 0x0000 ],
2127
- :x_axis_text_pos => [ 2, 2, 0, 0, 0x2B, 0x17 ],
2128
- :y_axis_text => [ 0x002D, 0x06AA, 0x5F, 0x1CC, 0x0281, 0x00, 90 ],
2129
- :y_axis_text_pos => [ 2, 2, 0, 0, 0x17, 0x44 ],
2130
- }
2131
- end
2132
- private :default_config_data
2133
-
2134
- ###############################################################################
2135
- #
2136
- # _set_embedded_config_data()
2137
- #
2138
- # Setup the default configuration data for an embedded chart.
2139
- #
2140
- def set_embedded_config_data # :nodoc:
2141
- @embedded = true
2142
-
2143
- @chartarea = {
2144
- :visible => 1,
2145
- :fg_color_index => 0x4E,
2146
- :fg_color_rgb => 0xFFFFFF,
2147
- :bg_color_index => 0x4D,
2148
- :bg_color_rgb => 0x000000,
2149
- :area_pattern => 0x0001,
2150
- :area_options => 0x0001,
2151
- :line_pattern => 0x0000,
2152
- :line_weight => 0x0000,
2153
- :line_color_index => 0x4D,
2154
- :line_color_rgb => 0x000000,
2155
- :line_options => 0x0009,
2156
- }
2157
-
2158
- @config = default_config_data.merge({
2159
- :axisparent => [ 0, 0x01D8, 0x031D, 0x0D79, 0x07E9 ],
2160
- :axisparent_pos => [ 2, 2, 0x010C, 0x0292, 0x0E46, 0x09FD ],
2161
- :chart => [ 0x0000, 0x0000, 0x01847FE8, 0x00F47FE8 ],
2162
- :font_numbers => [ 5, 10, 0x1DC4, 0x1284, 0x0000 ],
2163
- :font_series => [ 6, 10, 0x1DC4, 0x1284, 0x0001 ],
2164
- :font_title => [ 7, 12, 0x1DC4, 0x1284, 0x0000 ],
2165
- :font_axes => [ 8, 10, 0x1DC4, 0x1284, 0x0001 ],
2166
- :legend => [ 0x044E, 0x0E4A, 0x088D, 0x0123, 0x0, 0x1, 0xF ],
2167
- :legend_pos => [ 5, 2, 0x044E, 0x0E4A, 0, 0 ],
2168
- :legend_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x0000 ],
2169
- :series_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x1020 ],
2170
- :title_text => [ 0x060F, 0x004C, 0x038A, 0x016F, 0x0081, 0x1030 ],
2171
- :x_axis_text => [ 0x07EF, 0x0C8F, 0x153, 0x123, 0x81, 0x00 ],
2172
- :y_axis_text => [ 0x0057, 0x0564, 0xB5, 0x035D, 0x0281, 0x00, 90 ],
2173
- })
2174
- end
2175
- end # class Chart
2176
-
2177
- end # module Writeexcel
1
+ # -*- coding: utf-8 -*-
2
+ ###############################################################################
3
+ #
4
+ # Chart - A writer class for Excel Charts.
5
+ #
6
+ #
7
+ # Used in conjunction with WriteExcel
8
+ #
9
+ # Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
10
+ #
11
+ # original written in Perl by John McNamara
12
+ # converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
13
+ #
14
+
15
+ require 'writeexcel/worksheet'
16
+ require 'writeexcel/colors'
17
+
18
+ ###############################################################################
19
+ #
20
+ # Formatting information.
21
+ #
22
+ # perltidy with options: -mbl=2 -pt=0 -nola
23
+ #
24
+ # Any camel case Hungarian notation style variable names in the BIFF record
25
+ # writing sub-routines below are for similarity with names used in the Excel
26
+ # documentation. Otherwise lowercase underscore style names are used.
27
+ #
28
+
29
+
30
+ ###############################################################################
31
+ #
32
+ # The chart class hierarchy is as follows. Chart.pm acts as a factory for the
33
+ # sub-classes.
34
+ #
35
+ #
36
+ # BIFFwriter
37
+ # ^
38
+ # |
39
+ # Writeexcel::Worksheet
40
+ # ^
41
+ # |
42
+ # Writeexcel::Chart
43
+ # ^
44
+ # |
45
+ # Writeexcel::Chart::* (sub-types)
46
+ #
47
+
48
+ #
49
+ # = Chart
50
+ # Chart - A writer class for Excel Charts.
51
+ #
52
+ module Writeexcel
53
+
54
+ class Chart < Worksheet
55
+ require 'writeexcel/helper'
56
+
57
+ NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
58
+
59
+ ###############################################################################
60
+ #
61
+ # factory()
62
+ #
63
+ # Factory method for returning chart objects based on their class type.
64
+ #
65
+ def self.factory(type, *args) #:nodoc:
66
+ klass =
67
+ case type
68
+ when 'Chart::Column'
69
+ Chart::Column
70
+ when 'Chart::Bar'
71
+ Chart::Bar
72
+ when 'Chart::Line'
73
+ Chart::Line
74
+ when 'Chart::Area'
75
+ Chart::Area
76
+ when 'Chart::Pie'
77
+ Chart::Pie
78
+ when 'Chart::Scatter'
79
+ Chart::Scatter
80
+ when 'Chart::Stock'
81
+ Chart::Stock
82
+ end
83
+
84
+ klass.new(*args)
85
+ end
86
+
87
+ ###############################################################################
88
+ #
89
+ # :call-seq:
90
+ # new(filename, name, index, encoding, activesheet, firstsheet, external_bin = nil)
91
+ #
92
+ # Default constructor for sub-classes.
93
+ #
94
+ def initialize(*args) #:nodoc:
95
+ super
96
+
97
+ @sheet_type = 0x0200
98
+ @orientation = 0x0
99
+ @series = []
100
+ @embedded = false
101
+
102
+ @external_bin = false
103
+ @x_axis_formula = nil
104
+ @x_axis_name = nil
105
+ @y_axis_formula = nil
106
+ @y_axis_name = nil
107
+ @title_name = nil
108
+ @title_formula = nil
109
+ @vary_data_color = 0
110
+ set_default_properties
111
+ set_default_config_data
112
+ end
113
+
114
+ #
115
+ # Add a series and it's properties to a chart.
116
+ #
117
+ # In an Excel chart a "series" is a collection of information such as values,
118
+ # x-axis labels and the name that define which data is plotted. These
119
+ # settings are displayed when you select the Chart -> Source Data... menu
120
+ # option.
121
+ #
122
+ # With a WriteExcel chart object the add_series() method is used to set the
123
+ # properties for a series:
124
+ #
125
+ # chart.add_series(
126
+ # :categories => '=Sheet1!$A$2:$A$10',
127
+ # :values => '=Sheet1!$B$2:$B$10',
128
+ # :name => 'Series name',
129
+ # :name_formula => '=Sheet1!$B$1'
130
+ # )
131
+ #
132
+ # The properties that can be set are:
133
+ #
134
+ # :values (required)
135
+ # :categories (optional for most chart types)
136
+ # :name (optional)
137
+ # :name_formula (optional)
138
+ #
139
+ # * :values
140
+ #
141
+ # This is the most important property of a series and must be set for
142
+ # every chart object. It links the chart with the worksheet data that
143
+ # it displays.
144
+ #
145
+ # chart.add_series(:values => '=Sheet1!$B$2:$B$10')
146
+ #
147
+ # Note the format that should be used for the formula. It is the same
148
+ # as is used in Excel. You must also add the worksheet that you are
149
+ # referring to before you link to it, via the workbook
150
+ # add_worksheet() method.
151
+ #
152
+ # * :categories
153
+ #
154
+ # This sets the chart category labels. The category is more or less
155
+ # the same as the X-axis. In most chart types the categories property
156
+ # is optional and the chart will just assume a sequential series
157
+ # from 1 .. n.
158
+ #
159
+ # chart.add_series(
160
+ # :categories => '=Sheet1!$A$2:$A$10',
161
+ # :values => '=Sheet1!$B$2:$B$10'
162
+ # )
163
+ #
164
+ # * :name
165
+ #
166
+ # Set the name for the series. The name is displayed in the chart
167
+ # legend and in the formula bar. The name property is optional and
168
+ # if it isn't supplied will default to Series 1 .. n.
169
+ #
170
+ # chart.add_series(
171
+ # ...
172
+ # :name => 'Series name'
173
+ # )
174
+ #
175
+ # * :name_formula
176
+ #
177
+ # Optional, can be used to link the name to a worksheet cell.
178
+ # See "Chart names and links".
179
+ #
180
+ # chart.add_series(
181
+ # ...
182
+ # :name => 'Series name',
183
+ # :name_formula => '=Sheet1!$B$1'
184
+ # )
185
+ #
186
+ # You can add more than one series to a chart. The series numbering and
187
+ # order in the final chart is the same as the order in which that are added.
188
+ #
189
+ # # Add the first series.
190
+ # chart.add_series(
191
+ # :categories => '=Sheet1!$A$2:$A$7',
192
+ # :values => '=Sheet1!$B$2:$B$7',
193
+ # :name => 'Test data series 1'
194
+ # )
195
+ #
196
+ # # Add another series. Category is the same but values are different.
197
+ # chart.add_series(
198
+ # :categories => '=Sheet1!$A$2:$A$7',
199
+ # :values => '=Sheet1!$C$2:$C$7',
200
+ # :name => 'Test data series 2'
201
+ # )
202
+ #
203
+ def add_series(params)
204
+ raise "Must specify 'values' in add_series()" if params[:values].nil?
205
+
206
+ # Parse the ranges to validate them and extract salient information.
207
+ value_data = parse_series_formula(params[:values])
208
+ category_data = parse_series_formula(params[:categories])
209
+ name_formula = parse_series_formula(params[:name_formula])
210
+
211
+ # Default category count to the same as the value count if not defined.
212
+ category_data[1] = value_data[1] if category_data.size < 2
213
+
214
+ # Add the parsed data to the user supplied data.
215
+ params[:values] = value_data
216
+ params[:categories] = category_data
217
+ params[:name_formula] = name_formula
218
+
219
+ # Encode the Series name.
220
+ name, encoding = encode_utf16(params[:name], params[:name_encoding])
221
+
222
+ params[:name] = name
223
+ params[:name_encoding] = encoding
224
+
225
+ @series << params
226
+ end
227
+
228
+ #
229
+ # Set the properties of the X-axis.
230
+ #
231
+ # The set_x_axis() method is used to set properties of the X axis.
232
+ #
233
+ # chart.set_x_axis(:name => 'Sample length (m)' )
234
+ #
235
+ # The properties that can be set are:
236
+ #
237
+ # :name (optional)
238
+ # :name_formula (optional)
239
+ #
240
+ # * :name
241
+ #
242
+ # Set the name (title or caption) for the axis. The name is displayed
243
+ # below the X axis. This property is optional. The default is to have
244
+ # no axis name.
245
+ #
246
+ # chart.set_x_axis( :name => 'Sample length (m)' )
247
+ #
248
+ # * :name_formula
249
+ #
250
+ # Optional, can be used to link the name to a worksheet cell.
251
+ # See "Chart names and links".
252
+ #
253
+ # chart.set_x_axis(
254
+ # :name => 'Sample length (m)',
255
+ # :name_formula => '=Sheet1!$A$1'
256
+ # )
257
+ #
258
+ # Additional axis properties such as range, divisions and ticks will be made
259
+ # available in later releases.
260
+ def set_x_axis(params)
261
+ name, encoding = encode_utf16(params[:name], params[:name_encoding])
262
+ formula = parse_series_formula(params[:name_formula])
263
+
264
+ @x_axis_name = name
265
+ @x_axis_encoding = encoding
266
+ @x_axis_formula = formula
267
+ end
268
+
269
+ #
270
+ # Set the properties of the Y-axis.
271
+ #
272
+ # The set_y_axis() method is used to set properties of the Y axis.
273
+ #
274
+ # chart.set_y_axis(:name => 'Sample weight (kg)' )
275
+ #
276
+ # The properties that can be set are:
277
+ #
278
+ # :name (optional)
279
+ # :name_formula (optional)
280
+ #
281
+ # * :name
282
+ #
283
+ # Set the name (title or caption) for the axis. The name is displayed
284
+ # to the left of the Y axis. This property is optional. The default
285
+ # is to have no axis name.
286
+ #
287
+ # chart.set_y_axis(:name => 'Sample weight (kg)' )
288
+ #
289
+ # * :name_formula
290
+ #
291
+ # Optional, can be used to link the name to a worksheet cell.
292
+ # See "Chart names and links".
293
+ #
294
+ # chart.set_y_axis(
295
+ # :name => 'Sample weight (kg)',
296
+ # :name_formula => '=Sheet1!$B$1'
297
+ # )
298
+ #
299
+ # Additional axis properties such as range, divisions and ticks will be made
300
+ # available in later releases.
301
+ #
302
+ def set_y_axis(params)
303
+ name, encoding = encode_utf16(params[:name], params[:name_encoding])
304
+ formula = parse_series_formula(params[:name_formula])
305
+
306
+ @y_axis_name = name
307
+ @y_axis_encoding = encoding
308
+ @y_axis_formula = formula
309
+ end
310
+
311
+ #
312
+ # The set_title() method is used to set properties of the chart title.
313
+ #
314
+ # chart.set_title(:name => 'Year End Results')
315
+ #
316
+ # The properties that can be set are:
317
+ #
318
+ # :name (optional)
319
+ # :name_formula (optional)
320
+ #
321
+ # * :name
322
+ #
323
+ # Set the name (title) for the chart. The name is displayed above the
324
+ # chart. This property is optional. The default is to have no chart
325
+ # title.
326
+ #
327
+ # chart.set_title(:name => 'Year End Results')
328
+ #
329
+ # * :name_formula
330
+ #
331
+ # Optional, can be used to link the name to a worksheet cell.
332
+ # See "Chart names and links".
333
+ #
334
+ # chart.set_title(
335
+ # :name => 'Year End Results',
336
+ # :name_formula => '=Sheet1!$C$1'
337
+ # )
338
+ #
339
+ def set_title(params)
340
+ name, encoding = encode_utf16( params[:name], params[:name_encoding])
341
+
342
+ formula = parse_series_formula(params[:name_formula])
343
+
344
+ @title_name = name
345
+ @title_encoding = encoding
346
+ @title_formula = formula
347
+ end
348
+
349
+ ###############################################################################
350
+ #
351
+ # set_legend()
352
+ #
353
+ # Set the properties of the chart legend.
354
+ #
355
+ def set_legend(params = {})
356
+ if params.has_key?(:position)
357
+ if params[:position].downcase == 'none'
358
+ legend[:visible] = 0
359
+ end
360
+ end
361
+ end
362
+
363
+ ###############################################################################
364
+ #
365
+ # set_plotarea()
366
+ #
367
+ # Set the properties of the chart plotarea.
368
+ #
369
+ def set_plotarea(params = {})
370
+ return if params.empty?
371
+
372
+ area = @plotarea
373
+
374
+ # Set the plotarea visibility.
375
+ if params.has_key?(:visible)
376
+ area[:visible] = params[:visible]
377
+ return if area[:visible] == 0
378
+ end
379
+
380
+ # TODO. could move this out of if statement.
381
+ area[:bg_color_index] = 0x08
382
+
383
+ # Set the chart background colour.
384
+ if params.has_key?(:color)
385
+ index, rgb = get_color_indices(params[:color])
386
+ if !index.nil?
387
+ area[:fg_color_index] = index
388
+ area[:fg_color_rgb] = rgb
389
+ area[:bg_color_index] = 0x08
390
+ area[:bg_color_rgb] = 0x000000
391
+ end
392
+ end
393
+
394
+ # Set the border line colour.
395
+ if params.has_key?(:line_color)
396
+ index, rgb = get_color_indices(params[:line_color])
397
+ if !index.nil?
398
+ area[:line_color_index] = index
399
+ area[:line_color_rgb] = rgb
400
+ end
401
+ end
402
+
403
+ # Set the border line pattern.
404
+ if params.has_key?(:line_pattern)
405
+ pattern = get_line_pattern(params[:line_pattern])
406
+ area[:line_pattern] = pattern
407
+ end
408
+
409
+ # Set the border line weight.
410
+ if params.has_key?(:line_weight)
411
+ weight = get_line_weight(params[:line_weight])
412
+ area[:line_weight] = weight
413
+ end
414
+ end
415
+
416
+ ###############################################################################
417
+ #
418
+ # set_chartarea()
419
+ #
420
+ # Set the properties of the chart chartarea.
421
+ #
422
+ def set_chartarea(params = {})
423
+ return if params.empty?
424
+
425
+ area = @chartarea
426
+
427
+ # Embedded automatic line weight has a different default value.
428
+ area[:line_weight] = 0xFFFF if @embedded
429
+
430
+ # Set the chart background colour.
431
+ if params.has_key?(:color)
432
+ index, rgb = get_color_indices(params[:color])
433
+ if !index.nil?
434
+ area[:fg_color_index] = index
435
+ area[:fg_color_rgb] = rgb
436
+ area[:bg_color_index] = 0x08
437
+ area[:bg_color_rgb] = 0x000000
438
+ area[:area_pattern] = 1
439
+ area[:area_options] = 0x0000 if @embedded
440
+ area[:visible] = 1
441
+ end
442
+ end
443
+
444
+ # Set the border line colour.
445
+ if params.has_key?(:line_color)
446
+ index, rgb = get_color_indices(params[:line_color])
447
+ if !index.nil?
448
+ area[:line_color_index] = index
449
+ area[:line_color_rgb] = rgb
450
+ area[:line_pattern] = 0x00
451
+ area[:line_options] = 0x0000
452
+ area[:visible] = 1
453
+ end
454
+ end
455
+
456
+ # Set the border line pattern.
457
+ if params.has_key?(:line_pattern)
458
+ pattern = get_line_pattern(params[:line_pattern])
459
+ area[:line_pattern] = pattern
460
+ area[:line_options] = 0x0000
461
+ area[:line_color_index] = 0x4F unless params.has_key?(:line_color)
462
+ area[:visible] = 1
463
+ end
464
+
465
+ # Set the border line weight.
466
+ if params.has_key?(:line_weight)
467
+ weight = get_line_weight(params[:line_weight])
468
+ area[:line_weight] = weight
469
+ area[:line_options] = 0x0000
470
+ area[:line_pattern] = 0x00 unless params.has_key?(:line_pattern)
471
+ area[:line_color_index] = 0x4F unless params.has_key?(:line_color)
472
+ area[:visible] = 1
473
+ end
474
+ end
475
+
476
+
477
+
478
+ def using_tmpfile=(val) # :nodoc:
479
+ @using_tmpfile = val
480
+ end
481
+
482
+ def data=(val) # :nodoc:
483
+ @data = val
484
+ end
485
+
486
+ def embedded # :nodoc:
487
+ @embedded
488
+ end
489
+
490
+ def embedded=(val) # :nodoc:
491
+ @embedded = val
492
+ end
493
+
494
+ ###############################################################################
495
+ #
496
+ # _prepend(), overridden.
497
+ #
498
+ # The parent Worksheet class needs to store some data in memory and some in
499
+ # temporary files for efficiency. The Chart* classes don't need to do this
500
+ # since they are dealing with smaller amounts of data so we override
501
+ # _prepend() to turn it into an _append() method. This allows for a more
502
+ # natural method calling order.
503
+ #
504
+ def prepend(*args) # :nodoc:
505
+ @using_tmpfile = false
506
+ append(*args)
507
+ end
508
+
509
+ ###############################################################################
510
+ #
511
+ # _close(), overridden.
512
+ #
513
+ # Create and store the Chart data structures.
514
+ #
515
+ def close # :nodoc:
516
+ # Ignore any data that has been written so far since it is probably
517
+ # from unwanted Worksheet method calls.
518
+ @data = ''
519
+
520
+ # TODO. Check for charts without a series?
521
+
522
+ # Store the chart BOF.
523
+ store_bof(0x0020)
524
+
525
+ # Store the page header
526
+ store_header
527
+
528
+ # Store the page footer
529
+ store_footer
530
+
531
+ # Store the page horizontal centering
532
+ store_hcenter
533
+
534
+ # Store the page vertical centering
535
+ store_vcenter
536
+
537
+ # Store the left margin
538
+ store_margin_left
539
+
540
+ # Store the right margin
541
+ store_margin_right
542
+
543
+ # Store the top margin
544
+ store_margin_top
545
+
546
+ # Store the bottom margin
547
+ store_margin_bottom
548
+
549
+ # Store the page setup
550
+ store_setup
551
+
552
+ # Store the sheet password
553
+ store_password
554
+
555
+ # Start of Chart specific records.
556
+
557
+ # Store the FBI font records.
558
+ store_fbi(*@config[:font_numbers])
559
+ store_fbi(*@config[:font_series])
560
+ store_fbi(*@config[:font_title])
561
+ store_fbi(*@config[:font_axes])
562
+
563
+ # Ignore UNITS record.
564
+
565
+ # Store the Chart sub-stream.
566
+ store_chart_stream
567
+
568
+ # Append the sheet dimensions
569
+ store_dimensions
570
+
571
+ # TODO add SINDEX and NUMBER records.
572
+
573
+ store_window2 unless @embedded
574
+
575
+ store_eof
576
+ end
577
+
578
+ ###############################################################################
579
+ #
580
+ # _store_window2(), overridden.
581
+ #
582
+ # Write BIFF record Window2. Note, this overrides the parent Worksheet
583
+ # record because the Chart version of the record is smaller and is used
584
+ # mainly to indicate if the chart tab is selected or not.
585
+ #
586
+ def store_window2 # :nodoc:
587
+ record = 0x023E # Record identifier
588
+ length = 0x000A # Number of bytes to follow
589
+ grbit = 0x0000 # Option flags
590
+ rwTop = 0x0000 # Top visible row
591
+ colLeft = 0x0000 # Leftmost visible column
592
+ rgbHdr = 0x0000 # Row/col heading, grid color
593
+
594
+ # The options flags that comprise grbit
595
+ fDspFmla = 0 # 0 - bit
596
+ fDspGrid = 0 # 1
597
+ fDspRwCol = 0 # 2
598
+ fFrozen = 0 # 3
599
+ fDspZeros = 0 # 4
600
+ fDefaultHdr = 0 # 5
601
+ fArabic = 0 # 6
602
+ fDspGuts = 0 # 7
603
+ fFrozenNoSplit = 0 # 0 - bit
604
+ fSelected = @selected # 1
605
+ fPaged = 0 # 2
606
+ fBreakPreview = 0 # 3
607
+
608
+ #<<< Perltidy ignore this.
609
+ grbit = fDspFmla
610
+ grbit |= fDspGrid << 1
611
+ grbit |= fDspRwCol << 2
612
+ grbit |= fFrozen << 3
613
+ grbit |= fDspZeros << 4
614
+ grbit |= fDefaultHdr << 5
615
+ grbit |= fArabic << 6
616
+ grbit |= fDspGuts << 7
617
+ grbit |= fFrozenNoSplit << 8
618
+ grbit |= fSelected << 9
619
+ grbit |= fPaged << 10
620
+ grbit |= fBreakPreview << 11
621
+ #>>>
622
+
623
+ header = [record, length].pack("vv")
624
+ data = [grbit, rwTop, colLeft, rgbHdr].pack("vvvV")
625
+
626
+ append(header, data)
627
+ end
628
+
629
+ ###############################################################################
630
+ #
631
+ # _parse_series_formula()
632
+ #
633
+ # Parse the formula used to define a series. We also extract some range
634
+ # information required for _store_series() and the SERIES record.
635
+ #
636
+ def parse_series_formula(formula) # :nodoc:
637
+ encoding = 0
638
+ length = 0
639
+ count = 0
640
+ tokens = []
641
+
642
+ return [''] if formula.nil?
643
+
644
+ # Strip the = sign at the beginning of the formula string
645
+ formula = formula.sub(/^=/, '')
646
+
647
+ # Parse the formula using the parser in Formula.pm
648
+ parser = @parser
649
+
650
+ # In order to raise formula errors from the point of view of the calling
651
+ # program we use an eval block and re-raise the error from here.
652
+ #
653
+ tokens = parser.parse_formula(formula)
654
+
655
+ # Force ranges to be a reference class.
656
+ tokens.collect! { |t| t.gsub(/_ref3d/, '_ref3dR') }
657
+ tokens.collect! { |t| t.gsub(/_range3d/, '_range3dR') }
658
+ tokens.collect! { |t| t.gsub(/_name/, '_nameR') }
659
+
660
+ # Parse the tokens into a formula string.
661
+ formula = parser.parse_tokens(tokens)
662
+
663
+ # Return formula for a single cell as used by title and series name.
664
+ return formula if formula.ord == 0x3A
665
+
666
+ # Extract the range from the parse formula.
667
+ if formula.ord == 0x3B
668
+ ptg, ext_ref, row_1, row_2, col_1, col_2 = formula.unpack('Cv5')
669
+
670
+ # TODO. Remove high bit on relative references.
671
+ count = row_2 - row_1 + 1
672
+ end
673
+
674
+ [formula, count]
675
+ end
676
+
677
+ ###############################################################################
678
+ #
679
+ # _encode_utf16()
680
+ #
681
+ # Convert UTF8 strings used in the chart to UTF16.
682
+ #
683
+ def encode_utf16(str, encoding = 0) # :nodoc:
684
+ # Exit if the $string isn't defined, i.e., hasn't been set by user.
685
+ return [nil, nil] if str.nil?
686
+
687
+ string = str.dup
688
+ # Return if encoding is set, i.e., string has been manually encoded.
689
+ #return ( undef, undef ) if $string == 1;
690
+
691
+ ruby_19 { string = convert_to_ascii_if_ascii(string) }
692
+
693
+ # Handle utf8 strings.
694
+ ruby_18 do
695
+ if string =~ NonAscii
696
+ string = utf8_to_16be(string)
697
+ encoding = 1
698
+ end
699
+ end
700
+ ruby_19 do
701
+ if string.encoding == Encoding::UTF_8
702
+ string = utf8_to_16be(string)
703
+ encoding = 1
704
+ end
705
+ end
706
+
707
+ # Chart strings are limited to 255 characters.
708
+ limit = encoding != 0 ? 255 * 2 : 255
709
+
710
+ if string.bytesize >= limit
711
+ # truncate the string and raise a warning.
712
+ string = string[0, limit]
713
+ end
714
+
715
+ [string, encoding]
716
+ end
717
+
718
+ ###############################################################################
719
+ #
720
+ # _get_color_indices()
721
+ #
722
+ # Convert the user specified colour index or string to an colour index and
723
+ # RGB colour number.
724
+ #
725
+ def get_color_indices(color) # :nodoc:
726
+ invalid = 0x7FFF # return from Colors#get_color when color is invalid
727
+
728
+ index = Colors.new.get_color(color)
729
+ index = invalid if color.respond_to?(:coerce) && (color < 8 || color > 63)
730
+ if index == invalid
731
+ [nil, nil]
732
+ else
733
+ [index, get_color_rbg(index)]
734
+ end
735
+ end
736
+
737
+ ###############################################################################
738
+ #
739
+ # _get_color_rbg()
740
+ #
741
+ # Get the RedGreenBlue number for the colour index from the Workbook palette.
742
+ #
743
+ def get_color_rbg(index) # :nodoc:
744
+ # Adjust colour index from 8-63 (user range) to 0-55 (Excel range).
745
+ index -= 8
746
+
747
+ red_green_blue = @palette[index]
748
+ red_green_blue.pack('C*').unpack('V')[0]
749
+ end
750
+
751
+ ###############################################################################
752
+ #
753
+ # _get_line_pattern()
754
+ #
755
+ # Get the Excel chart index for line pattern that corresponds to the user
756
+ # defined value.
757
+ #
758
+ def get_line_pattern(value) # :nodoc:
759
+ value = value.downcase if value.respond_to?(:to_str)
760
+ default = 0
761
+
762
+ patterns = {
763
+ 0 => 5,
764
+ 1 => 0,
765
+ 2 => 1,
766
+ 3 => 2,
767
+ 4 => 3,
768
+ 5 => 4,
769
+ 6 => 7,
770
+ 7 => 6,
771
+ 8 => 8,
772
+ 'solid' => 0,
773
+ 'dash' => 1,
774
+ 'dot' => 2,
775
+ 'dash-dot' => 3,
776
+ 'dash-dot-dot' => 4,
777
+ 'none' => 5,
778
+ 'dark-gray' => 6,
779
+ 'medium-gray' => 7,
780
+ 'light-gray' => 8,
781
+ }
782
+
783
+ if patterns.has_key?(value)
784
+ patterns[value]
785
+ else
786
+ default
787
+ end
788
+ end
789
+
790
+ ###############################################################################
791
+ #
792
+ # _get_line_weight()
793
+ #
794
+ # Get the Excel chart index for line weight that corresponds to the user
795
+ # defined value.
796
+ #
797
+ def get_line_weight(value) # :nodoc:
798
+ value = value.downcase if value.respond_to?(:to_str)
799
+ default = 0
800
+
801
+ weights = {
802
+ 1 => -1,
803
+ 2 => 0,
804
+ 3 => 1,
805
+ 4 => 2,
806
+ 'hairline' => -1,
807
+ 'narrow' => 0,
808
+ 'medium' => 1,
809
+ 'wide' => 2,
810
+ }
811
+
812
+ if weights.has_key?(value)
813
+ weights[value]
814
+ else
815
+ default
816
+ end
817
+ end
818
+
819
+ ###############################################################################
820
+ #
821
+ # _store_chart_stream()
822
+ #
823
+ # Store the CHART record and it's substreams.
824
+ #
825
+ def store_chart_stream # :nodoc:
826
+ store_chart(*@config[:chart])
827
+ store_begin
828
+
829
+ # Store the chart SCL record.
830
+ store_plotgrowth
831
+
832
+ if @chartarea[:visible] != 0
833
+ store_chartarea_frame_stream
834
+ end
835
+
836
+ # Store SERIES stream for each series.
837
+ index = 0
838
+ @series.each do |series|
839
+ store_series_stream(
840
+ :index => index,
841
+ :value_formula => series[:values][0],
842
+ :value_count => series[:values][1],
843
+ :category_count => series[:categories][1],
844
+ :category_formula => series[:categories][0],
845
+ :name => series[:name],
846
+ :name_encoding => series[:name_encoding],
847
+ :name_formula => series[:name_formula]
848
+ )
849
+ index += 1
850
+ end
851
+
852
+ store_shtprops
853
+
854
+ # Write the TEXT streams.
855
+ (5..6).each do |font_index|
856
+ store_defaulttext
857
+ store_series_text_stream(font_index)
858
+ end
859
+
860
+ store_axesused(1)
861
+ store_axisparent_stream
862
+
863
+ if !@title_name.nil? || !@title_formula.nil?
864
+ store_title_text_stream
865
+ end
866
+
867
+ store_end
868
+ end
869
+
870
+ def _formula_type_from_param(t, f, params, key) # :nodoc:
871
+ if params.has_key?(key)
872
+ v = params[key]
873
+ (v.nil? || v == [""] || v == '' || v == 0) ? f : t
874
+ end
875
+ end
876
+ private :_formula_type_from_param
877
+
878
+ ###############################################################################
879
+ #
880
+ # _store_series_stream()
881
+ #
882
+ # Write the SERIES chart substream.
883
+ #
884
+ def store_series_stream(params) # :nodoc:
885
+ name_type = _formula_type_from_param(2, 1, params, :name_formula)
886
+ value_type = _formula_type_from_param(2, 0, params, :value_formula)
887
+ category_type = _formula_type_from_param(2, 0, params, :category_formula)
888
+
889
+ store_series(params[:value_count], params[:category_count])
890
+
891
+ store_begin
892
+
893
+ # Store the Series name AI record.
894
+ store_ai(0, name_type, params[:name_formula])
895
+ unless params[:name].nil?
896
+ store_seriestext(params[:name], params[:name_encoding])
897
+ end
898
+
899
+ store_ai(1, value_type, params[:value_formula])
900
+ store_ai(2, category_type, params[:category_formula])
901
+ store_ai(3, 1, '' )
902
+
903
+ store_dataformat_stream(params[:index])
904
+ store_sertocrt
905
+ store_end
906
+ end
907
+
908
+ ###############################################################################
909
+ #
910
+ # _store_dataformat_stream()
911
+ #
912
+ # Write the DATAFORMAT chart substream.
913
+ #
914
+ def store_dataformat_stream(series_index) # :nodoc:
915
+ store_dataformat(series_index, series_index, 0xFFFF)
916
+
917
+ store_begin
918
+ store_3dbarshape
919
+ store_end
920
+ end
921
+
922
+ ###############################################################################
923
+ #
924
+ # _store_series_text_stream()
925
+ #
926
+ # Write the series TEXT substream.
927
+ #
928
+ def store_series_text_stream(font_index) # :nodoc:
929
+ store_text(*@config[:series_text])
930
+
931
+ store_begin
932
+ store_pos(*@config[:series_text_pos])
933
+ store_fontx( font_index )
934
+ store_ai( 0, 1, '' )
935
+ store_end
936
+ end
937
+
938
+ def _formula_type(t, f, formula) # :nodoc:
939
+ (formula.nil? || formula == [""] || formula == '' || formula == 0) ? f : t
940
+ end
941
+ private :_formula_type
942
+
943
+ ###############################################################################
944
+ #
945
+ # _store_x_axis_text_stream()
946
+ #
947
+ # Write the X-axis TEXT substream.
948
+ #
949
+ def store_x_axis_text_stream # :nodoc:
950
+ formula = @x_axis_formula.nil? ? '' : @x_axis_formula
951
+ ai_type = _formula_type(2, 1, formula)
952
+
953
+ store_text(*@config[:x_axis_text])
954
+
955
+ store_begin
956
+ store_pos(*@config[:x_axis_text_pos])
957
+ store_fontx(8)
958
+ store_ai(0, ai_type, formula)
959
+
960
+ unless @x_axis_name.nil?
961
+ store_seriestext(@x_axis_name, @x_axis_encoding)
962
+ end
963
+
964
+ store_objectlink(3)
965
+ store_end
966
+ end
967
+
968
+ ###############################################################################
969
+ #
970
+ # _store_y_axis_text_stream()
971
+ #
972
+ # Write the Y-axis TEXT substream.
973
+ #
974
+ def store_y_axis_text_stream # :nodoc:
975
+ formula = @y_axis_formula
976
+ ai_type = _formula_type(2, 1, formula)
977
+
978
+ store_text(*@config[:y_axis_text])
979
+
980
+ store_begin
981
+ store_pos(*@config[:y_axis_text_pos])
982
+ store_fontx(8)
983
+ store_ai(0, ai_type, formula)
984
+
985
+ unless @y_axis_name.nil?
986
+ store_seriestext(@y_axis_name, @y_axis_encoding)
987
+ end
988
+
989
+ store_objectlink(2)
990
+ store_end
991
+ end
992
+
993
+ ###############################################################################
994
+ #
995
+ # _store_legend_text_stream()
996
+ #
997
+ # Write the legend TEXT substream.
998
+ #
999
+ def store_legend_text_stream # :nodoc:
1000
+ store_text(*@config[:legend_text])
1001
+
1002
+ store_begin
1003
+ store_pos(*@config[:legend_text_pos])
1004
+ store_ai(0, 1, '')
1005
+
1006
+ store_end
1007
+ end
1008
+
1009
+ ###############################################################################
1010
+ #
1011
+ # _store_title_text_stream()
1012
+ #
1013
+ # Write the title TEXT substream.
1014
+ #
1015
+ def store_title_text_stream # :nodoc:
1016
+ formula = @title_formula
1017
+ ai_type = _formula_type(2, 1, formula)
1018
+
1019
+ store_text(*@config[:title_text])
1020
+
1021
+ store_begin
1022
+ store_pos(*@config[:title_text_pos])
1023
+ store_fontx(7)
1024
+ store_ai(0, ai_type, formula)
1025
+
1026
+ unless @title_name.nil?
1027
+ store_seriestext(@title_name, @title_encoding)
1028
+ end
1029
+
1030
+ store_objectlink(1)
1031
+ store_end
1032
+ end
1033
+
1034
+ ###############################################################################
1035
+ #
1036
+ # _store_axisparent_stream()
1037
+ #
1038
+ # Write the AXISPARENT chart substream.
1039
+ #
1040
+ def store_axisparent_stream # :nodoc:
1041
+ store_axisparent(*@config[:axisparent])
1042
+
1043
+ store_begin
1044
+ store_pos(*@config[:axisparent_pos])
1045
+ store_axis_category_stream
1046
+ store_axis_values_stream
1047
+
1048
+ if !@x_axis_name.nil? || !@x_axis_formula.nil?
1049
+ store_x_axis_text_stream
1050
+ end
1051
+
1052
+ if !@y_axis_name.nil? || !@y_axis_formula.nil?
1053
+ store_y_axis_text_stream();
1054
+ end
1055
+
1056
+ if @plotarea[:visible] != 0
1057
+ store_plotarea
1058
+ store_plotarea_frame_stream
1059
+ end
1060
+ store_chartformat_stream
1061
+ store_end
1062
+ end
1063
+
1064
+ ###############################################################################
1065
+ #
1066
+ # _store_axis_category_stream()
1067
+ #
1068
+ # Write the AXIS chart substream for the chart category.
1069
+ #
1070
+ def store_axis_category_stream # :nodoc:
1071
+ store_axis(0)
1072
+
1073
+ store_begin
1074
+ store_catserrange
1075
+ store_axcext
1076
+ store_tick
1077
+ store_end
1078
+ end
1079
+
1080
+ ###############################################################################
1081
+ #
1082
+ # _store_axis_values_stream()
1083
+ #
1084
+ # Write the AXIS chart substream for the chart values.
1085
+ #
1086
+ def store_axis_values_stream # :nodoc:
1087
+ store_axis(1)
1088
+
1089
+ store_begin
1090
+ store_valuerange
1091
+ store_tick
1092
+ store_axislineformat
1093
+ store_lineformat(0x00000000, 0x0000, 0xFFFF, 0x0009, 0x004D)
1094
+ store_end
1095
+ end
1096
+
1097
+ ###############################################################################
1098
+ #
1099
+ # _store_plotarea_frame_stream()
1100
+ #
1101
+ # Write the FRAME chart substream.
1102
+ #
1103
+ def store_plotarea_frame_stream # :nodoc:
1104
+ store_area_frame_stream_common(:plot)
1105
+ end
1106
+
1107
+ ###############################################################################
1108
+ #
1109
+ # _store_chartarea_frame_stream()
1110
+ #
1111
+ # Write the FRAME chart substream for and embedded chart.
1112
+ #
1113
+ def store_chartarea_frame_stream # :nodoc:
1114
+ store_area_frame_stream_common(:chart)
1115
+ end
1116
+
1117
+ def store_area_frame_stream_common(type)
1118
+ if type == :plot
1119
+ area = @plotarea
1120
+ grbit = 0x03
1121
+ else
1122
+ area = @chartarea
1123
+ grbit = 0x02
1124
+ end
1125
+
1126
+ store_frame(0x00, grbit)
1127
+ store_begin
1128
+
1129
+ store_lineformat(
1130
+ area[:line_color_rgb], area[:line_pattern],
1131
+ area[:line_weight], area[:line_options],
1132
+ area[:line_color_index]
1133
+ )
1134
+
1135
+ store_areaformat(
1136
+ area[:fg_color_rgb], area[:bg_color_rgb],
1137
+ area[:area_pattern], area[:area_options],
1138
+ area[:fg_color_index], area[:bg_color_index]
1139
+ )
1140
+
1141
+ store_end
1142
+ end
1143
+ private :store_area_frame_stream_common
1144
+
1145
+ ###############################################################################
1146
+ #
1147
+ # _store_chartformat_stream()
1148
+ #
1149
+ # Write the CHARTFORMAT chart substream.
1150
+ #
1151
+ def store_chartformat_stream # :nodoc:
1152
+ # The _vary_data_color is set by classes that need it, like Pie.
1153
+ store_chartformat(@vary_data_color)
1154
+
1155
+ store_begin
1156
+
1157
+ # Store the BIFF record that will define the chart type.
1158
+ store_chart_type
1159
+
1160
+ # Note, the CHARTFORMATLINK record is only written by Excel.
1161
+
1162
+ if @legend[:visible]
1163
+ store_legend_stream
1164
+ end
1165
+
1166
+ store_marker_dataformat_stream
1167
+ store_end
1168
+ end
1169
+
1170
+ ###############################################################################
1171
+ #
1172
+ # _store_chart_type()
1173
+ #
1174
+ # This is an abstract method that is overridden by the sub-classes to define
1175
+ # the chart types such as Column, Line, Pie, etc.
1176
+ #
1177
+ def store_chart_type # :nodoc:
1178
+
1179
+ end
1180
+
1181
+ ###############################################################################
1182
+ #
1183
+ # _store_marker_dataformat_stream()
1184
+ #
1185
+ # This is an abstract method that is overridden by the sub-classes to define
1186
+ # properties of markers, linetypes, pie formats and other.
1187
+ #
1188
+ def store_marker_dataformat_stream # :nodoc:
1189
+
1190
+ end
1191
+
1192
+ ###############################################################################
1193
+ #
1194
+ # _store_legend_stream()
1195
+ #
1196
+ # Write the LEGEND chart substream.
1197
+ #
1198
+ def store_legend_stream # :nodoc:
1199
+ store_legend(*@config[:legend])
1200
+
1201
+ store_begin
1202
+ store_pos(*@config[:legend_pos])
1203
+ store_legend_text_stream
1204
+ store_end
1205
+ end
1206
+
1207
+ ###############################################################################
1208
+ #
1209
+ # BIFF Records.
1210
+ #
1211
+ ###############################################################################
1212
+
1213
+ ###############################################################################
1214
+ #
1215
+ # _store_3dbarshape()
1216
+ #
1217
+ # Write the 3DBARSHAPE chart BIFF record.
1218
+ #
1219
+ def store_3dbarshape # :nodoc:
1220
+ record = 0x105F # Record identifier.
1221
+ length = 0x0002 # Number of bytes to follow.
1222
+ riser = 0x00 # Shape of base.
1223
+ taper = 0x00 # Column taper type.
1224
+
1225
+ header = [record, length].pack('vv')
1226
+ data = [riser].pack('C')
1227
+ data += [taper].pack('C')
1228
+
1229
+ append(header, data)
1230
+ end
1231
+
1232
+ ###############################################################################
1233
+ #
1234
+ # _store_ai()
1235
+ #
1236
+ # Write the AI chart BIFF record.
1237
+ #
1238
+ def store_ai(id, type, formula, format_index = 0) # :nodoc:
1239
+ formula = '' if formula == [""]
1240
+
1241
+ record = 0x1051 # Record identifier.
1242
+ length = 0x0008 # Number of bytes to follow.
1243
+ # id # Link index.
1244
+ # type # Reference type.
1245
+ # formula # Pre-parsed formula.
1246
+ # format_index # Num format index.
1247
+ grbit = 0x0000 # Option flags.
1248
+
1249
+ ruby_19 { formula = convert_to_ascii_if_ascii(formula) }
1250
+
1251
+ formula_length = formula.bytesize
1252
+ length += formula_length
1253
+
1254
+ header = [record, length].pack('vv')
1255
+ data = [id].pack('C')
1256
+ data += [type].pack('C')
1257
+ data += [grbit].pack('v')
1258
+ data += [format_index].pack('v')
1259
+ data += [formula_length].pack('v')
1260
+ if formula.respond_to?(:to_array)
1261
+ data +=
1262
+ ruby_18 { formula[0] } ||
1263
+ ruby_19 { formula[0].encode('BINARY') }
1264
+ else
1265
+ data +=
1266
+ ruby_18 { formula unless formula.nil? } ||
1267
+ ruby_19 { formula.encode('BINARY') unless formula.nil? }
1268
+ end
1269
+
1270
+ append(header, data)
1271
+ end
1272
+
1273
+ ###############################################################################
1274
+ #
1275
+ # _store_areaformat()
1276
+ #
1277
+ # Write the AREAFORMAT chart BIFF record. Contains the patterns and colours
1278
+ # of a chart area.
1279
+ #
1280
+ def store_areaformat(rgbFore, rgbBack, pattern, grbit, indexFore, indexBack) # :nodoc:
1281
+ record = 0x100A # Record identifier.
1282
+ length = 0x0010 # Number of bytes to follow.
1283
+ # rgbFore # Foreground RGB colour.
1284
+ # rgbBack # Background RGB colour.
1285
+ # pattern # Pattern.
1286
+ # grbit # Option flags.
1287
+ # indexFore # Index to Foreground colour.
1288
+ # indexBack # Index to Background colour.
1289
+
1290
+ header = [record, length].pack('vv')
1291
+ data = [rgbFore].pack('V')
1292
+ data += [rgbBack].pack('V')
1293
+ data += [pattern].pack('v')
1294
+ data += [grbit].pack('v')
1295
+ data += [indexFore].pack('v')
1296
+ data += [indexBack].pack('v')
1297
+
1298
+ append(header, data)
1299
+ end
1300
+
1301
+ ###############################################################################
1302
+ #
1303
+ # _store_axcext()
1304
+ #
1305
+ # Write the AXCEXT chart BIFF record.
1306
+ #
1307
+ def store_axcext # :nodoc:
1308
+ record = 0x1062 # Record identifier.
1309
+ length = 0x0012 # Number of bytes to follow.
1310
+ catMin = 0x0000 # Minimum category on axis.
1311
+ catMax = 0x0000 # Maximum category on axis.
1312
+ catMajor = 0x0001 # Value of major unit.
1313
+ unitMajor = 0x0000 # Units of major unit.
1314
+ catMinor = 0x0001 # Value of minor unit.
1315
+ unitMinor = 0x0000 # Units of minor unit.
1316
+ unitBase = 0x0000 # Base unit of axis.
1317
+ catCrossDate = 0x0000 # Crossing point.
1318
+ grbit = 0x00EF # Option flags.
1319
+
1320
+ store_simple(record, length, catMin, catMax, catMajor, unitMajor,
1321
+ catMinor, unitMinor, unitBase, catCrossDate, grbit)
1322
+ end
1323
+
1324
+ ###############################################################################
1325
+ #
1326
+ # _store_axesused()
1327
+ #
1328
+ # Write the AXESUSED chart BIFF record.
1329
+ #
1330
+ def store_axesused(num_axes) # :nodoc:
1331
+ record = 0x1046 # Record identifier.
1332
+ length = 0x0002 # Number of bytes to follow.
1333
+ # num_axes # Number of axes used.
1334
+
1335
+ store_simple(record, length, num_axes)
1336
+ end
1337
+
1338
+ ###############################################################################
1339
+ #
1340
+ # _store_axis()
1341
+ #
1342
+ # Write the AXIS chart BIFF record to define the axis type.
1343
+ #
1344
+ def store_axis(type) # :nodoc:
1345
+ record = 0x101D # Record identifier.
1346
+ length = 0x0012 # Number of bytes to follow.
1347
+ # type # Axis type.
1348
+ reserved1 = 0x00000000 # Reserved.
1349
+ reserved2 = 0x00000000 # Reserved.
1350
+ reserved3 = 0x00000000 # Reserved.
1351
+ reserved4 = 0x00000000 # Reserved.
1352
+
1353
+ header = [record, length].pack('vv')
1354
+ data = [type].pack('v')
1355
+ data += [reserved1].pack('V')
1356
+ data += [reserved2].pack('V')
1357
+ data += [reserved3].pack('V')
1358
+ data += [reserved4].pack('V')
1359
+
1360
+ append(header, data)
1361
+ end
1362
+
1363
+ ###############################################################################
1364
+ #
1365
+ # _store_axislineformat()
1366
+ #
1367
+ # Write the AXISLINEFORMAT chart BIFF record.
1368
+ #
1369
+ def store_axislineformat # :nodoc:
1370
+ record = 0x1021 # Record identifier.
1371
+ length = 0x0002 # Number of bytes to follow.
1372
+ line_format = 0x0001 # Axis line format.
1373
+
1374
+ store_simple(record, length, line_format)
1375
+ end
1376
+
1377
+ ###############################################################################
1378
+ #
1379
+ # _store_axisparent()
1380
+ #
1381
+ # Write the AXISPARENT chart BIFF record.
1382
+ #
1383
+ def store_axisparent(iax, x, y, dx, dy) # :nodoc:
1384
+ record = 0x1041 # Record identifier.
1385
+ length = 0x0012 # Number of bytes to follow.
1386
+ # iax # Axis index.
1387
+ # x # X-coord.
1388
+ # y # Y-coord.
1389
+ # dx # Length of x axis.
1390
+ # dy # Length of y axis.
1391
+
1392
+ header = [record, length].pack('vv')
1393
+ data = [iax].pack('v')
1394
+ data += [x].pack('V')
1395
+ data += [y].pack('V')
1396
+ data += [dx].pack('V')
1397
+ data += [dy].pack('V')
1398
+
1399
+ append(header, data)
1400
+ end
1401
+
1402
+ ###############################################################################
1403
+ #
1404
+ # _store_begin()
1405
+ #
1406
+ # Write the BEGIN chart BIFF record to indicate the start of a sub stream.
1407
+ #
1408
+ def store_begin # :nodoc:
1409
+ record = 0x1033 # Record identifier.
1410
+ length = 0x0000 # Number of bytes to follow.
1411
+
1412
+ store_simple(record, length)
1413
+ end
1414
+
1415
+ ###############################################################################
1416
+ #
1417
+ # _store_catserrange()
1418
+ #
1419
+ # Write the CATSERRANGE chart BIFF record.
1420
+ #
1421
+ def store_catserrange # :nodoc:
1422
+ record = 0x1020 # Record identifier.
1423
+ length = 0x0008 # Number of bytes to follow.
1424
+ catCross = 0x0001 # Value/category crossing.
1425
+ catLabel = 0x0001 # Frequency of labels.
1426
+ catMark = 0x0001 # Frequency of ticks.
1427
+ grbit = 0x0001 # Option flags.
1428
+
1429
+ store_simple(record, length, catCross, catLabel, catMark, grbit)
1430
+ end
1431
+
1432
+ ###############################################################################
1433
+ #
1434
+ # _store_chart()
1435
+ #
1436
+ # Write the CHART BIFF record. This indicates the start of the chart sub-stream
1437
+ # and contains dimensions of the chart on the display. Units are in 1/72 inch
1438
+ # and are 2 byte integer with 2 byte fraction.
1439
+ #
1440
+ def store_chart(x_pos, y_pos, dx, dy) # :nodoc:
1441
+ record = 0x1002 # Record identifier.
1442
+ length = 0x0010 # Number of bytes to follow.
1443
+ # x_pos # X pos of top left corner.
1444
+ # y_pos # Y pos of top left corner.
1445
+ # dx # X size.
1446
+ # dy # Y size.
1447
+
1448
+ header = [record, length].pack('vv')
1449
+ data = [x_pos].pack('V')
1450
+ data += [y_pos].pack('V')
1451
+ data += [dx].pack('V')
1452
+ data += [dy].pack('V')
1453
+
1454
+ append(header, data)
1455
+ end
1456
+
1457
+ ###############################################################################
1458
+ #
1459
+ # _store_chartformat()
1460
+ #
1461
+ # Write the CHARTFORMAT chart BIFF record. The parent record for formatting
1462
+ # of a chart group.
1463
+ #
1464
+ def store_chartformat(grbit = 0) # :nodoc:
1465
+ record = 0x1014 # Record identifier.
1466
+ length = 0x0014 # Number of bytes to follow.
1467
+ reserved1 = 0x00000000 # Reserved.
1468
+ reserved2 = 0x00000000 # Reserved.
1469
+ reserved3 = 0x00000000 # Reserved.
1470
+ reserved4 = 0x00000000 # Reserved.
1471
+ # grbit # Option flags.
1472
+ icrt = 0x0000 # Drawing order.
1473
+
1474
+ header = [record, length].pack('vv')
1475
+ data = [reserved1].pack('V')
1476
+ data += [reserved2].pack('V')
1477
+ data += [reserved3].pack('V')
1478
+ data += [reserved4].pack('V')
1479
+ data += [grbit].pack('v')
1480
+ data += [icrt].pack('v')
1481
+
1482
+ append(header, data)
1483
+ end
1484
+
1485
+ ###############################################################################
1486
+ #
1487
+ # _store_chartline()
1488
+ #
1489
+ # Write the CHARTLINE chart BIFF record.
1490
+ #
1491
+ def store_chartline # :nodoc:
1492
+ record = 0x101C # Record identifier.
1493
+ length = 0x0002 # Number of bytes to follow.
1494
+ type = 0x0001 # Drop/hi-lo line type.
1495
+
1496
+ store_simple(record, length, type)
1497
+ end
1498
+
1499
+ ###############################################################################
1500
+ #
1501
+ # _store_charttext()
1502
+ #
1503
+ # Write the TEXT chart BIFF record.
1504
+ #
1505
+ def store_charttext # :nodoc:
1506
+ record = 0x1025 # Record identifier.
1507
+ length = 0x0020 # Number of bytes to follow.
1508
+ horz_align = 0x02 # Horizontal alignment.
1509
+ vert_align = 0x02 # Vertical alignment.
1510
+ bg_mode = 0x0001 # Background display.
1511
+ text_color_rgb = 0x00000000 # Text RGB colour.
1512
+ text_x = 0xFFFFFF46 # Text x-pos.
1513
+ text_y = 0xFFFFFF06 # Text y-pos.
1514
+ text_dx = 0x00000000 # Width.
1515
+ text_dy = 0x00000000 # Height.
1516
+ grbit1 = 0x00B1 # Options
1517
+ text_color_index = 0x004D # Auto Colour.
1518
+ grbit2 = 0x0000 # Data label placement.
1519
+ rotation = 0x0000 # Text rotation.
1520
+
1521
+ header = [record, length].pack('vv')
1522
+ data = [horz_align].pack('C')
1523
+ data += [vert_align].pack('C')
1524
+ data += [bg_mode].pack('v')
1525
+ data += [text_color_rgb].pack('V')
1526
+ data += [text_x].pack('V')
1527
+ data += [text_y].pack('V')
1528
+ data += [text_dx].pack('V')
1529
+ data += [text_dy].pack('V')
1530
+ data += [grbit1].pack('v')
1531
+ data += [text_color_index].pack('v')
1532
+ data += [grbit2].pack('v')
1533
+ data += [rotation].pack('v')
1534
+
1535
+ append(header, data)
1536
+ end
1537
+
1538
+ ###############################################################################
1539
+ #
1540
+ # _store_dataformat()
1541
+ #
1542
+ # Write the DATAFORMAT chart BIFF record. This record specifies the series
1543
+ # that the subsequent sub stream refers to.
1544
+ #
1545
+ def store_dataformat(series_index, series_number, point_number) # :nodoc:
1546
+ record = 0x1006 # Record identifier.
1547
+ length = 0x0008 # Number of bytes to follow.
1548
+ # series_index # Series index.
1549
+ # series_number # Series number. (Same as index).
1550
+ # point_number # Point number.
1551
+ grbit = 0x0000 # Format flags.
1552
+
1553
+ store_simple(record, length, point_number, series_index, series_number, grbit)
1554
+ end
1555
+
1556
+ ###############################################################################
1557
+ #
1558
+ # _store_defaulttext()
1559
+ #
1560
+ # Write the DEFAULTTEXT chart BIFF record. Identifier for subsequent TEXT
1561
+ # record.
1562
+ #
1563
+ def store_defaulttext # :nodoc:
1564
+ record = 0x1024 # Record identifier.
1565
+ length = 0x0002 # Number of bytes to follow.
1566
+ type = 0x0002 # Type.
1567
+
1568
+ store_simple(record, length, type)
1569
+ end
1570
+
1571
+ ###############################################################################
1572
+ #
1573
+ # _store_dropbar()
1574
+ #
1575
+ # Write the DROPBAR chart BIFF record.
1576
+ #
1577
+ def store_dropbar # :nodoc:
1578
+ record = 0x103D # Record identifier.
1579
+ length = 0x0002 # Number of bytes to follow.
1580
+ percent_gap = 0x0096 # Drop bar width gap (%).
1581
+
1582
+ store_simple(record, length, percent_gap)
1583
+ end
1584
+
1585
+ ###############################################################################
1586
+ #
1587
+ # _store_end()
1588
+ #
1589
+ # Write the END chart BIFF record to indicate the end of a sub stream.
1590
+ #
1591
+ def store_end # :nodoc:
1592
+ record = 0x1034 # Record identifier.
1593
+ length = 0x0000 # Number of bytes to follow.
1594
+
1595
+ store_simple(record, length)
1596
+ end
1597
+
1598
+ ###############################################################################
1599
+ # _store_fbi()
1600
+ #
1601
+ # Write the FBI chart BIFF record. Specifies the font information at the time
1602
+ # it was applied to the chart.
1603
+ #
1604
+ def store_fbi(index, height, width_basis, height_basis, scale_basis) # :nodoc:
1605
+ record = 0x1060 # Record identifier.
1606
+ length = 0x000A # Number of bytes to follow.
1607
+ # index # Font index.
1608
+ height = height * 20 # Default font height in twips.
1609
+ # width_basis # Width basis, in twips.
1610
+ # height_basis # Height basis, in twips.
1611
+ # scale_basis # Scale by chart area or plot area.
1612
+
1613
+ store_simple(record, length, width_basis, height_basis, height, scale_basis, index)
1614
+ end
1615
+
1616
+ ###############################################################################
1617
+ #
1618
+ # _store_fontx()
1619
+ #
1620
+ # Write the FONTX chart BIFF record which contains the index of the FONT
1621
+ # record in the Workbook.
1622
+ #
1623
+ def store_fontx(index) # :nodoc:
1624
+ record = 0x1026 # Record identifier.
1625
+ length = 0x0002 # Number of bytes to follow.
1626
+ # index # Font index.
1627
+
1628
+ store_simple(record, length, index)
1629
+ end
1630
+
1631
+ ###############################################################################
1632
+ #
1633
+ # _store_frame()
1634
+ #
1635
+ # Write the FRAME chart BIFF record.
1636
+ #
1637
+ def store_frame(frame_type, grbit) # :nodoc:
1638
+ record = 0x1032 # Record identifier.
1639
+ length = 0x0004 # Number of bytes to follow.
1640
+ # frame_type # Frame type.
1641
+ # grbit # Option flags.
1642
+
1643
+ store_simple(record, length, frame_type, grbit)
1644
+ end
1645
+
1646
+ ###############################################################################
1647
+ #
1648
+ # _store_legend()
1649
+ #
1650
+ # Write the LEGEND chart BIFF record. The Marcus Horan method.
1651
+ #
1652
+ def store_legend(x, y, width, height, wType, wSpacing, grbit) # :nodoc:
1653
+ record = 0x1015 # Record identifier.
1654
+ length = 0x0014 # Number of bytes to follow.
1655
+ # x # X-position.
1656
+ # y # Y-position.
1657
+ # width # Width.
1658
+ # height # Height.
1659
+ # wType # Type.
1660
+ # wSpacing # Spacing.
1661
+ # grbit # Option flags.
1662
+
1663
+ header = [record, length].pack('vv')
1664
+ data = [x].pack('V')
1665
+ data += [y].pack('V')
1666
+ data += [width].pack('V')
1667
+ data += [height].pack('V')
1668
+ data += [wType].pack('C')
1669
+ data += [wSpacing].pack('C')
1670
+ data += [grbit].pack('v')
1671
+
1672
+ append(header, data)
1673
+ end
1674
+
1675
+ ###############################################################################
1676
+ #
1677
+ # _store_lineformat()
1678
+ #
1679
+ # Write the LINEFORMAT chart BIFF record.
1680
+ #
1681
+ def store_lineformat(rgb, lns, we, grbit, index) # :nodoc:
1682
+ record = 0x1007 # Record identifier.
1683
+ length = 0x000C # Number of bytes to follow.
1684
+ # rgb # Line RGB colour.
1685
+ # lns # Line pattern.
1686
+ # we # Line weight.
1687
+ # grbit # Option flags.
1688
+ # index # Index to colour of line.
1689
+
1690
+ header = [record, length].pack('vv')
1691
+ data = [rgb].pack('V')
1692
+ data += [lns].pack('v')
1693
+ data += [we].pack('v')
1694
+ data += [grbit].pack('v')
1695
+ data += [index].pack('v')
1696
+
1697
+ append(header, data)
1698
+ end
1699
+
1700
+ ###############################################################################
1701
+ #
1702
+ # _store_markerformat()
1703
+ #
1704
+ # Write the MARKERFORMAT chart BIFF record.
1705
+ #
1706
+ def store_markerformat(rgbFore, rgbBack, marker, grbit, icvFore, icvBack, miSize)# :nodoc:
1707
+ record = 0x1009 # Record identifier.
1708
+ length = 0x0014 # Number of bytes to follow.
1709
+ # rgbFore # Foreground RGB color.
1710
+ # rgbBack # Background RGB color.
1711
+ # marker # Type of marker.
1712
+ # grbit # Format flags.
1713
+ # icvFore # Color index marker border.
1714
+ # icvBack # Color index marker fill.
1715
+ # miSize # Size of line markers.
1716
+
1717
+ header = [record, length].pack('vv')
1718
+ data = [rgbFore].pack('V')
1719
+ data += [rgbBack].pack('V')
1720
+ data += [marker].pack('v')
1721
+ data += [grbit].pack('v')
1722
+ data += [icvFore].pack('v')
1723
+ data += [icvBack].pack('v')
1724
+ data += [miSize].pack('V')
1725
+
1726
+ append(header, data)
1727
+ end
1728
+
1729
+ ###############################################################################
1730
+ #
1731
+ # _store_objectlink()
1732
+ #
1733
+ # Write the OBJECTLINK chart BIFF record.
1734
+ #
1735
+ def store_objectlink(link_type) # :nodoc:
1736
+ record = 0x1027 # Record identifier.
1737
+ length = 0x0006 # Number of bytes to follow.
1738
+ # link_type # Object text link type.
1739
+ link_index1 = 0x0000 # Link index 1.
1740
+ link_index2 = 0x0000 # Link index 2.
1741
+
1742
+ store_simple(record, length, link_type, link_index1, link_index2)
1743
+ end
1744
+
1745
+ ###############################################################################
1746
+ #
1747
+ # _store_pieformat()
1748
+ #
1749
+ # Write the PIEFORMAT chart BIFF record.
1750
+ #
1751
+ def store_pieformat # :nodoc:
1752
+ record = 0x100B # Record identifier.
1753
+ length = 0x0002 # Number of bytes to follow.
1754
+ percent = 0x0000 # Distance % from center.
1755
+
1756
+ store_simple(record, length, percent)
1757
+ end
1758
+
1759
+ ###############################################################################
1760
+ #
1761
+ # _store_plotarea()
1762
+ #
1763
+ # Write the PLOTAREA chart BIFF record. This indicates that the subsequent
1764
+ # FRAME record belongs to a plot area.
1765
+ #
1766
+ def store_plotarea # :nodoc:
1767
+ record = 0x1035 # Record identifier.
1768
+ length = 0x0000 # Number of bytes to follow.
1769
+
1770
+ store_simple(record, length)
1771
+ end
1772
+
1773
+ ###############################################################################
1774
+ #
1775
+ # _store_plotgrowth()
1776
+ #
1777
+ # Write the PLOTGROWTH chart BIFF record.
1778
+ #
1779
+ def store_plotgrowth # :nodoc:
1780
+ record = 0x1064 # Record identifier.
1781
+ length = 0x0008 # Number of bytes to follow.
1782
+ dx_plot = 0x00010000 # Horz growth for font scale.
1783
+ dy_plot = 0x00010000 # Vert growth for font scale.
1784
+
1785
+ header = [record, length].pack('vv')
1786
+ data = [dx_plot].pack('V')
1787
+ data += [dy_plot].pack('V')
1788
+
1789
+ append(header, data)
1790
+ end
1791
+
1792
+ ###############################################################################
1793
+ #
1794
+ # _store_pos()
1795
+ #
1796
+ # Write the POS chart BIFF record. Generally not required when using
1797
+ # automatic positioning.
1798
+ #
1799
+ def store_pos(mdTopLt, mdBotRt, x1, y1, x2, y2) # :nodoc:
1800
+ record = 0x104F # Record identifier.
1801
+ length = 0x0014 # Number of bytes to follow.
1802
+ # mdTopLt # Top left.
1803
+ # mdBotRt # Bottom right.
1804
+ # x1 # X coordinate.
1805
+ # y1 # Y coordinate.
1806
+ # x2 # Width.
1807
+ # y2 # Height.
1808
+
1809
+ header = [record, length].pack('vv')
1810
+ data = [mdTopLt].pack('v')
1811
+ data += [mdBotRt].pack('v')
1812
+ data += [x1].pack('V')
1813
+ data += [y1].pack('V')
1814
+ data += [x2].pack('V')
1815
+ data += [y2].pack('V')
1816
+
1817
+ append(header, data)
1818
+ end
1819
+
1820
+ ###############################################################################
1821
+ #
1822
+ # _store_serauxtrend()
1823
+ #
1824
+ # Write the SERAUXTREND chart BIFF record.
1825
+ #
1826
+ def store_serauxtrend(reg_type, poly_order, equation, r_squared) # :nodoc:
1827
+ record = 0x104B # Record identifier.
1828
+ length = 0x001C # Number of bytes to follow.
1829
+ # reg_type # Regression type.
1830
+ # poly_order # Polynomial order.
1831
+ # equation # Display equation.
1832
+ # r_squared # Display R-squared.
1833
+ # intercept # Forced intercept.
1834
+ # forecast # Forecast forward.
1835
+ # backcast # Forecast backward.
1836
+
1837
+ # TODO. When supported, intercept needs to be NAN if not used.
1838
+ # Also need to reverse doubles.
1839
+ intercept = ['FFFFFFFF0001FFFF'].pack('H*')
1840
+ forecast = ['0000000000000000'].pack('H*')
1841
+ backcast = ['0000000000000000'].pack('H*')
1842
+
1843
+ header = [record, length].pack('vv')
1844
+ data = [reg_type].pack('C')
1845
+ data += [poly_order].pack('C')
1846
+ data += intercept
1847
+ data += [equation].pack('C')
1848
+ data += [r_squared].pack('C')
1849
+ data += forecast
1850
+ data += backcast
1851
+
1852
+ append(header, data)
1853
+ end
1854
+
1855
+ ###############################################################################
1856
+ #
1857
+ # _store_series()
1858
+ #
1859
+ # Write the SERIES chart BIFF record.
1860
+ #
1861
+ def store_series(category_count, value_count) # :nodoc:
1862
+ record = 0x1003 # Record identifier.
1863
+ length = 0x000C # Number of bytes to follow.
1864
+ category_type = 0x0001 # Type: category.
1865
+ value_type = 0x0001 # Type: value.
1866
+ # category_count # Num of categories.
1867
+ # value_count # Num of values.
1868
+ bubble_type = 0x0001 # Type: bubble.
1869
+ bubble_count = 0x0000 # Num of bubble values.
1870
+
1871
+ store_simple(record, length, category_type, value_type,
1872
+ category_count, value_count, bubble_type, bubble_count)
1873
+ end
1874
+
1875
+ ###############################################################################
1876
+ #
1877
+ # _store_seriestext()
1878
+ #
1879
+ # Write the SERIESTEXT chart BIFF record.
1880
+ #
1881
+ def store_seriestext(str, encoding) # :nodoc:
1882
+ ruby_19 { str = convert_to_ascii_if_ascii(str) }
1883
+
1884
+ record = 0x100D # Record identifier.
1885
+ length = 0x0000 # Number of bytes to follow.
1886
+ id = 0x0000 # Text id.
1887
+ # str # Text.
1888
+ # encoding # String encoding.
1889
+ cch = str.bytesize # String length.
1890
+
1891
+ encoding ||= 0
1892
+
1893
+ # Character length is num of chars not num of bytes
1894
+ cch /= 2 if encoding != 0
1895
+
1896
+ # Change the UTF-16 name from BE to LE
1897
+ str = str.unpack('v*').pack('n*') if encoding != 0
1898
+
1899
+ length = 4 + str.bytesize
1900
+
1901
+ header = [record, length].pack('vv')
1902
+ data = [id].pack('v')
1903
+ data += [cch].pack('C')
1904
+ data += [encoding].pack('C')
1905
+
1906
+ append(header, data, str)
1907
+ end
1908
+
1909
+ ###############################################################################
1910
+ #
1911
+ # _store_serparent()
1912
+ #
1913
+ # Write the SERPARENT chart BIFF record.
1914
+ #
1915
+ def store_serparent(series) # :nodoc:
1916
+ record = 0x104A # Record identifier.
1917
+ length = 0x0002 # Number of bytes to follow.
1918
+ # series # Series parent.
1919
+
1920
+ store_simple(record, length, series)
1921
+ end
1922
+
1923
+ ###############################################################################
1924
+ #
1925
+ # _store_sertocrt()
1926
+ #
1927
+ # Write the SERTOCRT chart BIFF record to indicate the chart group index.
1928
+ #
1929
+ def store_sertocrt # :nodoc:
1930
+ record = 0x1045 # Record identifier.
1931
+ length = 0x0002 # Number of bytes to follow.
1932
+ chartgroup = 0x0000 # Chart group index.
1933
+
1934
+ store_simple(record, length, chartgroup)
1935
+ end
1936
+
1937
+ ###############################################################################
1938
+ #
1939
+ # _store_shtprops()
1940
+ #
1941
+ # Write the SHTPROPS chart BIFF record.
1942
+ #
1943
+ def store_shtprops # :nodoc:
1944
+ record = 0x1044 # Record identifier.
1945
+ length = 0x0004 # Number of bytes to follow.
1946
+ grbit = 0x000E # Option flags.
1947
+ empty_cells = 0x0000 # Empty cell handling.
1948
+
1949
+ grbit = 0x000A if @embedded
1950
+
1951
+ store_simple(record, length, grbit, empty_cells)
1952
+ end
1953
+
1954
+ ###############################################################################
1955
+ #
1956
+ # _store_text()
1957
+ #
1958
+ # Write the TEXT chart BIFF record.
1959
+ #
1960
+ def store_text(x, y, dx, dy, grbit1, grbit2, rotation = 0x00)# :nodoc:
1961
+ record = 0x1025 # Record identifier.
1962
+ length = 0x0020 # Number of bytes to follow.
1963
+ at = 0x02 # Horizontal alignment.
1964
+ vat = 0x02 # Vertical alignment.
1965
+ wBkgMode = 0x0001 # Background display.
1966
+ rgbText = 0x0000 # Text RGB colour.
1967
+ # x # Text x-pos.
1968
+ # y # Text y-pos.
1969
+ # dx # Width.
1970
+ # dy # Height.
1971
+ # grbit1 # Option flags.
1972
+ icvText = 0x004D # Auto Colour.
1973
+ # grbit2 # Show legend.
1974
+ # rotation # Show value.
1975
+
1976
+ header = [record, length].pack('vv')
1977
+ data = [at].pack('C')
1978
+ data += [vat].pack('C')
1979
+ data += [wBkgMode].pack('v')
1980
+ data += [rgbText].pack('V')
1981
+ data += [x].pack('V')
1982
+ data += [y].pack('V')
1983
+ data += [dx].pack('V')
1984
+ data += [dy].pack('V')
1985
+ data += [grbit1].pack('v')
1986
+ data += [icvText].pack('v')
1987
+ data += [grbit2].pack('v')
1988
+ data += [rotation].pack('v')
1989
+
1990
+ append(header, data)
1991
+ end
1992
+
1993
+ ###############################################################################
1994
+ #
1995
+ # _store_tick()
1996
+ #
1997
+ # Write the TICK chart BIFF record.
1998
+ #
1999
+ def store_tick # :nodoc:
2000
+ record = 0x101E # Record identifier.
2001
+ length = 0x001E # Number of bytes to follow.
2002
+ tktMajor = 0x02 # Type of major tick mark.
2003
+ tktMinor = 0x00 # Type of minor tick mark.
2004
+ tlt = 0x03 # Tick label position.
2005
+ wBkgMode = 0x01 # Background mode.
2006
+ rgb = 0x00000000 # Tick-label RGB colour.
2007
+ reserved1 = 0x00000000 # Reserved.
2008
+ reserved2 = 0x00000000 # Reserved.
2009
+ reserved3 = 0x00000000 # Reserved.
2010
+ reserved4 = 0x00000000 # Reserved.
2011
+ grbit = 0x0023 # Option flags.
2012
+ index = 0x004D # Colour index.
2013
+ reserved5 = 0x0000 # Reserved.
2014
+
2015
+ header = [record, length].pack('vv')
2016
+ data = [tktMajor].pack('C')
2017
+ data += [tktMinor].pack('C')
2018
+ data += [tlt].pack('C')
2019
+ data += [wBkgMode].pack('C')
2020
+ data += [rgb].pack('V')
2021
+ data += [reserved1].pack('V')
2022
+ data += [reserved2].pack('V')
2023
+ data += [reserved3].pack('V')
2024
+ data += [reserved4].pack('V')
2025
+ data += [grbit].pack('v')
2026
+ data += [index].pack('v')
2027
+ data += [reserved5].pack('v')
2028
+
2029
+ append(header, data)
2030
+ end
2031
+
2032
+ ###############################################################################
2033
+ #
2034
+ # _store_valuerange()
2035
+ #
2036
+ # Write the VALUERANGE chart BIFF record.
2037
+ #
2038
+ def store_valuerange # :nodoc:
2039
+ record = 0x101F # Record identifier.
2040
+ length = 0x002A # Number of bytes to follow.
2041
+ numMin = 0x00000000 # Minimum value on axis.
2042
+ numMax = 0x00000000 # Maximum value on axis.
2043
+ numMajor = 0x00000000 # Value of major increment.
2044
+ numMinor = 0x00000000 # Value of minor increment.
2045
+ numCross = 0x00000000 # Value where category axis crosses.
2046
+ grbit = 0x011F # Format flags.
2047
+
2048
+ # TODO. Reverse doubles when they are handled.
2049
+
2050
+ header = [record, length].pack('vv')
2051
+ data = [numMin].pack('d')
2052
+ data += [numMax].pack('d')
2053
+ data += [numMajor].pack('d')
2054
+ data += [numMinor].pack('d')
2055
+ data += [numCross].pack('d')
2056
+ data += [grbit].pack('v')
2057
+
2058
+ append(header, data)
2059
+ end
2060
+
2061
+
2062
+ ###############################################################################
2063
+ #
2064
+ # Config data.
2065
+ #
2066
+ ###############################################################################
2067
+
2068
+ ###############################################################################
2069
+ #
2070
+ # _set_default_properties()
2071
+ #
2072
+ # Setup the default properties for a chart.
2073
+ #
2074
+ def set_default_properties # :nodoc:
2075
+ @legend = {
2076
+ :visible => 1,
2077
+ :position => 0,
2078
+ :vertical => 0,
2079
+ }
2080
+
2081
+ @chartarea = {
2082
+ :visible => 0,
2083
+ :fg_color_index => 0x4E,
2084
+ :fg_color_rgb => 0xFFFFFF,
2085
+ :bg_color_index => 0x4D,
2086
+ :bg_color_rgb => 0x000000,
2087
+ :area_pattern => 0x0000,
2088
+ :area_options => 0x0000,
2089
+ :line_pattern => 0x0005,
2090
+ :line_weight => 0xFFFF,
2091
+ :line_color_index => 0x4D,
2092
+ :line_color_rgb => 0x000000,
2093
+ :line_options => 0x0008,
2094
+ }
2095
+
2096
+ @plotarea = {
2097
+ :visible => 1,
2098
+ :fg_color_index => 0x16,
2099
+ :fg_color_rgb => 0xC0C0C0,
2100
+ :bg_color_index => 0x4F,
2101
+ :bg_color_rgb => 0x000000,
2102
+ :area_pattern => 0x0001,
2103
+ :area_options => 0x0000,
2104
+ :line_pattern => 0x0000,
2105
+ :line_weight => 0x0000,
2106
+ :line_color_index => 0x17,
2107
+ :line_color_rgb => 0x808080,
2108
+ :line_options => 0x0000,
2109
+ }
2110
+ end
2111
+
2112
+ ###############################################################################
2113
+ #
2114
+ # _set_default_config_data()
2115
+ #
2116
+ # Setup the default configuration data for a chart.
2117
+ #
2118
+ def set_default_config_data # :nodoc:
2119
+ @config = default_config_data
2120
+ end
2121
+
2122
+ def default_config_data # :nodoc:
2123
+ {
2124
+ :axisparent => [ 0, 0x00F8, 0x01F5, 0x0E7F, 0x0B36 ],
2125
+ :axisparent_pos => [ 2, 2, 0x008C, 0x01AA, 0x0EEA, 0x0C52 ],
2126
+ :chart => [ 0x0000, 0x0000, 0x02DD51E0, 0x01C2B838 ],
2127
+ :font_numbers => [ 5, 10, 0x38B8, 0x22A1, 0x0000 ],
2128
+ :font_series => [ 6, 10, 0x38B8, 0x22A1, 0x0001 ],
2129
+ :font_title => [ 7, 12, 0x38B8, 0x22A1, 0x0000 ],
2130
+ :font_axes => [ 8, 10, 0x38B8, 0x22A1, 0x0001 ],
2131
+ :legend => [ 0x05F9, 0x0EE9, 0x047D, 0x9C, 0x00, 0x01, 0x0F ],
2132
+ :legend_pos => [ 5, 2, 0x05F9, 0x0EE9, 0, 0 ],
2133
+ :legend_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x0000 ],
2134
+ :legend_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2135
+ :series_text => [ 0xFFFFFF46, 0xFFFFFF06, 0, 0, 0x00B1, 0x1020 ],
2136
+ :series_text_pos => [ 2, 2, 0, 0, 0, 0 ],
2137
+ :title_text => [ 0x06E4, 0x0051, 0x01DB, 0x00C4, 0x0081, 0x1030 ],
2138
+ :title_text_pos => [ 2, 2, 0, 0, 0x73, 0x1D ],
2139
+ :x_axis_text => [ 0x07E1, 0x0DFC, 0xB2, 0x9C, 0x0081, 0x0000 ],
2140
+ :x_axis_text_pos => [ 2, 2, 0, 0, 0x2B, 0x17 ],
2141
+ :y_axis_text => [ 0x002D, 0x06AA, 0x5F, 0x1CC, 0x0281, 0x00, 90 ],
2142
+ :y_axis_text_pos => [ 2, 2, 0, 0, 0x17, 0x44 ],
2143
+ }
2144
+ end
2145
+ private :default_config_data
2146
+
2147
+ ###############################################################################
2148
+ #
2149
+ # _set_embedded_config_data()
2150
+ #
2151
+ # Setup the default configuration data for an embedded chart.
2152
+ #
2153
+ def set_embedded_config_data # :nodoc:
2154
+ @embedded = true
2155
+
2156
+ @chartarea = {
2157
+ :visible => 1,
2158
+ :fg_color_index => 0x4E,
2159
+ :fg_color_rgb => 0xFFFFFF,
2160
+ :bg_color_index => 0x4D,
2161
+ :bg_color_rgb => 0x000000,
2162
+ :area_pattern => 0x0001,
2163
+ :area_options => 0x0001,
2164
+ :line_pattern => 0x0000,
2165
+ :line_weight => 0x0000,
2166
+ :line_color_index => 0x4D,
2167
+ :line_color_rgb => 0x000000,
2168
+ :line_options => 0x0009,
2169
+ }
2170
+
2171
+ @config = default_config_data.merge({
2172
+ :axisparent => [ 0, 0x01D8, 0x031D, 0x0D79, 0x07E9 ],
2173
+ :axisparent_pos => [ 2, 2, 0x010C, 0x0292, 0x0E46, 0x09FD ],
2174
+ :chart => [ 0x0000, 0x0000, 0x01847FE8, 0x00F47FE8 ],
2175
+ :font_numbers => [ 5, 10, 0x1DC4, 0x1284, 0x0000 ],
2176
+ :font_series => [ 6, 10, 0x1DC4, 0x1284, 0x0001 ],
2177
+ :font_title => [ 7, 12, 0x1DC4, 0x1284, 0x0000 ],
2178
+ :font_axes => [ 8, 10, 0x1DC4, 0x1284, 0x0001 ],
2179
+ :legend => [ 0x044E, 0x0E4A, 0x088D, 0x0123, 0x0, 0x1, 0xF ],
2180
+ :legend_pos => [ 5, 2, 0x044E, 0x0E4A, 0, 0 ],
2181
+ :legend_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x0000 ],
2182
+ :series_text => [ 0xFFFFFFD9, 0xFFFFFFC1, 0, 0, 0x00B1, 0x1020 ],
2183
+ :title_text => [ 0x060F, 0x004C, 0x038A, 0x016F, 0x0081, 0x1030 ],
2184
+ :x_axis_text => [ 0x07EF, 0x0C8F, 0x153, 0x123, 0x81, 0x00 ],
2185
+ :y_axis_text => [ 0x0057, 0x0564, 0xB5, 0x035D, 0x0281, 0x00, 90 ],
2186
+ })
2187
+ end
2188
+ end # class Chart
2189
+
2190
+ end # module Writeexcel