write_xlsx 1.13.0 → 1.15.0

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +15 -0
  3. data/Changes +20 -0
  4. data/lib/write_xlsx/chart/area.rb +2 -2
  5. data/lib/write_xlsx/chart/axis.rb +55 -32
  6. data/lib/write_xlsx/chart/axis_writer.rb +528 -0
  7. data/lib/write_xlsx/chart/bar.rb +2 -2
  8. data/lib/write_xlsx/chart/caption.rb +16 -9
  9. data/lib/write_xlsx/chart/chart_area.rb +121 -0
  10. data/lib/write_xlsx/chart/column.rb +2 -2
  11. data/lib/write_xlsx/chart/d_pt_point_writer.rb +14 -0
  12. data/lib/write_xlsx/chart/doughnut.rb +0 -3
  13. data/lib/write_xlsx/chart/formatting_writer.rb +652 -0
  14. data/lib/write_xlsx/chart/initialization.rb +100 -0
  15. data/lib/write_xlsx/chart/line.rb +4 -3
  16. data/lib/write_xlsx/chart/pie.rb +6 -2
  17. data/lib/write_xlsx/chart/radar.rb +2 -2
  18. data/lib/write_xlsx/chart/scatter.rb +4 -3
  19. data/lib/write_xlsx/chart/series.rb +35 -15
  20. data/lib/write_xlsx/chart/series_data.rb +132 -0
  21. data/lib/write_xlsx/chart/series_writer.rb +318 -0
  22. data/lib/write_xlsx/chart/settings.rb +226 -0
  23. data/lib/write_xlsx/chart/stock.rb +2 -2
  24. data/lib/write_xlsx/chart/table.rb +50 -0
  25. data/lib/write_xlsx/chart/xml_writer.rb +305 -0
  26. data/lib/write_xlsx/chart.rb +286 -2477
  27. data/lib/write_xlsx/chartsheet.rb +31 -82
  28. data/lib/write_xlsx/constants.rb +11 -0
  29. data/lib/write_xlsx/drawing.rb +5 -3
  30. data/lib/write_xlsx/format/alignment_state.rb +39 -0
  31. data/lib/write_xlsx/format/alignment_style.rb +92 -0
  32. data/lib/write_xlsx/format/border_state.rb +47 -0
  33. data/lib/write_xlsx/format/border_style.rb +116 -0
  34. data/lib/write_xlsx/format/fill_state.rb +26 -0
  35. data/lib/write_xlsx/format/fill_style.rb +52 -0
  36. data/lib/write_xlsx/format/font_state.rb +74 -0
  37. data/lib/write_xlsx/format/font_style.rb +172 -0
  38. data/lib/write_xlsx/format/format_state.rb +65 -0
  39. data/lib/write_xlsx/format/number_format_state.rb +20 -0
  40. data/lib/write_xlsx/format/number_format_style.rb +28 -0
  41. data/lib/write_xlsx/format/protection_state.rb +20 -0
  42. data/lib/write_xlsx/format/protection_style.rb +28 -0
  43. data/lib/write_xlsx/format.rb +1093 -426
  44. data/lib/write_xlsx/formats.rb +0 -2
  45. data/lib/write_xlsx/image_property.rb +4 -1
  46. data/lib/write_xlsx/inserted_chart.rb +1 -1
  47. data/lib/write_xlsx/object_positioning.rb +15 -1
  48. data/lib/write_xlsx/package/app.rb +2 -2
  49. data/lib/write_xlsx/package/button.rb +6 -2
  50. data/lib/write_xlsx/package/comments.rb +11 -3
  51. data/lib/write_xlsx/package/conditional_format.rb +7 -3
  52. data/lib/write_xlsx/package/content_types.rb +2 -2
  53. data/lib/write_xlsx/package/core.rb +2 -2
  54. data/lib/write_xlsx/package/custom.rb +3 -2
  55. data/lib/write_xlsx/package/metadata.rb +2 -2
  56. data/lib/write_xlsx/package/packager.rb +0 -3
  57. data/lib/write_xlsx/package/relationships.rb +2 -2
  58. data/lib/write_xlsx/package/rich_value.rb +4 -2
  59. data/lib/write_xlsx/package/rich_value_rel.rb +2 -2
  60. data/lib/write_xlsx/package/rich_value_structure.rb +2 -2
  61. data/lib/write_xlsx/package/rich_value_types.rb +3 -3
  62. data/lib/write_xlsx/package/shared_strings.rb +2 -2
  63. data/lib/write_xlsx/package/styles.rb +13 -9
  64. data/lib/write_xlsx/package/table.rb +8 -2
  65. data/lib/write_xlsx/package/theme.rb +0 -3
  66. data/lib/write_xlsx/package/vml.rb +2 -2
  67. data/lib/write_xlsx/page_setup.rb +3 -1
  68. data/lib/write_xlsx/shape.rb +97 -100
  69. data/lib/write_xlsx/sheets.rb +6 -1
  70. data/lib/write_xlsx/sparkline.rb +2 -2
  71. data/lib/write_xlsx/utility/cell_reference.rb +124 -0
  72. data/lib/write_xlsx/utility/chart_formatting.rb +262 -0
  73. data/lib/write_xlsx/utility/common.rb +44 -0
  74. data/lib/write_xlsx/utility/date_time.rb +113 -0
  75. data/lib/write_xlsx/utility/dimensions.rb +40 -0
  76. data/lib/write_xlsx/utility/drawing.rb +136 -0
  77. data/lib/write_xlsx/utility/rich_text.rb +184 -0
  78. data/lib/write_xlsx/utility/sheetname_quoting.rb +73 -0
  79. data/lib/write_xlsx/utility/string_width.rb +45 -0
  80. data/lib/write_xlsx/utility/url.rb +27 -0
  81. data/lib/write_xlsx/utility/xml_primitives.rb +32 -0
  82. data/lib/write_xlsx/version.rb +1 -1
  83. data/lib/write_xlsx/workbook/chart_data.rb +188 -0
  84. data/lib/write_xlsx/workbook/format_preparation.rb +199 -0
  85. data/lib/write_xlsx/workbook/initialization.rb +223 -0
  86. data/lib/write_xlsx/workbook/package_preparation.rb +231 -0
  87. data/lib/write_xlsx/workbook/workbook_writer.rb +164 -0
  88. data/lib/write_xlsx/workbook.rb +143 -981
  89. data/lib/write_xlsx/worksheet/autofilter.rb +3 -1
  90. data/lib/write_xlsx/worksheet/cell_data.rb +5 -1
  91. data/lib/write_xlsx/worksheet/columns.rb +8 -3
  92. data/lib/write_xlsx/worksheet/data_validation.rb +9 -1
  93. data/lib/write_xlsx/worksheet/data_writing.rb +37 -10
  94. data/lib/write_xlsx/worksheet/formatting.rb +3 -1
  95. data/lib/write_xlsx/worksheet/hyperlink.rb +9 -1
  96. data/lib/write_xlsx/worksheet/row_col_sizing.rb +3 -1
  97. data/lib/write_xlsx/worksheet/xml_writer.rb +9 -4
  98. data/lib/write_xlsx/worksheet.rb +19 -2
  99. metadata +41 -2
  100. data/lib/write_xlsx/utility.rb +0 -1034
