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.
- checksums.yaml +4 -4
- data/.rubocop.yml +15 -0
- data/Changes +20 -0
- data/lib/write_xlsx/chart/area.rb +2 -2
- data/lib/write_xlsx/chart/axis.rb +55 -32
- data/lib/write_xlsx/chart/axis_writer.rb +528 -0
- data/lib/write_xlsx/chart/bar.rb +2 -2
- data/lib/write_xlsx/chart/caption.rb +16 -9
- data/lib/write_xlsx/chart/chart_area.rb +121 -0
- data/lib/write_xlsx/chart/column.rb +2 -2
- data/lib/write_xlsx/chart/d_pt_point_writer.rb +14 -0
- data/lib/write_xlsx/chart/doughnut.rb +0 -3
- data/lib/write_xlsx/chart/formatting_writer.rb +652 -0
- data/lib/write_xlsx/chart/initialization.rb +100 -0
- data/lib/write_xlsx/chart/line.rb +4 -3
- data/lib/write_xlsx/chart/pie.rb +6 -2
- data/lib/write_xlsx/chart/radar.rb +2 -2
- data/lib/write_xlsx/chart/scatter.rb +4 -3
- data/lib/write_xlsx/chart/series.rb +35 -15
- data/lib/write_xlsx/chart/series_data.rb +132 -0
- data/lib/write_xlsx/chart/series_writer.rb +318 -0
- data/lib/write_xlsx/chart/settings.rb +226 -0
- data/lib/write_xlsx/chart/stock.rb +2 -2
- data/lib/write_xlsx/chart/table.rb +50 -0
- data/lib/write_xlsx/chart/xml_writer.rb +305 -0
- data/lib/write_xlsx/chart.rb +286 -2477
- data/lib/write_xlsx/chartsheet.rb +31 -82
- data/lib/write_xlsx/constants.rb +11 -0
- data/lib/write_xlsx/drawing.rb +5 -3
- data/lib/write_xlsx/format/alignment_state.rb +39 -0
- data/lib/write_xlsx/format/alignment_style.rb +92 -0
- data/lib/write_xlsx/format/border_state.rb +47 -0
- data/lib/write_xlsx/format/border_style.rb +116 -0
- data/lib/write_xlsx/format/fill_state.rb +26 -0
- data/lib/write_xlsx/format/fill_style.rb +52 -0
- data/lib/write_xlsx/format/font_state.rb +74 -0
- data/lib/write_xlsx/format/font_style.rb +172 -0
- data/lib/write_xlsx/format/format_state.rb +65 -0
- data/lib/write_xlsx/format/number_format_state.rb +20 -0
- data/lib/write_xlsx/format/number_format_style.rb +28 -0
- data/lib/write_xlsx/format/protection_state.rb +20 -0
- data/lib/write_xlsx/format/protection_style.rb +28 -0
- data/lib/write_xlsx/format.rb +1093 -426
- data/lib/write_xlsx/formats.rb +0 -2
- data/lib/write_xlsx/image_property.rb +4 -1
- data/lib/write_xlsx/inserted_chart.rb +1 -1
- data/lib/write_xlsx/object_positioning.rb +15 -1
- data/lib/write_xlsx/package/app.rb +2 -2
- data/lib/write_xlsx/package/button.rb +6 -2
- data/lib/write_xlsx/package/comments.rb +11 -3
- data/lib/write_xlsx/package/conditional_format.rb +7 -3
- data/lib/write_xlsx/package/content_types.rb +2 -2
- data/lib/write_xlsx/package/core.rb +2 -2
- data/lib/write_xlsx/package/custom.rb +3 -2
- data/lib/write_xlsx/package/metadata.rb +2 -2
- data/lib/write_xlsx/package/packager.rb +0 -3
- data/lib/write_xlsx/package/relationships.rb +2 -2
- data/lib/write_xlsx/package/rich_value.rb +4 -2
- data/lib/write_xlsx/package/rich_value_rel.rb +2 -2
- data/lib/write_xlsx/package/rich_value_structure.rb +2 -2
- data/lib/write_xlsx/package/rich_value_types.rb +3 -3
- data/lib/write_xlsx/package/shared_strings.rb +2 -2
- data/lib/write_xlsx/package/styles.rb +13 -9
- data/lib/write_xlsx/package/table.rb +8 -2
- data/lib/write_xlsx/package/theme.rb +0 -3
- data/lib/write_xlsx/package/vml.rb +2 -2
- data/lib/write_xlsx/page_setup.rb +3 -1
- data/lib/write_xlsx/shape.rb +97 -100
- data/lib/write_xlsx/sheets.rb +6 -1
- data/lib/write_xlsx/sparkline.rb +2 -2
- data/lib/write_xlsx/utility/cell_reference.rb +124 -0
- data/lib/write_xlsx/utility/chart_formatting.rb +262 -0
- data/lib/write_xlsx/utility/common.rb +44 -0
- data/lib/write_xlsx/utility/date_time.rb +113 -0
- data/lib/write_xlsx/utility/dimensions.rb +40 -0
- data/lib/write_xlsx/utility/drawing.rb +136 -0
- data/lib/write_xlsx/utility/rich_text.rb +184 -0
- data/lib/write_xlsx/utility/sheetname_quoting.rb +73 -0
- data/lib/write_xlsx/utility/string_width.rb +45 -0
- data/lib/write_xlsx/utility/url.rb +27 -0
- data/lib/write_xlsx/utility/xml_primitives.rb +32 -0
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook/chart_data.rb +188 -0
- data/lib/write_xlsx/workbook/format_preparation.rb +199 -0
- data/lib/write_xlsx/workbook/initialization.rb +223 -0
- data/lib/write_xlsx/workbook/package_preparation.rb +231 -0
- data/lib/write_xlsx/workbook/workbook_writer.rb +164 -0
- data/lib/write_xlsx/workbook.rb +143 -981
- data/lib/write_xlsx/worksheet/autofilter.rb +3 -1
- data/lib/write_xlsx/worksheet/cell_data.rb +5 -1
- data/lib/write_xlsx/worksheet/columns.rb +8 -3
- data/lib/write_xlsx/worksheet/data_validation.rb +9 -1
- data/lib/write_xlsx/worksheet/data_writing.rb +37 -10
- data/lib/write_xlsx/worksheet/formatting.rb +3 -1
- data/lib/write_xlsx/worksheet/hyperlink.rb +9 -1
- data/lib/write_xlsx/worksheet/row_col_sizing.rb +3 -1
- data/lib/write_xlsx/worksheet/xml_writer.rb +9 -4
- data/lib/write_xlsx/worksheet.rb +19 -2
- metadata +41 -2
- data/lib/write_xlsx/utility.rb +0 -1034
data/lib/write_xlsx/shape.rb
CHANGED
|
@@ -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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
data/lib/write_xlsx/sheets.rb
CHANGED
|
@@ -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
|
|
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
|
|
data/lib/write_xlsx/sparkline.rb
CHANGED
|
@@ -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
|