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
@@ -1,6 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'write_xlsx/utility/chart_formatting'
5
+
4
6
  module Writexlsx
5
7
  ###############################################################################
6
8
  #
@@ -12,7 +14,7 @@ module Writexlsx
12
14
  # Converted to ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
13
15
  #
14
16
  class Shape
15
- include Writexlsx::Utility
17
+ include Writexlsx::Utility::ChartFormatting
16
18
 
17
19
  attr_reader :edit_as, :drawing
18
20
  attr_reader :tx_box, :fill, :line, :format
@@ -27,106 +29,11 @@ module Writexlsx
27
29
 
28
30
  def initialize(properties = {})
29
31
  @writer = Package::XMLWriterSimple.new
30
- @name = nil
31
- @type = 'rect'
32
-
33
- # Is a Connector shape. 1/0 Value is a hash lookup from type.
34
- @connect = 0
35
-
36
- # Is a Drawing. Always 0, since a single shape never fills an entire sheet.
37
- @drawing = 0
38
-
39
- # OneCell or Absolute: options to move and/or size with cells.
40
- @edit_as = nil
41
-
42
- # Auto-incremented, unless supplied by user.
43
- @id = 0
44
-
45
- # Shape text (usually centered on shape geometry).
46
- @text = 0
47
-
48
- # Shape stencil mode. A copy (child) is created when inserted.
49
- # The link to parent is broken.
50
- @stencil = 1
51
-
52
- # Index to _shapes array when inserted.
53
- @element = -1
54
-
55
- # Shape ID of starting connection, if any.
56
- @start = nil
57
-
58
- # Shape vertex, starts at 0, numbered clockwise from 12 o'clock.
59
- @start_index = nil
60
-
61
- @end = nil
62
- @end_index = nil
63
-
64
- # Number and size of adjustments for shapes (usually connectors).
65
- @adjustments = []
66
-
67
- # Start and end sides. t)op, b)ottom, l)eft, or r)ight.
68
- @start_side = ''
69
- @end_side = ''
70
-
71
- # Flip shape Horizontally. eg. arrow left to arrow right.
72
- @flip_h = 0
73
32
 
74
- # Flip shape Vertically. eg. up arrow to down arrow.
75
- @flip_v = 0
76
-
77
- # shape rotation (in degrees 0-360).
78
- @rotation = 0
79
-
80
- # An alternate way to create a text box, because Excel allows it.
81
- # It is just a rectangle with text.
82
- @tx_box = false
83
-
84
- # Shape outline colour, or 0 for noFill (default black).
85
- @line = '000000'
86
-
87
- # Line type: dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot.
88
- @line_type = ''
89
-
90
- # Line weight (integer).
91
- @line_weight = 1
92
-
93
- # Shape fill colour, or 0 for noFill (default noFill).
94
- @fill = 0
95
-
96
- # Formatting for shape text, if any.
97
- @format = {}
98
-
99
- # copy of colour palette table from Workbook.pm.
100
- @palette = []
101
-
102
- # Vertical alignment: t, ctr, b.
103
- @valign = 'ctr'
104
-
105
- # Alignment: l, ctr, r, just
106
- @align = 'ctr'
107
-
108
- @x_offset = 0
109
- @y_offset = 0
110
-
111
- # Scale factors, which also may be set when the shape is inserted.
112
- @scale_x = 1
113
- @scale_y = 1
114
-
115
- # Default size, which can be modified and/or scaled.
116
- @width = 50
117
- @height = 50
118
-
119
- # Initial assignment. May be modified when prepared.
120
- @column_start = 0
121
- @row_start = 0
122
- @x1 = 0
123
- @y1 = 0
124
- @column_end = 0
125
- @row_end = 0
126
- @x2 = 0
127
- @y2 = 0
128
- @x_abs = 0
129
- @y_abs = 0
33
+ init_basic_attributes
34
+ init_connection_attributes
35
+ init_appearance_attributes
36
+ init_position_attributes
130
37
 
131
38
  set_properties(properties)
132
39
  end