@@ -14,7 +14,7 @@
14
14
  #
15
15
 
16
16
  require 'write_xlsx/package/xml_writer_simple'
17
- require 'write_xlsx/utility'
17
+ require 'write_xlsx/utility/xml_primitives'
18
18
 
19
19
  module Writexlsx
20
20
  class Chart
@@ -28,7 +28,7 @@ module Writexlsx
28
28
  # chart = workbook.add_chart( :type => 'column', :subtype => 'stacked' )
29
29
  #
30
30
  class Column < self
31
- include Writexlsx::Utility
31
+ include Writexlsx::Utility::XmlPrimitives
32
32
 
33
33
  def initialize(subtype)
34
34
  super
@@ -0,0 +1,14 @@
1
+ module Writexlsx
2
+ class Chart
3
+ module DPtPointWriter
4
+ def write_d_pt_point(index, point)
5
+ @writer.tag_elements('c:dPt') do
6
+ write_idx(index)
7
+ @writer.tag_elements('c:marker') do
8
+ write_sp_pr(point)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -16,13 +16,10 @@
16
16
  require 'write_xlsx/package/xml_writer_simple'
17
17
  require 'write_xlsx/chart'
18
18
  require 'write_xlsx/chart/pie'
19
- require 'write_xlsx/utility'
20
19
 
21
20
  module Writexlsx
22
21
  class Chart
23
22
  class Doughnut < Pie
