write_xlsx 1.02.0 → 1.08.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/Changes +72 -0
  4. data/README.md +1 -1
  5. data/examples/chart_data_labels.rb +320 -0
  6. data/examples/chart_line.rb +85 -10
  7. data/examples/tables.rb +77 -42
  8. data/lib/write_xlsx/chart/line.rb +15 -1
  9. data/lib/write_xlsx/chart/series.rb +100 -0
  10. data/lib/write_xlsx/chart.rb +155 -33
  11. data/lib/write_xlsx/drawing.rb +80 -17
  12. data/lib/write_xlsx/format.rb +5 -5
  13. data/lib/write_xlsx/package/app.rb +3 -3
  14. data/lib/write_xlsx/package/comments.rb +4 -4
  15. data/lib/write_xlsx/package/conditional_format.rb +2 -8
  16. data/lib/write_xlsx/package/packager.rb +1 -0
  17. data/lib/write_xlsx/package/relationships.rb +2 -2
  18. data/lib/write_xlsx/package/styles.rb +42 -11
  19. data/lib/write_xlsx/package/table.rb +16 -7
  20. data/lib/write_xlsx/package/vml.rb +20 -19
  21. data/lib/write_xlsx/sheets.rb +12 -20
  22. data/lib/write_xlsx/utility.rb +9 -3
  23. data/lib/write_xlsx/version.rb +1 -1
  24. data/lib/write_xlsx/workbook.rb +76 -35
  25. data/lib/write_xlsx/worksheet/data_validation.rb +1 -6
  26. data/lib/write_xlsx/worksheet.rb +197 -57
  27. data/test/drawing/{test_write_ext.rb → test_write_xdr_ext.rb} +2 -2
  28. data/test/perl_output/chart_data_labels.xlsx +0 -0
  29. data/test/perl_output/chart_line.xlsx +0 -0
  30. data/test/perl_output/comments2.xlsx +0 -0
  31. data/test/perl_output/tables.xlsx +0 -0
  32. data/test/regression/images/red2.png +0 -0
  33. data/test/regression/test_array_formula04.rb +31 -0
  34. data/test/regression/test_chart_crossing01.rb +1 -1
  35. data/test/regression/test_chart_crossing05.rb +46 -0
  36. data/test/regression/test_chart_crossing06.rb +46 -0
  37. data/test/regression/test_chart_data_labels26.rb +44 -0
  38. data/test/regression/test_chart_data_labels27.rb +44 -0
  39. data/test/regression/test_chart_data_labels28.rb +52 -0
  40. data/test/regression/test_chart_data_labels29.rb +43 -0
  41. data/test/regression/test_chart_data_labels30.rb +46 -0
  42. data/test/regression/test_chart_data_labels31.rb +49 -0
  43. data/test/regression/test_chart_data_labels32.rb +54 -0
  44. data/test/regression/test_chart_data_labels33.rb +52 -0
  45. data/test/regression/test_chart_data_labels34.rb +54 -0
  46. data/test/regression/test_chart_data_labels35.rb +46 -0
  47. data/test/regression/test_chart_data_labels36.rb +54 -0
  48. data/test/regression/test_chart_data_labels37.rb +51 -0
  49. data/test/regression/test_chart_data_labels38.rb +54 -0
  50. data/test/regression/test_chart_data_labels39.rb +53 -0
  51. data/test/regression/test_chart_data_labels40.rb +53 -0
  52. data/test/regression/test_chart_data_labels41.rb +54 -0
  53. data/test/regression/test_chart_data_labels42.rb +58 -0
  54. data/test/regression/test_chart_data_labels43.rb +58 -0
  55. data/test/regression/test_chart_data_labels44.rb +56 -0
  56. data/test/regression/test_chart_data_labels45.rb +57 -0
  57. data/test/regression/test_chart_data_labels46.rb +61 -0
  58. data/test/regression/test_chart_data_labels47.rb +61 -0
  59. data/test/regression/test_chart_data_labels48.rb +55 -0
  60. data/test/regression/test_chart_data_labels49.rb +55 -0
  61. data/test/regression/test_chart_data_labels50.rb +57 -0
  62. data/test/regression/test_chart_line05.rb +43 -0
  63. data/test/regression/test_chart_line06.rb +43 -0
  64. data/test/regression/test_comment15.rb +28 -0
  65. data/test/regression/test_comment16.rb +34 -0
  66. data/test/regression/test_format16.rb +24 -0
  67. data/test/regression/test_format17.rb +24 -0
  68. data/test/regression/test_header04.rb +30 -0
  69. data/test/regression/test_header_image15.rb +36 -0
  70. data/test/regression/test_header_image16.rb +42 -0
  71. data/test/regression/test_header_image17.rb +46 -0
  72. data/test/regression/test_header_image18.rb +48 -0
  73. data/test/regression/test_header_image19.rb +36 -0
  74. data/test/regression/test_hyperlink48.rb +31 -0
  75. data/test/regression/test_hyperlink49.rb +29 -0
  76. data/test/regression/test_hyperlink50.rb +27 -0
  77. data/test/regression/test_hyperlink51.rb +27 -0
  78. data/test/regression/test_ignore_error01.rb +23 -0
  79. data/test/regression/test_ignore_error02.rb +24 -0
  80. data/test/regression/test_ignore_error03.rb +26 -0
  81. data/test/regression/test_ignore_error04.rb +26 -0
  82. data/test/regression/test_ignore_error05.rb +32 -0
  83. data/test/regression/test_ignore_error06.rb +32 -0
  84. data/test/regression/test_image45.rb +2 -1
  85. data/test/regression/test_image46.rb +1 -1
  86. data/test/regression/test_image48.rb +32 -0
  87. data/test/regression/test_image49.rb +38 -0
  88. data/test/regression/test_image50.rb +24 -0
  89. data/test/regression/test_image51.rb +30 -0
  90. data/test/regression/test_image52.rb +26 -0
  91. data/test/regression/test_image53.rb +26 -0
  92. data/test/regression/test_image54.rb +26 -0
  93. data/test/regression/test_image55.rb +27 -0
  94. data/test/regression/test_object_position12.rb +25 -0
  95. data/test/regression/test_object_position13.rb +25 -0
  96. data/test/regression/test_object_position14.rb +25 -0
  97. data/test/regression/test_object_position15.rb +29 -0
  98. data/test/regression/test_object_position16.rb +29 -0
  99. data/test/regression/test_object_position17.rb +29 -0
  100. data/test/regression/test_object_position18.rb +29 -0
  101. data/test/regression/test_object_position19.rb +29 -0
  102. data/test/regression/test_object_position20.rb +29 -0
  103. data/test/regression/test_protect04.rb +32 -0
  104. data/test/regression/test_protect05.rb +35 -0
  105. data/test/regression/test_protect06.rb +35 -0
  106. data/test/regression/test_protect07.rb +23 -0
  107. data/test/regression/test_table24.rb +27 -0
  108. data/test/regression/test_table25.rb +27 -0
  109. data/test/regression/test_table26.rb +38 -0
  110. data/test/regression/xlsx_files/array_formula04.xlsx +0 -0
  111. data/test/regression/xlsx_files/chart_crossing05.xlsx +0 -0
  112. data/test/regression/xlsx_files/chart_crossing06.xlsx +0 -0
  113. data/test/regression/xlsx_files/chart_data_labels26.xlsx +0 -0
  114. data/test/regression/xlsx_files/chart_data_labels27.xlsx +0 -0
  115. data/test/regression/xlsx_files/chart_data_labels28.xlsx +0 -0
  116. data/test/regression/xlsx_files/chart_data_labels29.xlsx +0 -0
  117. data/test/regression/xlsx_files/chart_data_labels30.xlsx +0 -0
  118. data/test/regression/xlsx_files/chart_data_labels31.xlsx +0 -0
  119. data/test/regression/xlsx_files/chart_data_labels32.xlsx +0 -0
  120. data/test/regression/xlsx_files/chart_data_labels33.xlsx +0 -0
  121. data/test/regression/xlsx_files/chart_data_labels34.xlsx +0 -0
  122. data/test/regression/xlsx_files/chart_data_labels35.xlsx +0 -0
  123. data/test/regression/xlsx_files/chart_data_labels36.xlsx +0 -0
  124. data/test/regression/xlsx_files/chart_data_labels37.xlsx +0 -0
  125. data/test/regression/xlsx_files/chart_data_labels38.xlsx +0 -0
  126. data/test/regression/xlsx_files/chart_data_labels39.xlsx +0 -0
  127. data/test/regression/xlsx_files/chart_data_labels40.xlsx +0 -0
  128. data/test/regression/xlsx_files/chart_data_labels41.xlsx +0 -0
  129. data/test/regression/xlsx_files/chart_data_labels42.xlsx +0 -0
  130. data/test/regression/xlsx_files/chart_data_labels43.xlsx +0 -0
  131. data/test/regression/xlsx_files/chart_data_labels44.xlsx +0 -0
  132. data/test/regression/xlsx_files/chart_data_labels45.xlsx +0 -0
  133. data/test/regression/xlsx_files/chart_data_labels46.xlsx +0 -0
  134. data/test/regression/xlsx_files/chart_data_labels47.xlsx +0 -0
  135. data/test/regression/xlsx_files/chart_data_labels48.xlsx +0 -0
  136. data/test/regression/xlsx_files/chart_data_labels49.xlsx +0 -0
  137. data/test/regression/xlsx_files/chart_data_labels50.xlsx +0 -0
  138. data/test/regression/xlsx_files/chart_line05.xlsx +0 -0
  139. data/test/regression/xlsx_files/chart_line06.xlsx +0 -0
  140. data/test/regression/xlsx_files/comment15.xlsx +0 -0
  141. data/test/regression/xlsx_files/comment16.xlsx +0 -0
  142. data/test/regression/xlsx_files/format16.xlsx +0 -0
  143. data/test/regression/xlsx_files/format17.xlsx +0 -0
  144. data/test/regression/xlsx_files/header04.xlsx +0 -0
  145. data/test/regression/xlsx_files/header_image15.xlsx +0 -0
  146. data/test/regression/xlsx_files/header_image16.xlsx +0 -0
  147. data/test/regression/xlsx_files/header_image17.xlsx +0 -0
  148. data/test/regression/xlsx_files/header_image18.xlsx +0 -0
  149. data/test/regression/xlsx_files/header_image19.xlsx +0 -0
  150. data/test/regression/xlsx_files/hyperlink46.xlsx +0 -0
  151. data/test/regression/xlsx_files/hyperlink50.xlsx +0 -0
  152. data/test/regression/xlsx_files/hyperlink51.xlsx +0 -0
  153. data/test/regression/xlsx_files/ignore_error01.xlsx +0 -0
  154. data/test/regression/xlsx_files/ignore_error02.xlsx +0 -0
  155. data/test/regression/xlsx_files/ignore_error03.xlsx +0 -0
  156. data/test/regression/xlsx_files/ignore_error04.xlsx +0 -0
  157. data/test/regression/xlsx_files/ignore_error05.xlsx +0 -0
  158. data/test/regression/xlsx_files/ignore_error06.xlsx +0 -0
  159. data/test/regression/xlsx_files/image45.xlsx +0 -0
  160. data/test/regression/xlsx_files/image46.xlsx +0 -0
  161. data/test/regression/xlsx_files/image48.xlsx +0 -0
  162. data/test/regression/xlsx_files/image49.xlsx +0 -0
  163. data/test/regression/xlsx_files/image50.xlsx +0 -0
  164. data/test/regression/xlsx_files/image51.xlsx +0 -0
  165. data/test/regression/xlsx_files/image52.xlsx +0 -0
  166. data/test/regression/xlsx_files/image53.xlsx +0 -0
  167. data/test/regression/xlsx_files/image54.xlsx +0 -0
  168. data/test/regression/xlsx_files/image55.xlsx +0 -0
  169. data/test/regression/xlsx_files/object_position12.xlsx +0 -0
  170. data/test/regression/xlsx_files/object_position13.xlsx +0 -0
  171. data/test/regression/xlsx_files/object_position14.xlsx +0 -0
  172. data/test/regression/xlsx_files/object_position15.xlsx +0 -0
  173. data/test/regression/xlsx_files/object_position16.xlsx +0 -0
  174. data/test/regression/xlsx_files/object_position17.xlsx +0 -0
  175. data/test/regression/xlsx_files/object_position18.xlsx +0 -0
  176. data/test/regression/xlsx_files/object_position19.xlsx +0 -0
  177. data/test/regression/xlsx_files/object_position20.xlsx +0 -0
  178. data/test/regression/xlsx_files/protect04.xlsx +0 -0
  179. data/test/regression/xlsx_files/protect05.xlsx +0 -0
  180. data/test/regression/xlsx_files/protect06.xlsx +0 -0
  181. data/test/regression/xlsx_files/protect07.xlsx +0 -0
  182. data/test/regression/xlsx_files/table24.xlsx +0 -0
  183. data/test/regression/xlsx_files/table25.xlsx +0 -0
  184. data/test/regression/xlsx_files/table26.xlsx +0 -0
  185. data/test/test_example_match.rb +433 -10
  186. data/test/utility/test_range.rb +20 -0
  187. data/test/workbook/test_check_sheetname.rb +0 -10
  188. data/write_xlsx.gemspec +1 -0
  189. metadata +323 -8