@@ -298,5 +205,95 @@ module Writexlsx
298
205
  @width_emu, @height_emu
299
206
  ]
300
207
  end
208
+
209
+ private
210
+
211
+ def init_basic_attributes
212
+ @name = nil
213
+ @type = 'rect'
214
+
215
+ # Is a Connector shape. 1/0 Value is a hash lookup from type.
216
+ @connect = 0
217
+ # Is a Drawing. Always 0, since a single shape never fills an entire sheet.
218
+ @drawing = 0
219
+ # OneCell or Absolute: options to move and/or size with cells.
220
+ @edit_as = nil
221
+ # Auto-incremented, unless supplied by user.
222
+ @id = 0
223
+ # Shape text (usually centered on shape geometry).
224
+ @text = 0
225
+ # Shape stencil mode. A copy (child) is created when inserted.
226
+ # The link to parent is broken.
227
+ @stencil = 1
228
+ # Index to _shapes array when inserted.
229
+ @element = -1
230
+ # An alternate way to create a text box, because Excel allows it.
231
+ # It is just a rectangle with text.
232
+ @tx_box = false
233
+ # copy of colour palette table from Workbook.pm.
234
+ @palette = []
235
+ end
236
+
237
+ def init_connection_attributes
238
+ # Shape ID of starting connection, if any.
239
+ @start = nil
240
+ # Shape vertex, starts at 0, numbered clockwise from 12 o'clock.
241
+ @start_index = nil
242
+ @end = nil
243
+ @end_index = nil
244
+ # Number and size of adjustments for shapes (usually connectors).
245
+ @adjustments = []
246
+ # Start and end sides. t)op, b)ottom, l)eft, or r)ight.
247
+ @start_side = ''
248
+ @end_side = ''
249
+ end
250
+
251
+ def init_appearance_attributes
252
+ # Flip shape Horizontally. eg. arrow left to arrow right.
253
+ @flip_h = 0
254
+ # Flip shape Vertically. eg. up arrow to down arrow.
255
+ @flip_v = 0
256
+ # shape rotation (in degrees 0-360).
257
+ @rotation = 0
258
+ # Shape outline colour, or 0 for noFill (default black).
259
+ @line = '000000'
260
+ # Line type: dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot.
261
+ @line_type = ''
262
+ # Line weight (integer).
263
+ @line_weight = 1
264
+ # Shape fill colour, or 0 for noFill (default noFill).
265
+ @fill = 0
266
+ # Formatting for shape text, if any.
267
+ @format = {}
268
+ # Vertical alignment: t, ctr, b.
269
+ @valign = 'ctr'
270
+ # Alignment: l, ctr, r, just
271
+ @align = 'ctr'
272
+ end
273
+
274
+ def init_position_attributes
275
+ @x_offset = 0
276
+ @y_offset = 0
277
+
278
+ # Scale factors, which also may be set when the shape is inserted.
279
+ @scale_x = 1
280
+ @scale_y = 1
281
+
282
+ # Default size, which can be modified and/or scaled.
283
+ @width = 50
284
+ @height = 50
285
+
286
+ # Initial assignment. May be modified when prepared.
287
+ @column_start = 0
288
+ @row_start = 0
289
+ @x1 = 0
290
+ @y1 = 0
291
+ @column_end = 0
292
+ @row_end = 0
293
+ @x2 = 0
294
+ @y2 = 0
295
+ @x_abs = 0
296
+ @y_abs = 0
297
+ end
301
298
  end
302
299
  end
@@ -2,11 +2,16 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'delegate'
5
+ require 'write_xlsx/constants'
6
+ require 'write_xlsx/utility/common'
7
+ require 'write_xlsx/utility/xml_primitives'
5
8
  require 'write_xlsx/package/xml_writer_simple'
6
9
 
7
10
  module Writexlsx
8
11
  class Sheets < DelegateClass(Array)
9
- include Writexlsx::Utility
12
+ include Constants
13
+ include Writexlsx::Utility::Common
14
+ include Writexlsx::Utility::XmlPrimitives
10
15
 