24
- include Writexlsx::Utility
25
-
26
23
  def initialize(subtype)
27
24
  super
28
25
  @vary_data_color = 1
@@ -0,0 +1,652 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ ###############################################################################
5
+ #
6
+ # formatting_writer.rb - formatting, rich text, and label XML helpers
7
+ #
8
+ ###############################################################################
9
+
10
+ module Writexlsx
11
+ class Chart
12
+ module FormattingWriter
13
+ private
14
+
15
+ def write_chart_title(title, is_y_axis = nil, allow_none: false)
16
+ return unless title
17
+
18
+ if allow_none && title.none
19
+ write_auto_title_deleted
20
+ elsif ptrue?(title.name)
21
+ write_title_rich(title, is_y_axis)
22
+ elsif title.formula
23
+ write_title_formula(title, is_y_axis)
24
+ elsif has_formatting(title)
25
+ write_title_format_only(title)
26
+ end
27
+ end
28
+
29
+ #
30
+ # Write the <c:title> element for a rich string.
31
+ #
32
+ def write_title_formula(title, is_y_axis = nil)
33
+ @writer.tag_elements('c:title') do
34
+ write_tx_formula(title.formula, title.data_id)
35
+ write_layout(title.layout, 'text')
36
+ write_overlay if title.overlay
37
+ write_sp_pr(title)
38
+ write_tx_pr(title.font, is_y_axis)
39
+ end
40
+ end
41
+
42
+ def write_title_format_only(title)
43
+ @writer.tag_elements('c:title') do
44
+ write_layout(title.layout, 'text')
45
+ write_overlay if title.overlay
46
+ write_sp_pr(title)
47
+ end
48
+ end
49
+
50
+ #
51
+ # Write the <c:tx> element.
52
+ #
53
+ def write_tx_rich(title, is_y_axis, font) # :nodoc:
54
+ @writer.tag_elements('c:tx') do
55
+ write_rich(title, font, is_y_axis)
56
+ end
57
+ end
58
+
59
+ #
60
+ # Write the <c:tx> element with a simple value such as for series names.
61
+ #
62
+ def write_tx_value(title) # :nodoc:
63
+ @writer.tag_elements('c:tx') { write_v(title) }
64
+ end
65
+
66
+ #
67
+ # Write the <c:tx> element.
68
+ #
69
+ def write_tx_formula(title, data_id) # :nodoc:
70
+ data = @formula_data[data_id] if data_id
71
+
72
+ @writer.tag_elements('c:tx') { write_str_ref(title, data, 'str') }
73
+ end
74
+
75
+ #
76
+ # Write the <c:rich> element.
77
+ #
78
+ def write_rich(title, font, is_y_axis, ignore_rich_pr = false) # :nodoc:
79
+ rotation = nil
80
+
81
+ rotation = font[:_rotation] if font && font[:_rotation]
82
+ @writer.tag_elements('c:rich') do
83
+ # Write the a:bodyPr element.
84
+ write_a_body_pr(rotation, is_y_axis)
85
+ # Write the a:lstStyle element.
86
+ write_a_lst_style
87
+ # Write the a:p element.
88
+ write_a_p_rich(title, font, ignore_rich_pr)
89
+ end
90
+ end
91
+
92
+ #
93
+ # Write the <a:p> element for rich string titles.
94
+ #
95
+ def write_a_p_rich(title, font, ignore_rich_pr) # :nodoc:
96
+ @writer.tag_elements('a:p') do
97
+ # Write the a:pPr element.
98
+ write_a_p_pr_rich(font) unless ignore_rich_pr
99
+ # Write the a:r element.
100
+ write_a_r(title, font)
101
+ end
102
+ end
103
+
104
+ #
105
+ # Write the <a:pPr> element for rich string titles.
106
+ #
107
+ def write_a_p_pr_rich(font) # :nodoc:
108
+ @writer.tag_elements('a:pPr') { write_a_def_rpr(font) }
109
+ end
110
+
111
+ #
112
+ # Write the <a:r> element.
113
+ #
114
+ def write_a_r(title, font) # :nodoc:
115
+ @writer.tag_elements('a:r') do
116
+ # Write the a:rPr element.
117
+ write_a_r_pr(font)
118
+ # Write the a:t element.
119
+ write_a_t(title.respond_to?(:name) ? title.name : title)
120
+ end
121
+ end
122
+
123
+ #
124
+ # Write the <a:rPr> element.
125
+ #
126
+ def write_a_r_pr(font) # :nodoc:
127
+ attributes = [%w[lang en-US]]
128
+ attr_font = get_font_style_attributes(font)
129
+ attributes += attr_font unless attr_font.empty?
130
+
131
+ write_def_rpr_r_pr_common(font, attributes, 'a:rPr')
132
+ end
133
+
134
+ #
135
+ # Write the <a:t> element.
136
+ #
137
+ def write_a_t(title) # :nodoc:
138
+ @writer.data_element('a:t', title)
139
+ end
140
+
141
+ #
142
+ # Write the <c:marker> element.
143
+ #
144
+ def write_marker(marker = nil) # :nodoc:
145
+ marker ||= @default_marker
146
+
147
+ return unless ptrue?(marker)
148
+ return if ptrue?(marker.automatic?)
149
+
150
+ @writer.tag_elements('c:marker') do
151
+ # Write the c:symbol element.
152
+ write_symbol(marker.type)
153
+ # Write the c:size element.
154
+ size = marker.size
155
+ write_marker_size(size) if ptrue?(size)
156
+ # Write the c:spPr element.
157
+ write_sp_pr(marker)
158
+ end
159
+ end
160
+
161
+ #
162
+ # Write the <c:marker> element without a sub-element.
163
+ #
164
+ def write_marker_value # :nodoc:
165
+ return unless @default_marker
166
+
167
+ @writer.empty_tag('c:marker', [['val', 1]])
168
+ end
169
+
170
+ #
171
+ # Write the <c:size> element.
172
+ #
173
+ def write_marker_size(val) # :nodoc:
174
+ @writer.empty_tag('c:size', [['val', val]])
175
+ end
176
+
177
+ #
178
+ # Write the <c:symbol> element.
179
+ #
180
+ def write_symbol(val) # :nodoc:
181
+ @writer.empty_tag('c:symbol', [['val', val]])
182
+ end
183
+
184
+ #
185
+ # Write the <c:spPr> element.
186
+ #
187
+ def write_sp_pr(object) # :nodoc:
188
+ return unless has_formatting(object)
189
+
190
+ line = series_property(object, :line)
191
+ fill = series_property(object, :fill)
192
+ pattern = series_property(object, :pattern)
193
+ gradient = series_property(object, :gradient)
194
+
195
+ @writer.tag_elements('c:spPr') do
196
+ # Write the fill elements for solid charts such as pie/doughnut and bar.
197
+ if fill && fill[:_defined] != 0
198
+ if ptrue?(fill[:none])
199
+ # Write the a:noFill element.
200
+ write_a_no_fill
201
+ else
202
+ # Write the a:solidFill element.
203
+ write_a_solid_fill(fill)
204
+ end
205
+ end
206
+
207
+ write_a_patt_fill(pattern) if ptrue?(pattern)
208
+ write_a_grad_fill(gradient) if ptrue?(gradient)
209
+ write_a_ln(line) if line && ptrue?(line[:_defined])
210
+ end
211
+ end
212
+
213
+ def series_property(object, property)
214
+ if object.respond_to?(property)
215
+ object.send(property)
216
+ elsif object.respond_to?(:[])
217
+ object[property]
218
+ end
219
+ end
220
+
221
+ #
222
+ # Write the <a:ln> element.
223
+ #
224
+ def write_a_ln(line) # :nodoc:
225
+ attributes = []
226
+
227
+ # Add the line width as an attribute.
228
+ if line[:width]
229
+ width = line[:width]
230
+ # Round width to nearest 0.25, like Excel.
231
+ width = ((width + 0.125) * 4).to_i / 4.0
232
+
233
+ # Convert to internal units.
234
+ width = (0.5 + (12700 * width)).to_i
235
+
236
+ attributes << ['w', width]
237
+ end
238
+
239
+ if ptrue?(line[:none]) || ptrue?(line[:color]) || line[:dash_type]
240
+ @writer.tag_elements('a:ln', attributes) do
241
+ # Write the line fill.
242
+ if ptrue?(line[:none])
243
+ # Write the a:noFill element.
244
+ write_a_no_fill
245
+ elsif ptrue?(line[:color])
246
+ # Write the a:solidFill element.
247
+ write_a_solid_fill(line)
248
+ end
249
+
250
+ # Write the line/dash type.
251
+ if line[:dash_type]
252
+ # Write the a:prstDash element.
253
+ write_a_prst_dash(line[:dash_type])
254
+ end
255
+ end
256
+ else
257
+ @writer.empty_tag('a:ln', attributes)
258
+ end
259
+ end
260
+
261
+ #
262
+ # Write the <a:noFill> element.
263
+ #
264
+ def write_a_no_fill # :nodoc:
265
+ @writer.empty_tag('a:noFill')
266
+ end
267
+
268
+ #
269
+ # Write the <a:alpha> element.
270
+ #
271
+ def write_a_alpha(val)
272
+ val = (100 - val.to_i) * 1000
273
+
274
+ @writer.empty_tag('a:alpha', [['val', val]])
275
+ end
276
+
277
+ #
278
+ # Write the <a:prstDash> element.
279
+ #
280
+ def write_a_prst_dash(val) # :nodoc:
281
+ @writer.empty_tag('a:prstDash', [['val', val]])
282
+ end
283
+
284
+ #
285
+ # Write the <a:gradFill> element.
286
+ #
287
+ def write_a_grad_fill(gradient)
288
+ attributes = [
289
+ %w[flip none],
290
+ ['rotWithShape', 1]
291
+ ]
292
+ attributes = [] if gradient[:type] == 'linear'
293
+
294
+ @writer.tag_elements('a:gradFill', attributes) do
295
+ # Write the a:gsLst element.
296
+ write_a_gs_lst(gradient)
297
+
298
+ if gradient[:type] == 'linear'
299
+ # Write the a:lin element.
300
+ write_a_lin(gradient[:angle])
301
+ else
302
+ # Write the a:path element.
303
+ write_a_path(gradient[:type])
304
+
305
+ # Write the a:tileRect element.
306
+ write_a_tile_rect(gradient[:type])
307
+ end
308
+ end
309
+ end
310
+
311
+ #
312
+ # Write the <a:gsLst> element.
313
+ #
314
+ def write_a_gs_lst(gradient)
315
+ positions = gradient[:positions]
316
+ colors = gradient[:colors]
317
+
318
+ @writer.tag_elements('a:gsLst') do
319
+ (0..(colors.size - 1)).each do |i|
320
+ pos = (positions[i] * 1000).to_i
321
+
322
+ attributes = [['pos', pos]]
323
+ @writer.tag_elements('a:gs', attributes) do
324
+ color = color(colors[i])
325
+
326
+ # Write the a:srgbClr element.
327
+ # TODO: Wait for a feature request to support transparency.
328
+ write_a_srgb_clr(color)
329
+ end
330
+ end
331
+ end
332
+ end
333
+
334
+ #
335
+ # Write the <a:lin> element.
336
+ #
337
+ def write_a_lin(angle)
338
+ scaled = 0
339
+
340
+ angle = (60000 * angle).to_i
341
+
342
+ attributes = [
343
+ ['ang', angle],
344
+ ['scaled', scaled]
345
+ ]
346
+
347
+ @writer.empty_tag('a:lin', attributes)
348
+ end
349
+
350
+ #
351
+ # Write the <a:path> element.
352
+ #
353
+ def write_a_path(type)
354
+ attributes = [['path', type]]
355
+
356
+ @writer.tag_elements('a:path', attributes) do
357
+ # Write the a:fillToRect element.
358
+ write_a_fill_to_rect(type)
359
+ end
360
+ end
361
+
362
+ #
363
+ # Write the <a:fillToRect> element.
364
+ #
365
+ def write_a_fill_to_rect(type)
366
+ attributes = if type == 'shape'
367
+ [
368
+ ['l', 50000],
369
+ ['t', 50000],
370
+ ['r', 50000],
371
+ ['b', 50000]
372
+ ]
373
+ else
374
+ [
375
+ ['l', 100000],
376
+ ['t', 100000]
377
+ ]
378
+ end
379
+
380
+ @writer.empty_tag('a:fillToRect', attributes)
381
+ end
382
+
383
+ #
384
+ # Write the <a:tileRect> element.
385
+ #
386
+ def write_a_tile_rect(type)
387
+ attributes = if type == 'shape'
388
+ []
389
+ else
390
+ [
391
+ ['r', -100000],
392
+ ['b', -100000]
393
+ ]
394
+ end
395
+
396
+ @writer.empty_tag('a:tileRect', attributes)
397
+ end
398
+
399
+ #
400
+ # Write the <a:pattFill> element.
401
+ #
402
+ def write_a_patt_fill(pattern)
403
+ attributes = [['prst', pattern[:pattern]]]
404
+
405
+ @writer.tag_elements('a:pattFill', attributes) do
406
+ write_a_fg_clr(pattern[:fg_color])
407
+ write_a_bg_clr(pattern[:bg_color])
408
+ end
409
+ end
410
+
411
+ def write_a_fg_clr(color)
412
+ @writer.tag_elements('a:fgClr') { write_a_srgb_clr(color(color)) }
413
+ end
414
+
415
+ def write_a_bg_clr(color)
416
+ @writer.tag_elements('a:bgClr') { write_a_srgb_clr(color(color)) }
417
+ end
418
+
419
+ #
420
+ # Write the <c:numberFormat> element for data labels.
421
+ #
422
+ def write_data_label_number_format(format_code)
423
+ source_linked = 0
424
+
425
+ attributes = [
426
+ ['formatCode', format_code],
427
+ ['sourceLinked', source_linked]
428
+ ]
429
+
430
+ @writer.empty_tag('c:numFmt', attributes)
431
+ end
432
+
433
+ #
434
+ # Write the <c:dLbls> element.
435
+ #
436
+ def write_d_lbls(labels) # :nodoc:
437
+ return unless labels
438
+
439
+ @writer.tag_elements('c:dLbls') do
440
+ # Write the custom c:dLbl elements.
441
+ write_custom_labels(labels, labels[:custom]) if labels[:custom]
442
+ # Write the c:numFmt element.
443
+ write_data_label_number_format(labels[:num_format]) if labels[:num_format]
444
+ # Write the c:spPr element.
445
+ write_sp_pr(labels)
446
+ # Write the data label font elements.
447
+ write_axis_font(labels[:font]) if labels[:font]
448
+ # Write the c:dLblPos element.
449
+ write_d_lbl_pos(labels[:position]) if ptrue?(labels[:position])
450
+ # Write the c:showLegendKey element.
451
+ write_show_legend_key if labels[:legend_key]
452
+ # Write the c:showVal element.
453
+ write_show_val if labels[:value]
454
+ # Write the c:showCatName element.
455
+ write_show_cat_name if labels[:category]
456
+ # Write the c:showSerName element.
457
+ write_show_ser_name if labels[:series_name]
458
+ # Write the c:showPercent element.
459
+ write_show_percent if labels[:percentage]
460
+ # Write the c:separator element.
461
+ write_separator(labels[:separator]) if labels[:separator]
462
+ # Write the c:showLeaderLines element.
463
+ write_show_leader_lines if labels[:leader_lines]
464
+ end
465
+ end
466
+
467
+ #
468
+ # Write the <c:dLbl> element.
469
+ #
470
+ def write_custom_labels(parent, labels)
471
+ index = 0
472
+
473
+ labels.each do |label|
474
+ index += 1
475
+ next unless ptrue?(label)
476
+
477
+ use_custom_formatting = true
478
+
479
+ @writer.tag_elements('c:dLbl') do
480
+ # Write the c:idx element.
481
+ write_idx(index - 1)
482
+
483
+ if label[:delete]
484
+ # Delete/hide label.
485
+ write_delete(1)
486
+ elsif label[:formula] || label[:value] || label[:position]
487
+ # Write the c:layout element.
488
+ write_layout
489
+
490
+ if label[:formula]
491
+ write_custom_label_formula(label)
492
+ elsif label[:value]
493
+ write_custom_label_str(label)
494
+
495
+ # String values use spPr formatting.
496
+ use_custom_formatting = false
497
+ end
498
+
499
+ write_custom_label_format(label) if use_custom_formatting
500
+
501
+ position = label[:position] || parent[:position]
502
+ write_d_lbl_pos(position) if position
503
+
504
+ write_show_val if parent[:value]
505
+ write_show_cat_name if parent[:category]
506
+ write_show_ser_name if parent[:series_name]
507
+ else
508
+ write_custom_label_format(label)
509
+ end
510
+ end
511
+ end
512
+ end
513
+
514
+ #
515
+ # Write parts of the <c:dLbl> element for strings.
516
+ #
517
+ def write_custom_label_str(label)
518
+ value = label[:value]
519
+ font = label[:font]
520
+ is_y_axis = 0
521
+ has_formatting = has_formatting(label)
522
+
523
+ @writer.tag_elements('c:tx') do
524
+ # Write the c:rich element.
525
+ write_rich(value, font, is_y_axis, !has_formatting)
526
+ end
527
+
528
+ # Write the c:cpPr element.
529
+ write_sp_pr(label)
530
+ end
531
+
532
+ #
533
+ # Write parts of the <c:dLbl> element for formulas.
534
+ #
535
+ def write_custom_label_formula(label)
536
+ formula = label[:formula]
537
+ data_id = label[:data_id]
538
+
539
+ data = @formula_data[data_id] if data_id
540
+
541
+ @writer.tag_elements('c:tx') do
542
+ # Write the c:strRef element.
543
+ write_str_ref(formula, data, 'str')
544
+ end
545
+ end
546
+
547
+ #
548
+ # Write the formatting and font elements for custom labels.
549
+ #
550
+ def write_custom_label_format(label)
551
+ font = label[:font]
552
+ has_formatting = has_formatting(label)
553
+
554
+ if has_formatting
555
+ # Write the c:spPr element.
556
+ write_sp_pr(label)
557
+ write_tx_pr(font)
558
+ elsif font
559
+ @writer.empty_tag('c:spPr')
560
+ write_tx_pr(font)
561
+ end
562
+ end
563
+
564
+ #
565
+ # Write the <c:showLegendKey> element.
566
+ #
567
+ def write_show_legend_key
568
+ @writer.empty_tag('c:showLegendKey', [['val', 1]])
569
+ end
570
+
571
+ #
572
+ # Write the <c:showVal> element.
573
+ #
574
+ def write_show_val # :nodoc:
575
+ @writer.empty_tag('c:showVal', [['val', 1]])
576
+ end
577
+
578
+ #
579
+ # Write the <c:showCatName> element.
580
+ #
581
+ def write_show_cat_name # :nodoc:
582
+ @writer.empty_tag('c:showCatName', [['val', 1]])
583
+ end
584
+
585
+ #
586
+ # Write the <c:showSerName> element.
587
+ #
588
+ def write_show_ser_name # :nodoc:
589
+ @writer.empty_tag('c:showSerName', [['val', 1]])
590
+ end
591
+
592
+ #
593
+ # Write the <c:showPercent> element.
594
+ #
595
+ def write_show_percent
596
+ @writer.empty_tag('c:showPercent', [['val', 1]])
597
+ end
598
+
599
+ #
600
+ # Write the <c:separator> element.
601
+ #
602
+ def write_separator(data)
603
+ @writer.data_element('c:separator', data)
604
+ end
605
+
606
+ # Write the <c:showLeaderLines> element. This is different for Pie/Doughnut
607
+ # charts. Other chart types only supported leader lines after Excel 2015 via
608
+ # an extension element.
609
+ def write_show_leader_lines
610
+ uri = '{CE6537A1-D6FC-4f65-9D91-7224C49458BB}'
611
+ xmlns_c_15 = 'http://schemas.microsoft.com/office/drawing/2012/chart'
612
+
613
+ attributes1 = [
614
+ ['uri', uri],
615
+ ['xmlns:c15', xmlns_c_15]
616
+ ]
617
+
618
+ attributes2 = [['val', 1]]
619
+
620
+ @writer.tag_elements('c:extLst') do
621
+ @writer.tag_elements('c:ext', attributes1) do
622
+ @writer.empty_tag('c15:showLeaderLines', attributes2)
623
+ end
624
+ end
625
+ end
626
+
627
+ #
628
+ # Write the <c:dLblPos> element.
629
+ #
630
+ def write_d_lbl_pos(val)
631
+ @writer.empty_tag('c:dLblPos', [['val', val]])
632
+ end
633
+
634
+ def has_formatting(element)
635
+ line = series_property(element, :line)
636
+ fill = series_property(element, :fill)
637
+ pattern = series_property(element, :pattern)
638
+ gradient = series_property(element, :gradient)
639
+
640
+ (line && ptrue?(line[:_defined])) ||
641
+ (fill && ptrue?(fill[:_defined])) || pattern || gradient
642
+ end
643
+
644
+ #
645
+ # Write the <a:latin> element.
646
+ #
647
+ def write_a_latin(args) # :nodoc:
648
+ @writer.empty_tag('a:latin', args)
649
+ end
650
+ end
651
+ end
652
+ end