data/examples/tables.rb CHANGED
@@ -28,6 +28,7 @@ worksheet9 = workbook.add_worksheet
28
28
  worksheet10 = workbook.add_worksheet
29
29
  worksheet11 = workbook.add_worksheet
30
30
  worksheet12 = workbook.add_worksheet
31
+ worksheet13 = workbook.add_worksheet
31
32
 
32
33
  currency_format = workbook.add_format(:num_format => '$#,##0')
33
34
 
@@ -60,7 +61,7 @@ worksheet1.add_table('B3:F7')
60
61
  #
61
62
  # Example 2.
62
63
  #
63
- caption = 'Default table with data.';
64
+ caption = 'Default table with data.'
64
65
 
65
66
  # Set the columns widths.
66
67
  worksheet2.set_column('B:G', 12)
@@ -130,7 +131,7 @@ worksheet5.write_col('B4', data)
130
131
  #
131
132
  # Example 6.
132
133
  #
133
- caption = 'Table with banded columns but without default banded rows.';
134
+ caption = 'Table with banded columns but without default banded rows.'
134
135
 
135
136
  # Set the columns widths.
136
137
  worksheet6.set_column('B:G', 12)
@@ -149,7 +150,7 @@ worksheet6.write_col('B4', data)
149
150
  #