11
16
  BASE_NAME = { sheet: 'Sheet', chart: 'Chart' } # :nodoc:
12
17
 
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'write_xlsx/utility'
4
+ require 'write_xlsx/utility/common'
5
5
 
6
6
  module Writexlsx
7
7
  ###############################################################################
@@ -14,7 +14,7 @@ module Writexlsx
14
14
  # Converted to ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
15
15
  #
16
16
  class Sparkline
17
- include Writexlsx::Utility
17
+ include Writexlsx::Utility::Common
18
18
 
19
19
  def initialize(ws, param, sheetname)
20
20
  @color = {}
@@ -0,0 +1,124 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'write_xlsx/col_name'
5
+ require 'write_xlsx/constants'
6
+
7
+ module Writexlsx
8
+ module Utility
9
+ module CellReference
10
+ include Constants
11
+
12
+ #
13
+ # xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
14
+ #
15
+ def xl_rowcol_to_cell(row_or_name, col, row_absolute = false, col_absolute = false)
16
+ if row_or_name.is_a?(Integer)
17
+ row_or_name += 1 # Change from 0-indexed to 1 indexed.
18
+ end
19
+ col_str = xl_col_to_name(col, col_absolute)
20
+ "#{col_str}#{absolute_char(row_absolute)}#{row_or_name}"
21
+ end
22
+
23
+ #
24
+ # Returns: [row, col, row_absolute, col_absolute]
25
+ #
26
+ # The row_absolute and col_absolute parameters aren't documented because they
27
+ # mainly used internally and aren't very useful to the user.
28
+ #
29
+ def xl_cell_to_rowcol(cell)
30
+ cell =~ /(\$?)([A-Z]{1,3})(\$?)(\d+)/
31
+
32
+ col_abs = ::Regexp.last_match(1) != ""
33
+ col = ::Regexp.last_match(2)
34
+ row_abs = ::Regexp.last_match(3) != ""
35
+ row = ::Regexp.last_match(4).to_i
36
+
37
+ # Convert base26 column string to number
38
+ # All your Base are belong to us.
39
+ chars = col.chars
40
+ expn = 0
41
+ col = 0
42
+
43
+ chars.reverse.each do |char|
44
+ col += (char.ord - 'A'.ord + 1) * (26**expn)
45
+ expn += 1
46
+ end
47
+
48
+ # Convert 1-index to zero-index
49
+ row -= 1
50
+ col -= 1
51
+
52
+ [row, col, row_abs, col_abs]
53
+ end
54
+
55
+ def xl_col_to_name(col, col_absolute)
56
+ col_str = ColName.instance.col_str(col)
57
+ if col_absolute
58
+ "#{absolute_char(col_absolute)}#{col_str}"
59
+ else
60
+ # Do not allocate new string
61
+ col_str
62
+ end
63
+ end
64
+
65
+ def xl_range(row_1, row_2, col_1, col_2,
66
+ row_abs_1 = false, row_abs_2 = false, col_abs_1 = false, col_abs_2 = false)
67
+ range1 = xl_rowcol_to_cell(row_1, col_1, row_abs_1, col_abs_1)
68
+ range2 = xl_rowcol_to_cell(row_2, col_2, row_abs_2, col_abs_2)
69
+
70
+ if range1 == range2
71
+ range1
72
+ else
73
+ "#{range1}:#{range2}"
74
+ end
75
+ end
76
+
77
+ def xl_range_formula(sheetname, row_1, row_2, col_1, col_2)
78
+ # Use Excel's conventions and quote the sheet name if it contains any
79
+ # non-word character or if it isn't already quoted.
80
+ sheetname = quote_sheetname(sheetname)
81
+
82
+ range1 = xl_rowcol_to_cell(row_1, col_1, 1, 1)
83
+ range2 = xl_rowcol_to_cell(row_2, col_2, 1, 1)
84
+
85
+ "=#{sheetname}!#{range1}:#{range2}"
86
+ end
87
+
88
+ # Check for a cell reference in A1 notation and substitute row and column
89
+ def row_col_notation(row_or_a1) # :nodoc:
90
+ substitute_cellref(row_or_a1) if row_or_a1.respond_to?(:match) && row_or_a1.to_s =~ /^\D/
91
+ end
92
+
93
+ #
94
+ # Substitute an Excel cell reference in A1 notation for zero based row and
95
+ # column values in an argument list.
96
+ #
97
+ # Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
98
+ #
99
+ def substitute_cellref(cell, *args) # :nodoc:
100
+ normalized_cell = cell.upcase
101
+
102
+ case normalized_cell
103
+ # Convert a column range: 'A:A' or 'B:G'.
104
+ # A range such as A:A is equivalent to A1:65536, so add rows as required
105
+ when /\$?([A-Z]{1,3}):\$?([A-Z]{1,3})/
106
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1) + '1')
107
+ row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2) + ROW_MAX.to_s)
108
+ [row1, col1, row2, col2, *args]
109
+ # Convert a cell range: 'A1:B7'
110
+ when /\$?([A-Z]{1,3}\$?\d+):\$?([A-Z]{1,3}\$?\d+)/
111
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
112
+ row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2))
113
+ [row1, col1, row2, col2, *args]
114
+ # Convert a cell reference: 'A1' or 'AD2000'
115
+ when /\$?([A-Z]{1,3}\$?\d+)/
116
+ row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
117
+ [row1, col1, *args]
118
+ else
119
+ raise("Unknown cell reference #{normalized_cell}")
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,262 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ module Writexlsx
5
+ module Utility
6
+ module ChartFormatting
7
+ PATTERN_TYPES = {
8
+ 'percent_5' => 'pct5',
9
+ 'percent_10' => 'pct10',
10
+ 'percent_20' => 'pct20',
11
+ 'percent_25' => 'pct25',
12
+ 'percent_30' => 'pct30',
13
+ 'percent_40' => 'pct40',
14
+
15
+ 'percent_50' => 'pct50',
16
+ 'percent_60' => 'pct60',
17
+ 'percent_70' => 'pct70',
18
+ 'percent_75' => 'pct75',
19
+ 'percent_80' => 'pct80',
20
+ 'percent_90' => 'pct90',
21
+
22
+ 'light_downward_diagonal' => 'ltDnDiag',
23
+ 'light_upward_diagonal' => 'ltUpDiag',
24
+ 'dark_downward_diagonal' => 'dkDnDiag',
25
+ 'dark_upward_diagonal' => 'dkUpDiag',
26
+ 'wide_downward_diagonal' => 'wdDnDiag',
27
+ 'wide_upward_diagonal' => 'wdUpDiag',
28
+
29
+ 'light_vertical' => 'ltVert',
30
+ 'light_horizontal' => 'ltHorz',
31
+ 'narrow_vertical' => 'narVert',
32
+ 'narrow_horizontal' => 'narHorz',
33
+ 'dark_vertical' => 'dkVert',
34
+ 'dark_horizontal' => 'dkHorz',
35
+
36
+ 'dashed_downward_diagonal' => 'dashDnDiag',
37
+ 'dashed_upward_diagonal' => 'dashUpDiag',
38
+ 'dashed_horizontal' => 'dashHorz',
39
+ 'dashed_vertical' => 'dashVert',
40
+ 'small_confetti' => 'smConfetti',
41
+ 'large_confetti' => 'lgConfetti',
42
+
43
+ 'zigzag' => 'zigZag',
44
+ 'wave' => 'wave',
45
+ 'diagonal_brick' => 'diagBrick',
46
+ 'horizontal_brick' => 'horzBrick',
47
+ 'weave' => 'weave',
48
+ 'plaid' => 'plaid',
49
+
50
+ 'divot' => 'divot',
51
+ 'dotted_grid' => 'dotGrid',
52
+ 'dotted_diamond' => 'dotDmnd',
53
+ 'shingle' => 'shingle',
54
+ 'trellis' => 'trellis',
55
+ 'sphere' => 'sphere',
56
+
57
+ 'small_grid' => 'smGrid',
58
+ 'large_grid' => 'lgGrid',
59
+ 'small_check' => 'smCheck',
60
+ 'large_check' => 'lgCheck',
61
+ 'outlined_diamond' => 'openDmnd',
62
+ 'solid_diamond' => 'solidDmnd'
63
+ }.freeze
64
+
65
+ #
66
+ # Convert user defined legend properties to the structure required internally.
67
+ #
68
+ def legend_properties(params)
69
+ legend = Writexlsx::Chart::Legend.new
70
+
71
+ legend.position = params[:position] || 'right'
72
+ legend.delete_series = params[:delete_series]
73
+ legend.font = convert_font_args(params[:font])
74
+
75
+ # Set the legend layout.
76
+ legend.layout = layout_properties(params[:layout])
77
+
78
+ # Turn off the legend.
79
+ legend.position = 'none' if params[:none]
80
+
81
+ # Set the line properties for the legend.
82
+ line = line_properties(params[:line])
83
+
84
+ # Allow 'border' as a synonym for 'line'.
85
+ line = line_properties(params[:border]) if params[:border]
86
+
87
+ # Set the fill properties for the legend.
88
+ fill = fill_properties(params[:fill])
89
+
90
+ # Set the pattern properties for the legend.
91
+ pattern = pattern_properties(params[:pattern])
92
+
93
+ # Set the gradient fill properties for the legend.
94
+ gradient = gradient_properties(params[:gradient])
95
+
96
+ # Pattern fill overrides solid fill.
97
+ fill = nil if pattern
98
+
99
+ # Gradient fill overrides solid and pattern fills.
100
+ if gradient
101
+ pattern = nil
102
+ fill = nil
103
+ end
104
+
105
+ # Set the legend layout.
106
+ layout = layout_properties(params[:layout])
107
+
108
+ legend.line = line
109
+ legend.fill = fill
110
+ legend.pattern = pattern
111
+ legend.gradient = gradient
112
+ legend.layout = layout
113
+
114
+ @legend = legend
115
+ end
116
+
117
+ #
118
+ # Convert user defined layout properties to the format required internally.
119
+ #
120
+ def layout_properties(args, is_text = false)
121
+ return unless ptrue?(args)
122
+
123
+ properties = is_text ? %i[x y] : %i[x y width height]
124
+
125
+ # Check for valid properties.
126
+ args.each_key do |key|
127
+ raise "Property '#{key}' not allowed in layout options\n" unless properties.include?(key.to_sym)
128
+ end
129
+
130
+ # Set the layout properties
131
+ layout = {}
132
+ properties.each do |property|
133
+ value = args[property]
134
+ # Convert to the format used by Excel for easier testing.
135
+ layout[property] = sprintf("%.17g", value)
136
+ end
137
+
138
+ layout
139
+ end
140
+
141
+ #
142
+ # Convert user defined line properties to the structure required internally.
143
+ #
144
+ def line_properties(line) # :nodoc:
145
+ line_fill_properties(line) do
146
+ value_or_raise(dash_types, line[:dash_type], 'dash type')
147
+ end
148
+ end
149
+
150
+ #
151
+ # Convert user defined fill properties to the structure required internally.
152
+ #
153
+ def fill_properties(fill) # :nodoc:
154
+ line_fill_properties(fill)
155
+ end
156
+
157
+ #
158
+ # Convert user defined pattern properties to the structure required internally.
159
+ #
160
+ def pattern_properties(args) # :nodoc:
161
+ return nil unless args
162
+ # Check the pattern type is present.
163
+ return nil unless args.has_key?(:pattern)
164
+ # Check the foreground color is present.
165
+ return nil unless args.has_key?(:fg_color)
166
+
167
+ pattern = {}
168
+
169
+ type = PATTERN_TYPES[args[:pattern]]
170
+ raise "Unknown pattern type '#{args[:pattern]}'" unless type
171
+
172
+ pattern[:pattern] = type
173
+ pattern[:bg_color] = args[:bg_color] || '#FFFFFF'
174
+ pattern[:fg_color] = args[:fg_color]
175
+
176
+ pattern
177
+ end
178
+
179
+ def line_fill_properties(params)
180
+ return { _defined: 0 } unless params
181
+
182
+ ret = params.dup
183
+ ret[:dash_type] = yield if block_given? && ret[:dash_type]
184
+ ret[:_defined] = 1
185
+ ret
186
+ end
187
+
188
+ def dash_types
189
+ {
190
+ solid: 'solid',
191
+ round_dot: 'sysDot',
192
+ square_dot: 'sysDash',
193
+ dash: 'dash',
194
+ dash_dot: 'dashDot',
195
+ long_dash: 'lgDash',
196
+ long_dash_dot: 'lgDashDot',
197
+ long_dash_dot_dot: 'lgDashDotDot',
198
+ dot: 'dot',
199
+ system_dash_dot: 'sysDashDot',
200
+ system_dash_dot_dot: 'sysDashDotDot'
201
+ }
202
+ end
203
+
204
+ def value_or_raise(hash, key, msg)
205
+ raise "Unknown #{msg} '#{key}'" if hash[key.to_sym].nil?
206
+
207
+ hash[key.to_sym]
208
+ end
209
+
210
+ def palette_color_from_index(index)
211
+ # Adjust the colour index.
212
+ idx = index - 8
213
+
214
+ r, g, b = @palette[idx]
215
+ sprintf("%02X%02X%02X", r, g, b)
216
+ end
217
+
218
+ #
219
+ # Convert the user specified colour index or string to a rgb colour.
220
+ #
221
+ def color(color_code) # :nodoc:
222
+ if color_code && color_code =~ /^#[0-9a-fA-F]{6}$/
223
+ # Convert a HTML style #RRGGBB color.
224
+ color_code.sub(/^#/, '').upcase
225
+ else
226
+ index = Format.color(color_code)
227
+ raise "Unknown color '#{color_code}' used in chart formatting." unless index
228
+
229
+ palette_color_from_index(index)
230
+ end
231
+ end
232
+
233
+ #
234
+ # Write the <a:solidFill> element.
235
+ #
236
+ def write_a_solid_fill(fill) # :nodoc:
237
+ @writer.tag_elements('a:solidFill') do
238
+ if fill[:color]
239
+ # Write the a:srgbClr element.
240
+ write_a_srgb_clr(color(fill[:color]), fill[:transparency])
241
+ end
242
+ end
243
+ end
244
+
245
+ #
246
+ # Write the <a:srgbClr> element.
247
+ #
248
+ def write_a_srgb_clr(color, transparency = nil) # :nodoc:
249
+ tag = 'a:srgbClr'
250
+ attributes = [['val', color]]
251
+
252
+ if ptrue?(transparency)
253
+ @writer.tag_elements(tag, attributes) do
254
+ write_a_alpha(transparency)
255
+ end
256
+ else
257
+ @writer.empty_tag(tag, attributes)
258
+ end
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ module Writexlsx
5
+ module Utility
6
+ module Common
7
+ PERL_TRUE_VALUES = [false, nil, 0, "0", "", [], {}].freeze
8
+
9
+ #
10
+ # return perl's boolean result
11
+ #
12
+ def ptrue?(value)
13
+ !PERL_TRUE_VALUES.include?(value)
14
+ end
15
+
16
+ def check_parameter(params, valid_keys, method)
17
+ invalids = params.keys - valid_keys
18
+ unless invalids.empty?
19
+ raise WriteXLSXOptionParameterError,
20
+ "Unknown parameter '#{invalids.join(", ")}' in #{method}."
21
+ end
22
+ true
23
+ end
24
+
25
+ def absolute_char(absolute)
26
+ absolute ? '$' : ''
27
+ end
28
+
29
+ def float_to_str(float)
30
+ return '' unless float
31
+
32
+ if float == float.to_i
33
+ float.to_i.to_s
34
+ else
35
+ float.to_s
36
+ end
37
+ end
38
+
39
+ def put_deprecate_message(method)
40
+ warn("Warning: calling deprecated method #{method}. This method will be removed in a future release.")
41
+ end
42
+ end
43
+ end
44
+ end