write_xlsx 1.12.3 → 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 +22 -0
- data/Changes +23 -0
- data/README.md +1 -1
- 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 +35 -83
- 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 +203 -0
- data/lib/write_xlsx/package/app.rb +3 -3
- 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 +192 -0
- data/lib/write_xlsx/shape.rb +97 -100
- data/lib/write_xlsx/sheets.rb +9 -4
- 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/asset_manager.rb +60 -0
- data/lib/write_xlsx/worksheet/autofilter.rb +390 -0
- data/lib/write_xlsx/worksheet/cell_data.rb +13 -6
- data/lib/write_xlsx/worksheet/cell_data_manager.rb +47 -0
- data/lib/write_xlsx/worksheet/cell_data_store.rb +61 -0
- data/lib/write_xlsx/worksheet/columns.rb +204 -0
- data/lib/write_xlsx/worksheet/comments_support.rb +61 -0
- data/lib/write_xlsx/worksheet/conditional_formats.rb +30 -0
- data/lib/write_xlsx/worksheet/data_validation.rb +9 -1
- data/lib/write_xlsx/worksheet/data_writing.rb +1017 -0
- data/lib/write_xlsx/worksheet/drawing_methods.rb +308 -0
- data/lib/write_xlsx/worksheet/drawing_preparation.rb +290 -0
- data/lib/write_xlsx/worksheet/drawing_relations.rb +76 -0
- data/lib/write_xlsx/worksheet/drawing_xml_writer.rb +50 -0
- data/lib/write_xlsx/worksheet/formatting.rb +418 -0
- data/lib/write_xlsx/worksheet/hyperlink.rb +9 -1
- data/lib/write_xlsx/worksheet/initialization.rb +146 -0
- data/lib/write_xlsx/worksheet/panes.rb +64 -0
- data/lib/write_xlsx/worksheet/print_options.rb +72 -0
- data/lib/write_xlsx/worksheet/protection.rb +65 -0
- data/lib/write_xlsx/worksheet/rich_text_helpers.rb +78 -0
- data/lib/write_xlsx/worksheet/row_col_sizing.rb +69 -0
- data/lib/write_xlsx/worksheet/rows.rb +84 -0
- data/lib/write_xlsx/worksheet/selection.rb +41 -0
- data/lib/write_xlsx/worksheet/xml_writer.rb +1246 -0
- data/lib/write_xlsx/worksheet.rb +376 -4530
- metadata +66 -4
- data/lib/write_xlsx/utility.rb +0 -986
- data/lib/write_xlsx/worksheet/page_setup.rb +0 -192
|
@@ -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
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Writexlsx
|
|
5
|
+
module Utility
|
|
6
|
+
module DateTime
|
|
7
|
+
#
|
|
8
|
+
# convert_date_time(date_time_string)
|
|
9
|
+
#
|
|
10
|
+
# The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format
|
|
11
|
+
# and converts it to a decimal number representing a valid Excel date.
|
|
12
|
+
#
|
|
13
|
+
def convert_date_time(date_time_string) # :nodoc:
|
|
14
|
+
date_time = date_time_string.to_s.sub(/^\s+/, '').sub(/\s+$/, '').sub(/Z$/, '')
|
|
15
|
+
|
|
16
|
+
# Check for invalid date char.
|
|
17
|
+
return nil if date_time =~ /[^0-9T:\-.Z]/
|
|
18
|
+
|
|
19
|
+
# Check for "T" after date or before time.
|
|
20
|
+
return nil unless date_time =~ /\dT|T\d/
|
|
21
|
+
|
|
22
|
+
days = 0 # Number of days since epoch
|
|
23
|
+
seconds = 0 # Time expressed as fraction of 24h hours in seconds
|
|
24
|
+
|
|
25
|
+
# Split into date and time.
|
|
26
|
+
date, time = date_time.split("T")
|
|
27
|
+
|
|
28
|
+
# We allow the time portion of the input DateTime to be optional.
|
|
29
|
+
if time
|
|
30
|
+
# Match hh:mm:ss.sss+ where the seconds are optional
|
|
31
|
+
if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
|
|
32
|
+
hour = ::Regexp.last_match(1).to_i
|
|
33
|
+
min = ::Regexp.last_match(2).to_i
|
|
34
|
+
sec = ::Regexp.last_match(4).to_f
|
|
35
|
+
else
|
|
36
|
+
return nil # Not a valid time format.
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Some boundary checks
|
|
40
|
+
return nil if hour >= 24
|
|
41
|
+
return nil if min >= 60
|
|
42
|
+
return nil if sec >= 60
|
|
43
|
+
|
|
44
|
+
# Excel expresses seconds as a fraction of the number in 24 hours.
|
|
45
|
+
seconds = ((hour * 60 * 60) + (min * 60) + sec) / (24.0 * 60 * 60)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# We allow the date portion of the input DateTime to be optional.
|
|
49
|
+
return seconds if date == ''
|
|
50
|
+
|
|
51
|
+
# Match date as yyyy-mm-dd.
|
|
52
|
+
if date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/
|
|
53
|
+
year = ::Regexp.last_match(1).to_i
|
|
54
|
+
month = ::Regexp.last_match(2).to_i
|
|
55
|
+
day = ::Regexp.last_match(3).to_i
|
|
56
|
+
else
|
|
57
|
+
return nil # Not a valid date format.
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Set the epoch as 1900 or 1904. Defaults to 1900.
|
|
61
|
+
# Special cases for Excel.
|
|
62
|
+
unless date_1904?
|
|
63
|
+
return seconds if date == '1899-12-31' # Excel 1900 epoch
|
|
64
|
+
return seconds if date == '1900-01-00' # Excel 1900 epoch
|
|
65
|
+
return 60 + seconds if date == '1900-02-29' # Excel false leapday
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# We calculate the date by calculating the number of days since the epoch
|
|
69
|
+
# and adjust for the number of leap days. We calculate the number of leap
|
|
70
|
+
# days by normalising the year in relation to the epoch. Thus the year 2000
|
|
71
|
+
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
|
|
72
|
+
#
|
|
73
|
+
epoch = date_1904? ? 1904 : 1900
|
|
74
|
+
offset = date_1904? ? 4 : 0
|
|
75
|
+
norm = 300
|
|
76
|
+
range = year - epoch
|
|
77
|
+
|
|
78
|
+
# Set month days and check for leap year.
|
|
79
|
+
mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
80
|
+
leap = 0
|
|
81
|
+
leap = 1 if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
|
|
82
|
+
mdays[1] = 29 if leap != 0
|
|
83
|
+
|
|
84
|
+
# Some boundary checks
|
|
85
|
+
return nil if year < epoch || year > 9999
|
|
86
|
+
return nil if month < 1 || month > 12
|
|
87
|
+
return nil if day < 1 || day > mdays[month - 1]
|
|
88
|
+
|
|
89
|
+
# Accumulate the number of days since the epoch.
|
|
90
|
+
days = day # Add days for current month
|
|
91
|
+
(0..(month - 2)).each do |m|
|
|
92
|
+
days += mdays[m] # Add days for past months
|
|
93
|
+
end
|
|
94
|
+
days += range * 365 # Add days for past years
|
|
95
|
+
days += (range / 4) # Add leapdays
|
|
96
|
+
days -= ((range + offset) / 100) # Subtract 100 year leapdays
|
|
97
|
+
days += ((range + offset + norm) / 400) # Add 400 year leapdays
|
|
98
|
+
days -= leap # Already counted above
|
|
99
|
+
|
|
100
|
+
# Adjust for Excel erroneously treating 1900 as a leap year.
|
|
101
|
+
days += 1 if !date_1904? && days > 59
|
|
102
|
+
|
|
103
|
+
date_time = sprintf("%0.10f", days + seconds)
|
|
104
|
+
date_time = date_time.sub(/\.?0+$/, '') if date_time =~ /\./
|
|
105
|
+
if date_time =~ /\./
|
|
106
|
+
date_time.to_f
|
|
107
|
+
else
|
|
108
|
+
date_time.to_i
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'write_xlsx/constants'
|
|
5
|
+
|
|
6
|
+
module Writexlsx
|
|
7
|
+
module Utility
|
|
8
|
+
module Dimensions
|
|
9
|
+
include Constants
|
|
10
|
+
|
|
11
|
+
def check_dimensions(row, col)
|
|
12
|
+
raise WriteXLSXDimensionError if !row || row >= ROW_MAX || !col || col >= COL_MAX
|
|
13
|
+
|
|
14
|
+
0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Check that row and col are valid and store max and min values for use in
|
|
19
|
+
# other methods/elements.
|
|
20
|
+
#
|
|
21
|
+
def check_dimensions_and_update_max_min_values(row, col, ignore_row = 0, ignore_col = 0) # :nodoc:
|
|
22
|
+
check_dimensions(row, col)
|
|
23
|
+
store_row_max_min_values(row) if ignore_row == 0
|
|
24
|
+
store_col_max_min_values(col) if ignore_col == 0
|
|
25
|
+
|
|
26
|
+
0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def store_row_max_min_values(row)
|
|
30
|
+
@dim_rowmin = row if !@dim_rowmin || (row < @dim_rowmin)
|
|
31
|
+
@dim_rowmax = row if !@dim_rowmax || (row > @dim_rowmax)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def store_col_max_min_values(col)
|
|
35
|
+
@dim_colmin = col if !@dim_colmin || (col < @dim_colmin)
|
|
36
|
+
@dim_colmax = col if !@dim_colmax || (col > @dim_colmax)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Writexlsx
|
|
5
|
+
module Utility
|
|
6
|
+
module Drawing
|
|
7
|
+
#
|
|
8
|
+
# Convert vertices from pixels to points.
|
|
9
|
+
#
|
|
10
|
+
def pixels_to_points(vertices)
|
|
11
|
+
_col_start, _row_start, _x1, _y1,
|
|
12
|
+
_col_end, _row_end, _x2, _y2,
|
|
13
|
+
left, top, width, height = vertices.flatten
|
|
14
|
+
|
|
15
|
+
left *= 0.75
|
|
16
|
+
top *= 0.75
|
|
17
|
+
width *= 0.75
|
|
18
|
+
height *= 0.75
|
|
19
|
+
|
|
20
|
+
[left, top, width, height]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def v_shape_attributes_base(id)
|
|
24
|
+
[
|
|
25
|
+
['id', "_x0000_s#{id}"],
|
|
26
|
+
['type', type]
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def v_shape_style_base(z_index, vertices)
|
|
31
|
+
left, top, width, height = pixels_to_points(vertices)
|
|
32
|
+
|
|
33
|
+
left_str = float_to_str(left)
|
|
34
|
+
top_str = float_to_str(top)
|
|
35
|
+
width_str = float_to_str(width)
|
|
36
|
+
height_str = float_to_str(height)
|
|
37
|
+
z_index_str = float_to_str(z_index)
|
|
38
|
+
|
|
39
|
+
shape_style_base(left_str, top_str, width_str, height_str, z_index_str)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def shape_style_base(left_str, top_str, width_str, height_str, z_index_str)
|
|
43
|
+
[
|
|
44
|
+
'position:absolute;',
|
|
45
|
+
'margin-left:',
|
|
46
|
+
left_str, 'pt;',
|
|
47
|
+
'margin-top:',
|
|
48
|
+
top_str, 'pt;',
|
|
49
|
+
'width:',
|
|
50
|
+
width_str, 'pt;',
|
|
51
|
+
'height:',
|
|
52
|
+
height_str, 'pt;',
|
|
53
|
+
'z-index:',
|
|
54
|
+
z_index_str, ';'
|
|
55
|
+
]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# Write the <v:fill> element.
|
|
60
|
+
#
|
|
61
|
+
def write_fill
|
|
62
|
+
@writer.empty_tag('v:fill', fill_attributes)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Write the <v:path> element.
|
|
67
|
+
#
|
|
68
|
+
def write_comment_path(gradientshapeok, connecttype)
|
|
69
|
+
attributes = []
|
|
70
|
+
|
|
71
|
+
attributes << %w[gradientshapeok t] if gradientshapeok
|
|
72
|
+
attributes << ['o:connecttype', connecttype]
|
|
73
|
+
|
|
74
|
+
@writer.empty_tag('v:path', attributes)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Write the <x:Anchor> element.
|
|
79
|
+
#
|
|
80
|
+
def write_anchor
|
|
81
|
+
col_start, row_start, x1, y1, col_end, row_end, x2, y2 = @vertices
|
|
82
|
+
data = [col_start, x1, row_start, y1, col_end, x2, row_end, y2].join(', ')
|
|
83
|
+
|
|
84
|
+
@writer.data_element('x:Anchor', data)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
#
|
|
88
|
+
# Write the <x:AutoFill> element.
|
|
89
|
+
#
|
|
90
|
+
def write_auto_fill
|
|
91
|
+
@writer.data_element('x:AutoFill', 'False')
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
#
|
|
95
|
+
# Write the <div> element.
|
|
96
|
+
#
|
|
97
|
+
def write_div(align, font = nil)
|
|
98
|
+
style = "text-align:#{align}"
|
|
99
|
+
attributes = [['style', style]]
|
|
100
|
+
|
|
101
|
+
@writer.tag_elements('div', attributes) do
|
|
102
|
+
if font
|
|
103
|
+
# Write the font element.
|
|
104
|
+
write_font(font)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
#
|
|
110
|
+
# Write the <font> element.
|
|
111
|
+
#
|
|
112
|
+
def write_font(font)
|
|
113
|
+
caption = font[:_caption]
|
|
114
|
+
face = 'Calibri'
|
|
115
|
+
size = 220
|
|
116
|
+
color = '#000000'
|
|
117
|
+
|
|
118
|
+
attributes = [
|
|
119
|
+
['face', face],
|
|
120
|
+
['size', size],
|
|
121
|
+
['color', color]
|
|
122
|
+
]
|
|
123
|
+
@writer.data_element('font', caption, attributes)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
#
|
|
127
|
+
# Write the <v:stroke> element.
|
|
128
|
+
#
|
|
129
|
+
def write_stroke
|
|
130
|
+
attributes = [%w[joinstyle miter]]
|
|
131
|
+
|
|
132
|
+
@writer.empty_tag('v:stroke', attributes)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|