150
151
  # Example 7.
151
152
  #
152
- caption = 'Table with user defined column headers';
153
+ caption = 'Table with user defined column headers'
153
154
 
154
155
  # Set the columns widths.
155
156
  worksheet7.set_column('B:G', 12)
@@ -176,7 +177,7 @@ worksheet7.add_table(
176
177
  #
177
178
  # Example 8.
178
179
  #
179
- caption = 'Table with user defined column headers';
180
+ caption = 'Table with user defined column headers'
180
181
 
181
182
  # Set the columns widths.
182
183
  worksheet8.set_column('B:G', 12)
@@ -208,7 +209,7 @@ worksheet8.add_table(
208
209
  #
209
210
  # Example 9.
210
211
  #
211
- caption = 'Table with totals row (but no caption or totals).';
212
+ caption = 'Table with totals row (but no caption or totals).'
212
213
 
213
214
  # Set the columns widths.
214
215
  worksheet9.set_column('B:G', 12)
@@ -241,7 +242,7 @@ worksheet9.add_table(
241
242
  #
242
243
  # Example 10.
243
244
  #
244
- caption = 'Table with totals row with user captions and functions.';
245
+ caption = 'Table with totals row with user captions and functions.'
245
246
 
246
247
  # Set the columns widths.
247
248
  worksheet10.set_column('B:G', 12)
@@ -275,7 +276,7 @@ worksheet10.add_table(
275
276
  #
276
277
  # Example 11.
277
278
  #
278
- caption = 'Table with alternative Excel style.';
279
+ caption = 'Table with alternative Excel style.'
279
280
 
280
281
  # Set the columns widths.
281
282
  worksheet11.set_column('B:G', 12)
@@ -310,7 +311,7 @@ worksheet11.add_table(
310
311
  #
311
312
  # Example 12.
312
313
  #
313
- caption = 'Table with column formats.';
314
+ caption = 'Table with no Excel style.'
314
315
 
315
316
  # Set the columns widths.
316
317
  worksheet12.set_column('B:G', 12)
@@ -320,40 +321,74 @@ worksheet12.write('B1', caption)
320
321
 
321
322
  # Add a table to the worksheet.
322
323
  worksheet12.add_table(
323
- 'B3:G8',
324
- {
325
- :data => data,
326
- :total_row => 1,
327
- :columns => [
328
- { :header => 'Product', :total_string => 'Totals' },
329
- {
330
- :header => 'Quarter 1',
331
- :total_function => 'sum',
332
- :format => currency_format,
333
- },
334
- {
335
- :header => 'Quarter 2',
336
- :total_function => 'sum',
337
- :format => currency_format,
338
- },
339
- {
340
- :header => 'Quarter 3',
341
- :total_function => 'sum',
342
- :format => currency_format,
343
- },
344
- {
345
- :header => 'Quarter 4',
346
- :total_function => 'sum',
347
- :format => currency_format,
348
- },
349
- {
350
- :header => 'Year',
351
- :formula => '=SUM(Table8[@[Quarter 1]:[Quarter 4]])',
352
- :total_function => 'sum',
353
- :format => currency_format,
354
- }
355
- ]
356
- }
324
+ 'B3:G8',
325
+ {
326
+ :data => data,
327
+ :style => 'None',
328
+ :total_row => 1,
329
+ :columns => [
330
+ { :header => 'Product', :total_string => 'Totals' },
331
+ { :header => 'Quarter 1', :total_function => 'sum' },
332
+ { :header => 'Quarter 2', :total_function => 'sum' },
333
+ { :header => 'Quarter 3', :total_function => 'sum' },
334
+ { :header => 'Quarter 4', :total_function => 'sum' },
335
+ {
336
+ :header => 'Year',
337
+ :formula => '=SUM(Table12[@[Quarter 1]:[Quarter 4]])',
338
+ :total_function => 'sum'
339
+ }
340
+ ]
341
+ }
342
+ )
343
+
344
+ ###############################################################################
345
+ #
346
+ # Example 13.
347
+ #
348
+ caption = 'Table with column formats.'
349
+
350
+ # Set the columns widths.
351
+ worksheet13.set_column('B:G', 12)
352
+
353
+ # Write the caption.
354
+ worksheet13.write('B1', caption)
355
+
356
+ # Add a table to the worksheet.
357
+ worksheet13.add_table(
358
+ 'B3:G8',
359
+ {
360
+ :data => data,
361
+ :total_row => 1,
362
+ :columns => [
363
+ { :header => 'Product', :total_string => 'Totals' },
364
+ {
365
+ :header => 'Quarter 1',
366
+ :total_function => 'sum',
367
+ :format => currency_format,
368
+ },
369
+ {
370
+ :header => 'Quarter 2',
371
+ :total_function => 'sum',
372
+ :format => currency_format,
373
+ },
374
+ {
375
+ :header => 'Quarter 3',
376
+ :total_function => 'sum',
377
+ :format => currency_format,
378
+ },
379
+ {
380
+ :header => 'Quarter 4',
381
+ :total_function => 'sum',
382
+ :format => currency_format,
383
+ },
384
+ {
385
+ :header => 'Year',
386
+ :formula => '=SUM(Table8[@[Quarter 1]:[Quarter 4]])',
387
+ :total_function => 'sum',
388
+ :format => currency_format,
389
+ }
390
+ ]
391
+ }
357
392
  )
358
393
 
359
394
  workbook.close
@@ -22,9 +22,17 @@ module Writexlsx
22
22
 
23
23
  def initialize(subtype)
24
24
  super(subtype)
25
+ @subtype = @subtype || 'standard'
25
26
  @default_marker = Marker.new(:type => 'none')
26
27
  @smooth_allowed = 1
27
28
 
29
+ # Override and reset the default axis values.
30
+ if @subtype == 'percent_stacked'
31
+ @y_axis.defaults[:num_format] = '0%'
32
+ end
33
+
34
+ set_y_axis
35
+
28
36
  # Set the available data label positions for this chart type.
29
37
  @label_position_default = 'right'
30
38
  @label_positions = {
@@ -54,9 +62,15 @@ module Writexlsx
54
62
  series = axes_series(params)
55
63
  return if series.empty?
56
64
 
65
+ if @subtype == 'percent_stacked'
66
+ subtype = 'percentStacked'
67
+ else
68
+ subtype = @subtype
69
+ end
70
+
57
71
  @writer.tag_elements('c:lineChart') do
58
72
  # Write the c:grouping element.
59
- write_grouping('standard')
73
+ write_grouping(subtype)
60
74
  # Write the series elements.
61
75
  series.each {|s| write_series(s)}
62
76
 
@@ -296,10 +296,110 @@ module Writexlsx
296
296
  labels[:separator] = separators[separator]
297
297
  end
298
298
 
299
+
300
+ # Set the line properties for the data labels.
301
+ line = line_properties( labels[:line] )
302
+
303
+ # Allow 'border' as a synonym for 'line'.
304
+ if labels[:border]
305
+ line = line_properties(labels[:border])
306
+ end
307
+
308
+ # Set the fill properties for the labels.
309
+ fill = fill_properties(labels[:fill])
310
+
311
+ # Set the pattern properties for the labels.
312
+ pattern = pattern_properties(labels[:pattern])
313
+
314
+ # Set the gradient fill properties for the labels.
315
+ gradient = gradient_properties(labels[:gradient])
316
+
317
+ # Pattern fill overrides solid fill.
318
+ if pattern
319
+ fill = nil
320
+ end
321
+
322
+ # Gradient fill overrides solid and pattern fills.
323
+ if gradient
324
+ pattern = nil
325
+ fill = nil
326
+ end
327
+
328
+ labels[:line] = line
329
+ labels[:fill] = fill
330
+ labels[:pattern] = pattern
331
+ labels[:gradient] = gradient
332
+
299
333
  if labels[:font]
300
334
  labels[:font] = convert_font_args(labels[:font])
301
335
  end
302
336
 
337
+ if labels[:custom]
338
+ # Duplicate, and modify, the custom label properties.
339
+ custom = []
340
+
341
+ labels[:custom].each do |label|
342
+ if !label
343
+ custom << nil
344
+ next
345
+ end
346
+
347
+ property = label.dup
348
+
349
+ # Convert formula.
350
+ if property[:value] && property[:value] =~ /^=[^!]+!\$/
351
+ property[:formula] = property[:value]
352
+ end
353
+
354
+ if property[:formula]
355
+ property[:formula] = property[:formula].sub(/^=/, '')
356
+
357
+ data_id = @chart.data_id(property[:formula], property[:data])
358
+ property[:data_id] = data_id
359
+ end
360
+
361
+ if property[:font]
362
+ property[:font] = convert_font_args(property[:font])
363
+ end
364
+
365
+ # Allow 'border' as a synonym for 'line'.
366
+ if property[:border]
367
+ line = line_properties(property[:border])
368
+ else
369
+ # Set the line properties for the data labels.
370
+ line = line_properties(property[:line])
371
+ end
372
+
373
+ # Set the fill properties for the labels.
374
+ fill = fill_properties(property[:fill])
375
+
376
+ # Set the pattern properties for the labels.
377
+ pattern = pattern_properties(property[:pattern])
378
+
379
+ # Set the gradient fill properties for the labels.
380
+ gradient = gradient_properties(property[:gradient])
381
+
382
+ # Pattern fill overrides solid fill.
383
+ if pattern
384
+ fill = nil
385
+ end
386
+
387
+ # Gradient fill overrides solid and pattern fills.
388
+ if gradient
389
+ pattern = nil
390
+ fill = nil
391
+ end
392
+
393
+ property[:line] = line
394
+ property[:fill] = fill
395
+ property[:pattern] = pattern
396
+ property[:gradient] = gradient
397
+
398
+ custom << property
399
+ end
400
+ labels[:custom] = custom
401
+ end
402
+
303
403
  labels
304
404
  end
305
405
  end
@@ -34,7 +34,7 @@ module Writexlsx
34
34
  @writer.empty_tag('c:showOutline', attributes) if ptrue?(outline)
35
35
  @writer.empty_tag('c:showKeys', attributes) if ptrue?(show_keys)
36
36
  # Write the table font.
37
- write_tx_pr(nil, font) if ptrue?(font)
37
+ write_tx_pr(font) if ptrue?(font)
38
38
  end
39
39
  end
40
40
 
@@ -783,7 +783,7 @@ module Writexlsx
783
783
  elsif @title.formula
784
784
  write_title_formula(@title, nil, nil, @title.layout, @title.overlay)
785
785
  elsif @title.name
786
- write_title_rich(@title, nil, @title.layout, @title.overlay)
786
+ write_title_rich(@title, nil, @title.name_font, @title.layout, @title.overlay)
787
787
  end
788
788
 
789
789
  # Write the c:plotArea element.
@@ -1204,7 +1204,7 @@ module Writexlsx
1204
1204
  if x_axis.formula
1205
1205
  write_title_formula(x_axis, is_y_axis, @x_axis, x_axis.layout)
1206
1206
  elsif x_axis.name
1207
- write_title_rich(x_axis, is_y_axis, x_axis.layout)
1207
+ write_title_rich(x_axis, is_y_axis, x_axis.name_font, x_axis.layout)
1208
1208
  end
1209
1209
 
1210
1210
  # Write the c:numFmt element.
@@ -1281,7 +1281,7 @@ module Writexlsx
1281
1281
  if y_axis.formula
1282
1282
  write_title_formula(y_axis, @horiz_val_axis, nil, y_axis.layout)
1283
1283
  elsif y_axis.name
1284
- write_title_rich(y_axis, @horiz_val_axis, y_axis.layout)
1284
+ write_title_rich(y_axis, @horiz_val_axis, y_axis.name_font, y_axis.layout)
1285
1285
  end
1286
1286
 
1287
1287
  # Write the c:numberFormat element.
@@ -1356,7 +1356,7 @@ module Writexlsx
1356
1356
  if x_axis.formula
1357
1357
  write_title_formula(x_axis, nil, nil, x_axis.layout)
1358
1358
  elsif x_axis.name
1359
- write_title_rich(x_axis, nil, x_axis.layout)
1359
+ write_title_rich(x_axis, nil, x_axis.name_font, x_axis.layout)
1360
1360
  end
1361
1361
  # Write the c:numFmt element.
1362
1362
  write_number_format(x_axis)
@@ -1397,7 +1397,7 @@ module Writexlsx
1397
1397
 
1398
1398
  def write_crossing(crossing)
1399
1399
  # Note, the category crossing comes from the value axis.
1400
- if nil_or_max?(crossing)
1400
+ if [nil, 'max', 'min'].include?(crossing)
1401
1401
  # Write the c:crosses element.
1402
1402
  write_crosses(crossing)
1403
1403
  else
@@ -1693,7 +1693,7 @@ module Writexlsx
1693
1693
  # Write the c:spPr element.
1694
1694
  write_sp_pr(@legend)
1695
1695
  # Write the c:txPr element.
1696
- write_tx_pr(nil, @legend.font) if ptrue?(@legend.font)
1696
+ write_tx_pr(@legend.font) if ptrue?(@legend.font)
1697
1697
  end
1698
1698
  end
1699
1699
 
@@ -1808,10 +1808,10 @@ module Writexlsx
1808
1808
  #
1809
1809
  # Write the <c:title> element for a rich string.
1810
1810
  #
1811
- def write_title_rich(title, is_y_axis = nil, layout = nil, overlay = nil) # :nodoc:
1811
+ def write_title_rich(title, is_y_axis, font, layout, overlay = nil) # :nodoc:
1812
1812
  @writer.tag_elements('c:title') do
1813
1813
  # Write the c:tx element.
1814
- write_tx_rich(title, is_y_axis)
1814
+ write_tx_rich(title, is_y_axis, font)
1815
1815
  # Write the c:layout element.
1816
1816
  write_layout(layout, 'text')
1817
1817
  # Write the c:overlay element.
@@ -1831,15 +1831,17 @@ module Writexlsx
1831
1831
  # Write the c:overlay element.
1832
1832
  write_overlay if overlay
1833
1833
  # Write the c:txPr element.
1834
- write_tx_pr(is_y_axis, axis ? axis.name_font : title.name_font)
1834
+ write_tx_pr(axis ? axis.name_font : title.name_font, is_y_axis)
1835
1835
  end
1836
1836
  end
1837
1837
 
1838
1838
  #
1839
1839
  # Write the <c:tx> element.
1840
1840
  #
1841
- def write_tx_rich(title, is_y_axis) # :nodoc:
1842
- @writer.tag_elements('c:tx') { write_rich(title, is_y_axis) }
1841
+ def write_tx_rich(title, is_y_axis, font) # :nodoc:
1842
+ @writer.tag_elements('c:tx') do
1843
+ write_rich(title, font, is_y_axis)
1844
+ end
1843
1845
  end
1844
1846
 
1845
1847
  #
@@ -1861,10 +1863,11 @@ module Writexlsx
1861
1863
  #
1862
1864
  # Write the <c:rich> element.
1863
1865
  #
1864
- def write_rich(title, is_y_axis) # :nodoc:
1866
+ def write_rich(title, font, is_y_axis, ignore_rich_pr = false) # :nodoc:
1865
1867
  rotation = nil
1866
- if title.name_font && title.name_font[:_rotation]
1867
- rotation = title.name_font[:_rotation]
1868
+
1869
+ if font && font[:_rotation]
1870
+ rotation = font[:_rotation]
1868
1871
  end
1869
1872
  @writer.tag_elements('c:rich') do
1870
1873
  # Write the a:bodyPr element.
@@ -1872,18 +1875,18 @@ module Writexlsx
1872
1875
  # Write the a:lstStyle element.
1873
1876
  write_a_lst_style
1874
1877
  # Write the a:p element.
1875
- write_a_p_rich(title)
1878
+ write_a_p_rich(title, font, ignore_rich_pr)
1876
1879
  end
1877
1880
  end
1878
1881
  #
1879
1882
  # Write the <a:p> element for rich string titles.
1880
1883
  #
1881
- def write_a_p_rich(title) # :nodoc:
1884
+ def write_a_p_rich(title, font, ignore_rich_pr) # :nodoc:
1882
1885
  @writer.tag_elements('a:p') do
1883
1886
  # Write the a:pPr element.
1884
- write_a_p_pr_rich(title.name_font)
1887
+ write_a_p_pr_rich(font) if !ignore_rich_pr
1885
1888
  # Write the a:r element.
1886
- write_a_r(title)
1889
+ write_a_r(title, font)
1887
1890
  end
1888
1891
  end
1889
1892
 
@@ -1897,12 +1900,12 @@ module Writexlsx
1897
1900
  #
1898
1901
  # Write the <a:r> element.
1899
1902
  #
1900
- def write_a_r(title) # :nodoc:
1903
+ def write_a_r(title, font) # :nodoc:
1901
1904
  @writer.tag_elements('a:r') do
1902
1905
  # Write the a:rPr element.
1903
- write_a_r_pr(title.name_font)
1906
+ write_a_r_pr(font)
1904
1907
  # Write the a:t element.
1905
- write_a_t(title.name)
1908
+ write_a_t(title.respond_to?(:name) ? title.name : title)
1906
1909
  end
1907
1910
  end
1908
1911
 
@@ -1967,17 +1970,27 @@ module Writexlsx
1967
1970
  @writer.empty_tag('c:symbol', [ ['val', val] ])
1968
1971
  end
1969
1972
 
1973
+ def has_fill_formatting(element)
1974
+ line = series_property(element, :line)
1975
+ fill = series_property(element, :fill)
1976
+ pattern = series_property(element, :pattern)
1977
+ gradient = series_property(element, :gradient)
1978
+
1979
+ (line && ptrue?(line[:_defined])) ||
1980
+ (fill && ptrue?(fill[:_defined])) || pattern || gradient
1981
+ end
1982
+
1983
+
1970
1984
  #
1971
1985
  # Write the <c:spPr> element.
1972
1986
  #
1973
1987
  def write_sp_pr(series) # :nodoc:
1974
- line = series.line
1975
- fill = series.fill
1976
- pattern = series.pattern if series.respond_to?(:pattern)
1977
- gradient = series.gradient if series.respond_to?(:gradient)
1988
+ return if !has_fill_formatting(series)
1978
1989
 
1979
- return if (!line || !ptrue?(line[:_defined])) &&
1980
- (!fill || !ptrue?(fill[:_defined])) && !pattern && !gradient
1990
+ line = series_property(series, :line)
1991
+ fill = series_property(series, :fill)
1992
+ pattern = series_property(series, :pattern)
1993
+ gradient = series_property(series, :gradient)
1981
1994
 
1982
1995
  @writer.tag_elements('c:spPr') do
1983
1996
  # Write the fill elements for solid charts such as pie/doughnut and bar.
@@ -2002,6 +2015,14 @@ module Writexlsx
2002
2015
  end
2003
2016
  end
2004
2017
 
2018
+ def series_property(object, property)
2019
+ if object.respond_to?(property)
2020
+ object.send(property)
2021
+ elsif object.respond_to?(:[])
2022
+ object[property]
2023
+ end
2024
+ end
2025
+
2005
2026
  #
2006
2027
  # Write the <a:ln> element.
2007
2028
  #
@@ -2349,8 +2370,14 @@ module Writexlsx
2349
2370
  return unless labels
2350
2371
 
2351
2372
  @writer.tag_elements('c:dLbls') do
2373
+ # Write the custom c:dLbl elements.
2374
+ if labels[:custom]
2375
+ write_custom_labels(labels, labels[:custom])
2376
+ end
2352
2377
  # Write the c:numFmt element.
2353
2378
  write_data_label_number_format(labels[:num_format]) if labels[:num_format]
2379
+ # Write the c:spPr element.
2380
+ write_sp_pr(labels)
2354
2381
  # Write the data label font elements.
2355
2382
  write_axis_font(labels[:font]) if labels[:font]
2356
2383
  # Write the c:dLblPos element.
@@ -2372,6 +2399,105 @@ module Writexlsx
2372
2399
  end
2373
2400
  end
2374
2401
 
2402
+ #
2403
+ # Write the <c:dLbl> element.
2404
+ #
2405
+ def write_custom_labels(parent, labels)
2406
+ index = 0
2407
+
2408
+ labels.each do |label|
2409
+ index += 1
2410
+ next if !ptrue?(label)
2411
+
2412
+ @writer.tag_elements('c:dLbl') do
2413
+ # Write the c:idx element.
2414
+ write_idx(index - 1)
2415
+
2416
+ if label[:delete] && label[:delete]
2417
+ write_delete(1)
2418
+ elsif label[:formula]
2419
+ write_custom_label_formula(label)
2420
+
2421
+ write_d_lbl_pos(parent[:position]) if parent[:position]
2422
+ write_show_val if parent[:value]
2423
+ write_show_cat_name if parent[:category]
2424
+ write_show_ser_name if parent[:series_name]
2425
+ elsif label[:value]
2426
+ write_custom_label_str(label)
2427
+
2428
+ write_d_lbl_pos(parent[:position]) if parent[:position]
2429
+ write_show_val if parent[:value]
2430
+ write_show_cat_name if parent[:category]
2431
+ write_show_ser_name if parent[:series_name]
2432
+ else
2433
+ write_custom_label_format_only(label)
2434
+ end
2435
+ end
2436
+ end
2437
+ end
2438
+
2439
+ #
2440
+ # Write parts of the <c:dLbl> element for strings.
2441
+ #
2442
+ def write_custom_label_str(label)
2443
+ value = label[:value]
2444
+ font = label[:font]
2445
+ is_y_axis = 0
2446
+ has_formatting = has_fill_formatting(label)
2447
+
2448
+ # Write the c:layout element.
2449
+ write_layout()
2450
+
2451
+ @writer.tag_elements('c:tx') do
2452
+ # Write the c:rich element.
2453
+ write_rich(value, font, is_y_axis, !has_formatting)
2454
+ end
2455
+
2456
+ # Write the c:cpPr element.
2457
+ write_sp_pr(label)
2458
+ end
2459
+
2460
+ #
2461
+ # Write parts of the <c:dLbl> element for formulas.
2462
+ #
2463
+ def write_custom_label_formula(label)
2464
+ formula = label[:formula]
2465
+ data_id = label[:data_id]
2466
+
2467
+ if data_id
2468
+ data = @formula_data[data_id]
2469
+ end
2470
+
2471
+ # Write the c:layout element.
2472
+ write_layout
2473
+
2474
+ @writer.tag_elements('c:tx') do
2475
+ # Write the c:strRef element.
2476
+ write_str_ref(formula, data, 'str')
2477
+ end
2478
+
2479
+ # Write the data label formatting, if any.
2480
+ write_custom_label_format_only(label)
2481
+ end
2482
+
2483
+ #
2484
+ # Write parts of the <c:dLbl> element for labels where only the formatting has
2485
+ # changed.
2486
+ #
2487
+ def write_custom_label_format_only(label)
2488
+ font = label[:font]
2489
+ has_formatting = has_fill_formatting(label)
2490
+
2491
+ if has_formatting
2492
+ # Write the c:spPr element.
2493
+ write_sp_pr(label)
2494
+ write_tx_pr(font)
2495
+ elsif font
2496
+ @writer.empty_tag('c:spPr')
2497
+ write_tx_pr(font)
2498
+ end
2499
+ end
2500
+
2375
2501
  #
2376
2502
  # Write the <c:showLegendKey> element.
2377
2503
  #
@@ -2700,7 +2826,7 @@ module Writexlsx
2700
2826
 
2701
2827
  # Write the a:srgbClr element.
2702
2828
  # TODO: Wait for a feature request to support transparency.
2703
- write_a_srgb_clr( color );
2829
+ write_a_srgb_clr( color )
2704
2830
  end
2705
2831
  end
2706
2832
  end
@@ -2802,9 +2928,5 @@ module Writexlsx
2802
2928
  @writer.empty_tag(tag)
2803
2929
  end
2804
2930
  end
2805
-
2806
- def nil_or_max?(val) # :nodoc:
2807
- val.nil? || val == 'max'
2808
- end
2809
2931
  end
2810
2932
  end