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
data/lib/write_xlsx/utility.rb
DELETED
|
@@ -1,986 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'write_xlsx/col_name'
|
|
5
|
-
|
|
6
|
-
module Writexlsx
|
|
7
|
-
module Utility
|
|
8
|
-
ROW_MAX = 1048576 # :nodoc:
|
|
9
|
-
COL_MAX = 16384 # :nodoc:
|
|
10
|
-
STR_MAX = 32767 # :nodoc:
|
|
11
|
-
SHEETNAME_MAX = 31 # :nodoc:
|
|
12
|
-
CHAR_WIDTHS = {
|
|
13
|
-
' ' => 3, '!' => 5, '"' => 6, '#' => 7, '$' => 7, '%' => 11,
|
|
14
|
-
'&' => 10, "'" => 3, '(' => 5, ')' => 5, '*' => 7, '+' => 7,
|
|
15
|
-
',' => 4, '-' => 5, '.' => 4, '/' => 6, '0' => 7, '1' => 7,
|
|
16
|
-
'2' => 7, '3' => 7, '4' => 7, '5' => 7, '6' => 7, '7' => 7,
|
|
17
|
-
'8' => 7, '9' => 7, ':' => 4, ';' => 4, '<' => 7, '=' => 7,
|
|
18
|
-
'>' => 7, '?' => 7, '@' => 13, 'A' => 9, 'B' => 8, 'C' => 8,
|
|
19
|
-
'D' => 9, 'E' => 7, 'F' => 7, 'G' => 9, 'H' => 9, 'I' => 4,
|
|
20
|
-
'J' => 5, 'K' => 8, 'L' => 6, 'M' => 12, 'N' => 10, 'O' => 10,
|
|
21
|
-
'P' => 8, 'Q' => 10, 'R' => 8, 'S' => 7, 'T' => 7, 'U' => 9,
|
|
22
|
-
'V' => 9, 'W' => 13, 'X' => 8, 'Y' => 7, 'Z' => 7, '[' => 5,
|
|
23
|
-
'\\' => 6, ']' => 5, '^' => 7, '_' => 7, '`' => 4, 'a' => 7,
|
|
24
|
-
'b' => 8, 'c' => 6, 'd' => 8, 'e' => 8, 'f' => 5, 'g' => 7,
|
|
25
|
-
'h' => 8, 'i' => 4, 'j' => 4, 'k' => 7, 'l' => 4, 'm' => 12,
|
|
26
|
-
'n' => 8, 'o' => 8, 'p' => 8, 'q' => 8, 'r' => 5, 's' => 6,
|
|
27
|
-
't' => 5, 'u' => 8, 'v' => 7, 'w' => 11, 'x' => 7, 'y' => 7,
|
|
28
|
-
'z' => 6, '{' => 5, '|' => 7, '}' => 5, '~' => 7
|
|
29
|
-
}.freeze
|
|
30
|
-
MAX_DIGIT_WIDTH = 7 # For Calabri 11. # :nodoc:
|
|
31
|
-
PADDING = 5 # :nodoc:
|
|
32
|
-
DEFAULT_COL_PIXELS = 64
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
# xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
|
|
36
|
-
#
|
|
37
|
-
def xl_rowcol_to_cell(row_or_name, col, row_absolute = false, col_absolute = false)
|
|
38
|
-
if row_or_name.is_a?(Integer)
|
|
39
|
-
row_or_name += 1 # Change from 0-indexed to 1 indexed.
|
|
40
|
-
end
|
|
41
|
-
col_str = xl_col_to_name(col, col_absolute)
|
|
42
|
-
"#{col_str}#{absolute_char(row_absolute)}#{row_or_name}"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
# Returns: [row, col, row_absolute, col_absolute]
|
|
47
|
-
#
|
|
48
|
-
# The row_absolute and col_absolute parameters aren't documented because they
|
|
49
|
-
# mainly used internally and aren't very useful to the user.
|
|
50
|
-
#
|
|
51
|
-
def xl_cell_to_rowcol(cell)
|
|
52
|
-
cell =~ /(\$?)([A-Z]{1,3})(\$?)(\d+)/
|
|
53
|
-
|
|
54
|
-
col_abs = ::Regexp.last_match(1) != ""
|
|
55
|
-
col = ::Regexp.last_match(2)
|
|
56
|
-
row_abs = ::Regexp.last_match(3) != ""
|
|
57
|
-
row = ::Regexp.last_match(4).to_i
|
|
58
|
-
|
|
59
|
-
# Convert base26 column string to number
|
|
60
|
-
# All your Base are belong to us.
|
|
61
|
-
chars = col.split("")
|
|
62
|
-
expn = 0
|
|
63
|
-
col = 0
|
|
64
|
-
|
|
65
|
-
chars.reverse.each do |char|
|
|
66
|
-
col += (char.ord - 'A'.ord + 1) * (26**expn)
|
|
67
|
-
expn += 1
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Convert 1-index to zero-index
|
|
71
|
-
row -= 1
|
|
72
|
-
col -= 1
|
|
73
|
-
|
|
74
|
-
[row, col, row_abs, col_abs]
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def xl_col_to_name(col, col_absolute)
|
|
78
|
-
col_str = ColName.instance.col_str(col)
|
|
79
|
-
if col_absolute
|
|
80
|
-
"#{absolute_char(col_absolute)}#{col_str}"
|
|
81
|
-
else
|
|
82
|
-
# Do not allocate new string
|
|
83
|
-
col_str
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def xl_range(row_1, row_2, col_1, col_2,
|
|
88
|
-
row_abs_1 = false, row_abs_2 = false, col_abs_1 = false, col_abs_2 = false)
|
|
89
|
-
range1 = xl_rowcol_to_cell(row_1, col_1, row_abs_1, col_abs_1)
|
|
90
|
-
range2 = xl_rowcol_to_cell(row_2, col_2, row_abs_2, col_abs_2)
|
|
91
|
-
|
|
92
|
-
if range1 == range2
|
|
93
|
-
range1
|
|
94
|
-
else
|
|
95
|
-
"#{range1}:#{range2}"
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def xl_range_formula(sheetname, row_1, row_2, col_1, col_2)
|
|
100
|
-
# Use Excel's conventions and quote the sheet name if it contains any
|
|
101
|
-
# non-word character or if it isn't already quoted.
|
|
102
|
-
sheetname = "'#{sheetname}'" if sheetname =~ /\W/ && !(sheetname =~ /^'/)
|
|
103
|
-
|
|
104
|
-
range1 = xl_rowcol_to_cell(row_1, col_1, 1, 1)
|
|
105
|
-
range2 = xl_rowcol_to_cell(row_2, col_2, 1, 1)
|
|
106
|
-
|
|
107
|
-
"=#{sheetname}!#{range1}:#{range2}"
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
#
|
|
111
|
-
# xl_string_pixel_width($string)
|
|
112
|
-
#
|
|
113
|
-
# Get the pixel width of a string based on individual character widths taken
|
|
114
|
-
# from Excel. UTF8 characters are given a default width of 8.
|
|
115
|
-
#
|
|
116
|
-
# Note, Excel adds an additional 7 pixels padding to a cell.
|
|
117
|
-
#
|
|
118
|
-
def xl_string_pixel_width(string)
|
|
119
|
-
length = 0
|
|
120
|
-
string.to_s.split("").each { |char| length += CHAR_WIDTHS[char] || 8 }
|
|
121
|
-
|
|
122
|
-
length
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
#
|
|
126
|
-
# Sheetnames used in references should be quoted if they contain any spaces,
|
|
127
|
-
# special characters or if the look like something that isn't a sheet name.
|
|
128
|
-
# TODO. We need to handle more special cases.
|
|
129
|
-
#
|
|
130
|
-
def quote_sheetname(sheetname) # :nodoc:
|
|
131
|
-
# Use Excel's conventions and quote the sheet name if it comtains any
|
|
132
|
-
# non-word character or if it isn't already quoted.
|
|
133
|
-
name = sheetname.dup
|
|
134
|
-
if name =~ /\W/ && !(name =~ /^'/)
|
|
135
|
-
# Double quote and single quoted strings.
|
|
136
|
-
name = name.gsub("'", "''")
|
|
137
|
-
name = "'#{name}'"
|
|
138
|
-
end
|
|
139
|
-
name
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def check_dimensions(row, col)
|
|
143
|
-
raise WriteXLSXDimensionError if !row || row >= ROW_MAX || !col || col >= COL_MAX
|
|
144
|
-
|
|
145
|
-
0
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
#
|
|
149
|
-
# convert_date_time(date_time_string)
|
|
150
|
-
#
|
|
151
|
-
# The function takes a date and time in ISO8601 "yyyy-mm-ddThh:mm:ss.ss" format
|
|
152
|
-
# and converts it to a decimal number representing a valid Excel date.
|
|
153
|
-
#
|
|
154
|
-
def convert_date_time(date_time_string) # :nodoc:
|
|
155
|
-
date_time = date_time_string.to_s.sub(/^\s+/, '').sub(/\s+$/, '').sub(/Z$/, '')
|
|
156
|
-
|
|
157
|
-
# Check for invalid date char.
|
|
158
|
-
return nil if date_time =~ /[^0-9T:\-.Z]/
|
|
159
|
-
|
|
160
|
-
# Check for "T" after date or before time.
|
|
161
|
-
return nil unless date_time =~ /\dT|T\d/
|
|
162
|
-
|
|
163
|
-
days = 0 # Number of days since epoch
|
|
164
|
-
seconds = 0 # Time expressed as fraction of 24h hours in seconds
|
|
165
|
-
|
|
166
|
-
# Split into date and time.
|
|
167
|
-
date, time = date_time.split("T")
|
|
168
|
-
|
|
169
|
-
# We allow the time portion of the input DateTime to be optional.
|
|
170
|
-
if time
|
|
171
|
-
# Match hh:mm:ss.sss+ where the seconds are optional
|
|
172
|
-
if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
|
|
173
|
-
hour = ::Regexp.last_match(1).to_i
|
|
174
|
-
min = ::Regexp.last_match(2).to_i
|
|
175
|
-
sec = ::Regexp.last_match(4).to_f
|
|
176
|
-
else
|
|
177
|
-
return nil # Not a valid time format.
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# Some boundary checks
|
|
181
|
-
return nil if hour >= 24
|
|
182
|
-
return nil if min >= 60
|
|
183
|
-
return nil if sec >= 60
|
|
184
|
-
|
|
185
|
-
# Excel expresses seconds as a fraction of the number in 24 hours.
|
|
186
|
-
seconds = ((hour * 60 * 60) + (min * 60) + sec) / (24.0 * 60 * 60)
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# We allow the date portion of the input DateTime to be optional.
|
|
190
|
-
return seconds if date == ''
|
|
191
|
-
|
|
192
|
-
# Match date as yyyy-mm-dd.
|
|
193
|
-
if date =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$/
|
|
194
|
-
year = ::Regexp.last_match(1).to_i
|
|
195
|
-
month = ::Regexp.last_match(2).to_i
|
|
196
|
-
day = ::Regexp.last_match(3).to_i
|
|
197
|
-
else
|
|
198
|
-
return nil # Not a valid date format.
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# Set the epoch as 1900 or 1904. Defaults to 1900.
|
|
202
|
-
# Special cases for Excel.
|
|
203
|
-
unless date_1904?
|
|
204
|
-
return seconds if date == '1899-12-31' # Excel 1900 epoch
|
|
205
|
-
return seconds if date == '1900-01-00' # Excel 1900 epoch
|
|
206
|
-
return 60 + seconds if date == '1900-02-29' # Excel false leapday
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# We calculate the date by calculating the number of days since the epoch
|
|
210
|
-
# and adjust for the number of leap days. We calculate the number of leap
|
|
211
|
-
# days by normalising the year in relation to the epoch. Thus the year 2000
|
|
212
|
-
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
|
|
213
|
-
#
|
|
214
|
-
epoch = date_1904? ? 1904 : 1900
|
|
215
|
-
offset = date_1904? ? 4 : 0
|
|
216
|
-
norm = 300
|
|
217
|
-
range = year - epoch
|
|
218
|
-
|
|
219
|
-
# Set month days and check for leap year.
|
|
220
|
-
mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
221
|
-
leap = 0
|
|
222
|
-
leap = 1 if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0
|
|
223
|
-
mdays[1] = 29 if leap != 0
|
|
224
|
-
|
|
225
|
-
# Some boundary checks
|
|
226
|
-
return nil if year < epoch or year > 9999
|
|
227
|
-
return nil if month < 1 or month > 12
|
|
228
|
-
return nil if day < 1 or day > mdays[month - 1]
|
|
229
|
-
|
|
230
|
-
# Accumulate the number of days since the epoch.
|
|
231
|
-
days = day # Add days for current month
|
|
232
|
-
(0..(month - 2)).each do |m|
|
|
233
|
-
days += mdays[m] # Add days for past months
|
|
234
|
-
end
|
|
235
|
-
days += range * 365 # Add days for past years
|
|
236
|
-
days += (range / 4) # Add leapdays
|
|
237
|
-
days -= ((range + offset) / 100) # Subtract 100 year leapdays
|
|
238
|
-
days += ((range + offset + norm) / 400) # Add 400 year leapdays
|
|
239
|
-
days -= leap # Already counted above
|
|
240
|
-
|
|
241
|
-
# Adjust for Excel erroneously treating 1900 as a leap year.
|
|
242
|
-
days += 1 if !date_1904? and days > 59
|
|
243
|
-
|
|
244
|
-
date_time = sprintf("%0.10f", days + seconds)
|
|
245
|
-
date_time = date_time.sub(/\.?0+$/, '') if date_time =~ /\./
|
|
246
|
-
if date_time =~ /\./
|
|
247
|
-
date_time.to_f
|
|
248
|
-
else
|
|
249
|
-
date_time.to_i
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def escape_url(url)
|
|
254
|
-
unless url =~ /%[0-9a-fA-F]{2}/
|
|
255
|
-
# Escape the URL escape symbol.
|
|
256
|
-
url = url.gsub("%", "%25")
|
|
257
|
-
|
|
258
|
-
# Escape whitespae in URL.
|
|
259
|
-
url = url.gsub(/[\s\x00]/, '%20')
|
|
260
|
-
|
|
261
|
-
# Escape other special characters in URL.
|
|
262
|
-
re = /(["<>\[\]`^{}])/
|
|
263
|
-
while re =~ url
|
|
264
|
-
match = $~[1]
|
|
265
|
-
url = url.sub(re, sprintf("%%%x", match.ord))
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
url
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
def absolute_char(absolute)
|
|
273
|
-
absolute ? '$' : ''
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
def xml_str
|
|
277
|
-
@writer.string
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def self.delete_files(path)
|
|
281
|
-
if FileTest.file?(path)
|
|
282
|
-
File.delete(path)
|
|
283
|
-
elsif FileTest.directory?(path)
|
|
284
|
-
Dir.foreach(path) do |file|
|
|
285
|
-
next if file =~ /^\.\.?$/ # '.' or '..'
|
|
286
|
-
|
|
287
|
-
delete_files(path.sub(%r{/+$}, "") + '/' + file)
|
|
288
|
-
end
|
|
289
|
-
Dir.rmdir(path)
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
def put_deprecate_message(method)
|
|
294
|
-
warn("Warning: calling deprecated method #{method}. This method will be removed in a future release.")
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
# Check for a cell reference in A1 notation and substitute row and column
|
|
298
|
-
def row_col_notation(row_or_a1) # :nodoc:
|
|
299
|
-
substitute_cellref(row_or_a1) if row_or_a1.respond_to?(:match) && row_or_a1.to_s =~ /^\D/
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
#
|
|
303
|
-
# Substitute an Excel cell reference in A1 notation for zero based row and
|
|
304
|
-
# column values in an argument list.
|
|
305
|
-
#
|
|
306
|
-
# Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
|
|
307
|
-
#
|
|
308
|
-
def substitute_cellref(cell, *args) # :nodoc:
|
|
309
|
-
# return [*args] if cell.respond_to?(:coerce) # Numeric
|
|
310
|
-
|
|
311
|
-
normalized_cell = cell.upcase
|
|
312
|
-
|
|
313
|
-
case normalized_cell
|
|
314
|
-
# Convert a column range: 'A:A' or 'B:G'.
|
|
315
|
-
# A range such as A:A is equivalent to A1:65536, so add rows as required
|
|
316
|
-
when /\$?([A-Z]{1,3}):\$?([A-Z]{1,3})/
|
|
317
|
-
row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1) + '1')
|
|
318
|
-
row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2) + ROW_MAX.to_s)
|
|
319
|
-
[row1, col1, row2, col2, *args]
|
|
320
|
-
# Convert a cell range: 'A1:B7'
|
|
321
|
-
when /\$?([A-Z]{1,3}\$?\d+):\$?([A-Z]{1,3}\$?\d+)/
|
|
322
|
-
row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
|
|
323
|
-
row2, col2 = xl_cell_to_rowcol(::Regexp.last_match(2))
|
|
324
|
-
[row1, col1, row2, col2, *args]
|
|
325
|
-
# Convert a cell reference: 'A1' or 'AD2000'
|
|
326
|
-
when /\$?([A-Z]{1,3}\$?\d+)/
|
|
327
|
-
row1, col1 = xl_cell_to_rowcol(::Regexp.last_match(1))
|
|
328
|
-
[row1, col1, *args]
|
|
329
|
-
else
|
|
330
|
-
raise("Unknown cell reference #{normalized_cell}")
|
|
331
|
-
end
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
def underline_attributes(underline)
|
|
335
|
-
if underline == 2
|
|
336
|
-
[%w[val double]]
|
|
337
|
-
elsif underline == 33
|
|
338
|
-
[%w[val singleAccounting]]
|
|
339
|
-
elsif underline == 34
|
|
340
|
-
[%w[val doubleAccounting]]
|
|
341
|
-
else
|
|
342
|
-
[] # Default to single underline.
|
|
343
|
-
end
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
#
|
|
347
|
-
# Write the <color> element.
|
|
348
|
-
#
|
|
349
|
-
def write_color(name, value, writer = @writer) # :nodoc:
|
|
350
|
-
attributes = [[name, value]]
|
|
351
|
-
|
|
352
|
-
writer.empty_tag('color', attributes)
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
PERL_TRUE_VALUES = [false, nil, 0, "0", "", [], {}].freeze
|
|
356
|
-
#
|
|
357
|
-
# return perl's boolean result
|
|
358
|
-
#
|
|
359
|
-
def ptrue?(value)
|
|
360
|
-
if PERL_TRUE_VALUES.include?(value)
|
|
361
|
-
false
|
|
362
|
-
else
|
|
363
|
-
true
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
def check_parameter(params, valid_keys, method)
|
|
368
|
-
invalids = params.keys - valid_keys
|
|
369
|
-
unless invalids.empty?
|
|
370
|
-
raise WriteXLSXOptionParameterError,
|
|
371
|
-
"Unknown parameter '#{invalids.join(", ")}' in #{method}."
|
|
372
|
-
end
|
|
373
|
-
true
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
#
|
|
377
|
-
# Check that row and col are valid and store max and min values for use in
|
|
378
|
-
# other methods/elements.
|
|
379
|
-
#
|
|
380
|
-
def check_dimensions_and_update_max_min_values(row, col, ignore_row = 0, ignore_col = 0) # :nodoc:
|
|
381
|
-
check_dimensions(row, col)
|
|
382
|
-
store_row_max_min_values(row) if ignore_row == 0
|
|
383
|
-
store_col_max_min_values(col) if ignore_col == 0
|
|
384
|
-
|
|
385
|
-
0
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
def store_row_max_min_values(row)
|
|
389
|
-
@dim_rowmin = row if !@dim_rowmin || (row < @dim_rowmin)
|
|
390
|
-
@dim_rowmax = row if !@dim_rowmax || (row > @dim_rowmax)
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
def store_col_max_min_values(col)
|
|
394
|
-
@dim_colmin = col if !@dim_colmin || (col < @dim_colmin)
|
|
395
|
-
@dim_colmax = col if !@dim_colmax || (col > @dim_colmax)
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
def float_to_str(float)
|
|
399
|
-
return '' unless float
|
|
400
|
-
|
|
401
|
-
if float == float.to_i
|
|
402
|
-
float.to_i.to_s
|
|
403
|
-
else
|
|
404
|
-
float.to_s
|
|
405
|
-
end
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
#
|
|
409
|
-
# Convert user defined legend properties to the structure required internally.
|
|
410
|
-
#
|
|
411
|
-
def legend_properties(params)
|
|
412
|
-
legend = Writexlsx::Chart::Legend.new
|
|
413
|
-
|
|
414
|
-
legend.position = params[:position] || 'right'
|
|
415
|
-
legend.delete_series = params[:delete_series]
|
|
416
|
-
legend.font = convert_font_args(params[:font])
|
|
417
|
-
|
|
418
|
-
# Set the legend layout.
|
|
419
|
-
legend.layout = layout_properties(params[:layout])
|
|
420
|
-
|
|
421
|
-
# Turn off the legend.
|
|
422
|
-
legend.position = 'none' if params[:none]
|
|
423
|
-
|
|
424
|
-
# Set the line properties for the legend.
|
|
425
|
-
line = line_properties(params[:line])
|
|
426
|
-
|
|
427
|
-
# Allow 'border' as a synonym for 'line'.
|
|
428
|
-
line = line_properties(params[:border]) if params[:border]
|
|
429
|
-
|
|
430
|
-
# Set the fill properties for the legend.
|
|
431
|
-
fill = fill_properties(params[:fill])
|
|
432
|
-
|
|
433
|
-
# Set the pattern properties for the legend.
|
|
434
|
-
pattern = pattern_properties(params[:pattern])
|
|
435
|
-
|
|
436
|
-
# Set the gradient fill properties for the legend.
|
|
437
|
-
gradient = gradient_properties(params[:gradient])
|
|
438
|
-
|
|
439
|
-
# Pattern fill overrides solid fill.
|
|
440
|
-
fill = nil if pattern
|
|
441
|
-
|
|
442
|
-
# Gradient fill overrides solid and pattern fills.
|
|
443
|
-
if gradient
|
|
444
|
-
pattern = nil
|
|
445
|
-
fill = nil
|
|
446
|
-
end
|
|
447
|
-
|
|
448
|
-
# Set the legend layout.
|
|
449
|
-
layout = layout_properties(params[:layout])
|
|
450
|
-
|
|
451
|
-
legend.line = line
|
|
452
|
-
legend.fill = fill
|
|
453
|
-
legend.pattern = pattern
|
|
454
|
-
legend.gradient = gradient
|
|
455
|
-
legend.layout = layout
|
|
456
|
-
|
|
457
|
-
@legend = legend
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
#
|
|
461
|
-
# Convert user defined layout properties to the format required internally.
|
|
462
|
-
#
|
|
463
|
-
def layout_properties(args, is_text = false)
|
|
464
|
-
return unless ptrue?(args)
|
|
465
|
-
|
|
466
|
-
properties = is_text ? %i[x y] : %i[x y width height]
|
|
467
|
-
|
|
468
|
-
# Check for valid properties.
|
|
469
|
-
args.keys.each do |key|
|
|
470
|
-
raise "Property '#{key}' not allowed in layout options\n" unless properties.include?(key.to_sym)
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
# Set the layout properties
|
|
474
|
-
layout = {}
|
|
475
|
-
properties.each do |property|
|
|
476
|
-
value = args[property]
|
|
477
|
-
# Convert to the format used by Excel for easier testing.
|
|
478
|
-
layout[property] = sprintf("%.17g", value)
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
layout
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
#
|
|
485
|
-
# Convert vertices from pixels to points.
|
|
486
|
-
#
|
|
487
|
-
def pixels_to_points(vertices)
|
|
488
|
-
_col_start, _row_start, _x1, _y1,
|
|
489
|
-
_col_end, _row_end, _x2, _y2,
|
|
490
|
-
left, top, width, height = vertices.flatten
|
|
491
|
-
|
|
492
|
-
left *= 0.75
|
|
493
|
-
top *= 0.75
|
|
494
|
-
width *= 0.75
|
|
495
|
-
height *= 0.75
|
|
496
|
-
|
|
497
|
-
[left, top, width, height]
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
def v_shape_attributes_base(id)
|
|
501
|
-
[
|
|
502
|
-
['id', "_x0000_s#{id}"],
|
|
503
|
-
['type', type]
|
|
504
|
-
]
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
def v_shape_style_base(z_index, vertices)
|
|
508
|
-
left, top, width, height = pixels_to_points(vertices)
|
|
509
|
-
|
|
510
|
-
left_str = float_to_str(left)
|
|
511
|
-
top_str = float_to_str(top)
|
|
512
|
-
width_str = float_to_str(width)
|
|
513
|
-
height_str = float_to_str(height)
|
|
514
|
-
z_index_str = float_to_str(z_index)
|
|
515
|
-
|
|
516
|
-
shape_style_base(left_str, top_str, width_str, height_str, z_index_str)
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
def shape_style_base(left_str, top_str, width_str, height_str, z_index_str)
|
|
520
|
-
[
|
|
521
|
-
'position:absolute;',
|
|
522
|
-
'margin-left:',
|
|
523
|
-
left_str, 'pt;',
|
|
524
|
-
'margin-top:',
|
|
525
|
-
top_str, 'pt;',
|
|
526
|
-
'width:',
|
|
527
|
-
width_str, 'pt;',
|
|
528
|
-
'height:',
|
|
529
|
-
height_str, 'pt;',
|
|
530
|
-
'z-index:',
|
|
531
|
-
z_index_str, ';'
|
|
532
|
-
]
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
#
|
|
536
|
-
# Write the <v:fill> element.
|
|
537
|
-
#
|
|
538
|
-
def write_fill
|
|
539
|
-
@writer.empty_tag('v:fill', fill_attributes)
|
|
540
|
-
end
|
|
541
|
-
|
|
542
|
-
#
|
|
543
|
-
# Write the <v:path> element.
|
|
544
|
-
#
|
|
545
|
-
def write_comment_path(gradientshapeok, connecttype)
|
|
546
|
-
attributes = []
|
|
547
|
-
|
|
548
|
-
attributes << %w[gradientshapeok t] if gradientshapeok
|
|
549
|
-
attributes << ['o:connecttype', connecttype]
|
|
550
|
-
|
|
551
|
-
@writer.empty_tag('v:path', attributes)
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
#
|
|
555
|
-
# Write the <x:Anchor> element.
|
|
556
|
-
#
|
|
557
|
-
def write_anchor
|
|
558
|
-
col_start, row_start, x1, y1, col_end, row_end, x2, y2 = @vertices
|
|
559
|
-
data = [col_start, x1, row_start, y1, col_end, x2, row_end, y2].join(', ')
|
|
560
|
-
|
|
561
|
-
@writer.data_element('x:Anchor', data)
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
#
|
|
565
|
-
# Write the <x:AutoFill> element.
|
|
566
|
-
#
|
|
567
|
-
def write_auto_fill
|
|
568
|
-
@writer.data_element('x:AutoFill', 'False')
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
#
|
|
572
|
-
# Write the <div> element.
|
|
573
|
-
#
|
|
574
|
-
def write_div(align, font = nil)
|
|
575
|
-
style = "text-align:#{align}"
|
|
576
|
-
attributes = [['style', style]]
|
|
577
|
-
|
|
578
|
-
@writer.tag_elements('div', attributes) do
|
|
579
|
-
if font
|
|
580
|
-
# Write the font element.
|
|
581
|
-
write_font(font)
|
|
582
|
-
end
|
|
583
|
-
end
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
#
|
|
587
|
-
# Write the <font> element.
|
|
588
|
-
#
|
|
589
|
-
def write_font(font)
|
|
590
|
-
caption = font[:_caption]
|
|
591
|
-
face = 'Calibri'
|
|
592
|
-
size = 220
|
|
593
|
-
color = '#000000'
|
|
594
|
-
|
|
595
|
-
attributes = [
|
|
596
|
-
['face', face],
|
|
597
|
-
['size', size],
|
|
598
|
-
['color', color]
|
|
599
|
-
]
|
|
600
|
-
@writer.data_element('font', caption, attributes)
|
|
601
|
-
end
|
|
602
|
-
|
|
603
|
-
#
|
|
604
|
-
# Write the <v:stroke> element.
|
|
605
|
-
#
|
|
606
|
-
def write_stroke
|
|
607
|
-
attributes = [%w[joinstyle miter]]
|
|
608
|
-
|
|
609
|
-
@writer.empty_tag('v:stroke', attributes)
|
|
610
|
-
end
|
|
611
|
-
|
|
612
|
-
def r_id_attributes(id)
|
|
613
|
-
['r:id', "rId#{id}"]
|
|
614
|
-
end
|
|
615
|
-
|
|
616
|
-
def write_xml_declaration
|
|
617
|
-
@writer.xml_decl
|
|
618
|
-
yield
|
|
619
|
-
@writer.crlf
|
|
620
|
-
@writer.close
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
#
|
|
624
|
-
# Convert user defined line properties to the structure required internally.
|
|
625
|
-
#
|
|
626
|
-
def line_properties(line) # :nodoc:
|
|
627
|
-
line_fill_properties(line) do
|
|
628
|
-
value_or_raise(dash_types, line[:dash_type], 'dash type')
|
|
629
|
-
end
|
|
630
|
-
end
|
|
631
|
-
|
|
632
|
-
#
|
|
633
|
-
# Convert user defined fill properties to the structure required internally.
|
|
634
|
-
#
|
|
635
|
-
def fill_properties(fill) # :nodoc:
|
|
636
|
-
line_fill_properties(fill)
|
|
637
|
-
end
|
|
638
|
-
|
|
639
|
-
#
|
|
640
|
-
# Convert user defined pattern properties to the structure required internally.
|
|
641
|
-
#
|
|
642
|
-
def pattern_properties(args) # :nodoc:
|
|
643
|
-
pattern = {}
|
|
644
|
-
|
|
645
|
-
return nil unless args
|
|
646
|
-
|
|
647
|
-
# Check the pattern type is present.
|
|
648
|
-
return nil unless args.has_key?(:pattern)
|
|
649
|
-
|
|
650
|
-
# Check the foreground color is present.
|
|
651
|
-
retuen nil unless args.has_key?(:fg_color)
|
|
652
|
-
|
|
653
|
-
types = {
|
|
654
|
-
'percent_5' => 'pct5',
|
|
655
|
-
'percent_10' => 'pct10',
|
|
656
|
-
'percent_20' => 'pct20',
|
|
657
|
-
'percent_25' => 'pct25',
|
|
658
|
-
'percent_30' => 'pct30',
|
|
659
|
-
'percent_40' => 'pct40',
|
|
660
|
-
|
|
661
|
-
'percent_50' => 'pct50',
|
|
662
|
-
'percent_60' => 'pct60',
|
|
663
|
-
'percent_70' => 'pct70',
|
|
664
|
-
'percent_75' => 'pct75',
|
|
665
|
-
'percent_80' => 'pct80',
|
|
666
|
-
'percent_90' => 'pct90',
|
|
667
|
-
|
|
668
|
-
'light_downward_diagonal' => 'ltDnDiag',
|
|
669
|
-
'light_upward_diagonal' => 'ltUpDiag',
|
|
670
|
-
'dark_downward_diagonal' => 'dkDnDiag',
|
|
671
|
-
'dark_upward_diagonal' => 'dkUpDiag',
|
|
672
|
-
'wide_downward_diagonal' => 'wdDnDiag',
|
|
673
|
-
'wide_upward_diagonal' => 'wdUpDiag',
|
|
674
|
-
|
|
675
|
-
'light_vertical' => 'ltVert',
|
|
676
|
-
'light_horizontal' => 'ltHorz',
|
|
677
|
-
'narrow_vertical' => 'narVert',
|
|
678
|
-
'narrow_horizontal' => 'narHorz',
|
|
679
|
-
'dark_vertical' => 'dkVert',
|
|
680
|
-
'dark_horizontal' => 'dkHorz',
|
|
681
|
-
|
|
682
|
-
'dashed_downward_diagonal' => 'dashDnDiag',
|
|
683
|
-
'dashed_upward_diagonal' => 'dashUpDiag',
|
|
684
|
-
'dashed_horizontal' => 'dashHorz',
|
|
685
|
-
'dashed_vertical' => 'dashVert',
|
|
686
|
-
'small_confetti' => 'smConfetti',
|
|
687
|
-
'large_confetti' => 'lgConfetti',
|
|
688
|
-
|
|
689
|
-
'zigzag' => 'zigZag',
|
|
690
|
-
'wave' => 'wave',
|
|
691
|
-
'diagonal_brick' => 'diagBrick',
|
|
692
|
-
'horizontal_brick' => 'horzBrick',
|
|
693
|
-
'weave' => 'weave',
|
|
694
|
-
'plaid' => 'plaid',
|
|
695
|
-
|
|
696
|
-
'divot' => 'divot',
|
|
697
|
-
'dotted_grid' => 'dotGrid',
|
|
698
|
-
'dotted_diamond' => 'dotDmnd',
|
|
699
|
-
'shingle' => 'shingle',
|
|
700
|
-
'trellis' => 'trellis',
|
|
701
|
-
'sphere' => 'sphere',
|
|
702
|
-
|
|
703
|
-
'small_grid' => 'smGrid',
|
|
704
|
-
'large_grid' => 'lgGrid',
|
|
705
|
-
'small_check' => 'smCheck',
|
|
706
|
-
'large_check' => 'lgCheck',
|
|
707
|
-
'outlined_diamond' => 'openDmnd',
|
|
708
|
-
'solid_diamond' => 'solidDmnd'
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
# Check for valid types.
|
|
712
|
-
if types[args[:pattern]]
|
|
713
|
-
pattern[:pattern] = types[args[:pattern]]
|
|
714
|
-
else
|
|
715
|
-
raise "Unknown pattern type '#{args[:pattern]}'"
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
pattern[:bg_color] = args[:bg_color] || '#FFFFFF'
|
|
719
|
-
pattern[:fg_color] = args[:fg_color]
|
|
720
|
-
|
|
721
|
-
pattern
|
|
722
|
-
end
|
|
723
|
-
|
|
724
|
-
def line_fill_properties(params)
|
|
725
|
-
return { _defined: 0 } unless params
|
|
726
|
-
|
|
727
|
-
ret = params.dup
|
|
728
|
-
ret[:dash_type] = yield if block_given? && ret[:dash_type]
|
|
729
|
-
ret[:_defined] = 1
|
|
730
|
-
ret
|
|
731
|
-
end
|
|
732
|
-
|
|
733
|
-
def dash_types
|
|
734
|
-
{
|
|
735
|
-
solid: 'solid',
|
|
736
|
-
round_dot: 'sysDot',
|
|
737
|
-
square_dot: 'sysDash',
|
|
738
|
-
dash: 'dash',
|
|
739
|
-
dash_dot: 'dashDot',
|
|
740
|
-
long_dash: 'lgDash',
|
|
741
|
-
long_dash_dot: 'lgDashDot',
|
|
742
|
-
long_dash_dot_dot: 'lgDashDotDot',
|
|
743
|
-
dot: 'dot',
|
|
744
|
-
system_dash_dot: 'sysDashDot',
|
|
745
|
-
system_dash_dot_dot: 'sysDashDotDot'
|
|
746
|
-
}
|
|
747
|
-
end
|
|
748
|
-
|
|
749
|
-
def value_or_raise(hash, key, msg)
|
|
750
|
-
raise "Unknown #{msg} '#{key}'" if hash[key.to_sym].nil?
|
|
751
|
-
|
|
752
|
-
hash[key.to_sym]
|
|
753
|
-
end
|
|
754
|
-
|
|
755
|
-
def palette_color_from_index(index)
|
|
756
|
-
# Adjust the colour index.
|
|
757
|
-
idx = index - 8
|
|
758
|
-
|
|
759
|
-
r, g, b = @palette[idx]
|
|
760
|
-
sprintf("%02X%02X%02X", r, g, b)
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
#
|
|
764
|
-
# Convert user defined font values into private hash values.
|
|
765
|
-
#
|
|
766
|
-
def convert_font_args(params)
|
|
767
|
-
return unless params
|
|
768
|
-
|
|
769
|
-
font = params_to_font(params)
|
|
770
|
-
|
|
771
|
-
# Convert font size units.
|
|
772
|
-
font[:_size] *= 100 if font[:_size] && font[:_size] != 0
|
|
773
|
-
|
|
774
|
-
# Convert rotation into 60,000ths of a degree.
|
|
775
|
-
font[:_rotation] = 60_000 * font[:_rotation].to_i if ptrue?(font[:_rotation])
|
|
776
|
-
|
|
777
|
-
font
|
|
778
|
-
end
|
|
779
|
-
|
|
780
|
-
def params_to_font(params)
|
|
781
|
-
{
|
|
782
|
-
_name: params[:name],
|
|
783
|
-
_color: params[:color],
|
|
784
|
-
_size: params[:size],
|
|
785
|
-
_bold: params[:bold],
|
|
786
|
-
_italic: params[:italic],
|
|
787
|
-
_underline: params[:underline],
|
|
788
|
-
_pitch_family: params[:pitch_family],
|
|
789
|
-
_charset: params[:charset],
|
|
790
|
-
_baseline: params[:baseline] || 0,
|
|
791
|
-
_rotation: params[:rotation]
|
|
792
|
-
}
|
|
793
|
-
end
|
|
794
|
-
|
|
795
|
-
#
|
|
796
|
-
# Write the <c:txPr> element.
|
|
797
|
-
#
|
|
798
|
-
def write_tx_pr(font, is_y_axis = nil) # :nodoc:
|
|
799
|
-
rotation = nil
|
|
800
|
-
rotation = font[:_rotation] if font && font.respond_to?(:[]) && font[:_rotation]
|
|
801
|
-
@writer.tag_elements('c:txPr') do
|
|
802
|
-
# Write the a:bodyPr element.
|
|
803
|
-
write_a_body_pr(rotation, is_y_axis)
|
|
804
|
-
# Write the a:lstStyle element.
|
|
805
|
-
write_a_lst_style
|
|
806
|
-
# Write the a:p element.
|
|
807
|
-
write_a_p_formula(font)
|
|
808
|
-
end
|
|
809
|
-
end
|
|
810
|
-
|
|
811
|
-
#
|
|
812
|
-
# Write the <a:bodyPr> element.
|
|
813
|
-
#
|
|
814
|
-
def write_a_body_pr(rot, is_y_axis = nil) # :nodoc:
|
|
815
|
-
rot = -5400000 if !rot && ptrue?(is_y_axis)
|
|
816
|
-
attributes = []
|
|
817
|
-
if rot
|
|
818
|
-
if rot == 16_200_000
|
|
819
|
-
# 270 deg/stacked angle.
|
|
820
|
-
attributes << ['rot', 0]
|
|
821
|
-
attributes << %w[vert wordArtVert]
|
|
822
|
-
elsif rot == 16_260_000
|
|
823
|
-
# 271 deg/stacked angle.
|
|
824
|
-
attributes << ['rot', 0]
|
|
825
|
-
attributes << %w[vert eaVert]
|
|
826
|
-
else
|
|
827
|
-
attributes << ['rot', rot]
|
|
828
|
-
attributes << %w[vert horz]
|
|
829
|
-
end
|
|
830
|
-
end
|
|
831
|
-
|
|
832
|
-
@writer.empty_tag('a:bodyPr', attributes)
|
|
833
|
-
end
|
|
834
|
-
|
|
835
|
-
#
|
|
836
|
-
# Write the <a:lstStyle> element.
|
|
837
|
-
#
|
|
838
|
-
def write_a_lst_style # :nodoc:
|
|
839
|
-
@writer.empty_tag('a:lstStyle')
|
|
840
|
-
end
|
|
841
|
-
|
|
842
|
-
#
|
|
843
|
-
# Write the <a:p> element for formula titles.
|
|
844
|
-
#
|
|
845
|
-
def write_a_p_formula(font = nil) # :nodoc:
|
|
846
|
-
@writer.tag_elements('a:p') do
|
|
847
|
-
# Write the a:pPr element.
|
|
848
|
-
write_a_p_pr_formula(font)
|
|
849
|
-
# Write the a:endParaRPr element.
|
|
850
|
-
write_a_end_para_rpr
|
|
851
|
-
end
|
|
852
|
-
end
|
|
853
|
-
|
|
854
|
-
#
|
|
855
|
-
# Write the <a:pPr> element for formula titles.
|
|
856
|
-
#
|
|
857
|
-
def write_a_p_pr_formula(font) # :nodoc:
|
|
858
|
-
@writer.tag_elements('a:pPr') { write_a_def_rpr(font) }
|
|
859
|
-
end
|
|
860
|
-
|
|
861
|
-
#
|
|
862
|
-
# Write the <a:defRPr> element.
|
|
863
|
-
#
|
|
864
|
-
def write_a_def_rpr(font = nil) # :nodoc:
|
|
865
|
-
write_def_rpr_r_pr_common(
|
|
866
|
-
font,
|
|
867
|
-
get_font_style_attributes(font),
|
|
868
|
-
'a:defRPr'
|
|
869
|
-
)
|
|
870
|
-
end
|
|
871
|
-
|
|
872
|
-
def write_def_rpr_r_pr_common(font, style_attributes, tag) # :nodoc:
|
|
873
|
-
latin_attributes = get_font_latin_attributes(font)
|
|
874
|
-
has_color = ptrue?(font) && ptrue?(font[:_color])
|
|
875
|
-
|
|
876
|
-
if !latin_attributes.empty? || has_color
|
|
877
|
-
@writer.tag_elements(tag, style_attributes) do
|
|
878
|
-
write_a_solid_fill(color: font[:_color]) if has_color
|
|
879
|
-
write_a_latin(latin_attributes) unless latin_attributes.empty?
|
|
880
|
-
end
|
|
881
|
-
else
|
|
882
|
-
@writer.empty_tag(tag, style_attributes)
|
|
883
|
-
end
|
|
884
|
-
end
|
|
885
|
-
|
|
886
|
-
#
|
|
887
|
-
# Get the font latin attributes from a font hash.
|
|
888
|
-
#
|
|
889
|
-
def get_font_latin_attributes(font)
|
|
890
|
-
return [] unless font
|
|
891
|
-
return [] unless font.respond_to?(:[])
|
|
892
|
-
|
|
893
|
-
attributes = []
|
|
894
|
-
attributes << ['typeface', font[:_name]] if ptrue?(font[:_name])
|
|
895
|
-
attributes << ['pitchFamily', font[:_pitch_family]] if font[:_pitch_family]
|
|
896
|
-
attributes << ['charset', font[:_charset]] if font[:_charset]
|
|
897
|
-
|
|
898
|
-
attributes
|
|
899
|
-
end
|
|
900
|
-
|
|
901
|
-
#
|
|
902
|
-
# Write the <a:solidFill> element.
|
|
903
|
-
#
|
|
904
|
-
def write_a_solid_fill(fill) # :nodoc:
|
|
905
|
-
@writer.tag_elements('a:solidFill') do
|
|
906
|
-
if fill[:color]
|
|
907
|
-
# Write the a:srgbClr element.
|
|
908
|
-
write_a_srgb_clr(color(fill[:color]), fill[:transparency])
|
|
909
|
-
end
|
|
910
|
-
end
|
|
911
|
-
end
|
|
912
|
-
|
|
913
|
-
#
|
|
914
|
-
# Write the <a:srgbClr> element.
|
|
915
|
-
#
|
|
916
|
-
def write_a_srgb_clr(color, transparency = nil) # :nodoc:
|
|
917
|
-
tag = 'a:srgbClr'
|
|
918
|
-
attributes = [['val', color]]
|
|
919
|
-
|
|
920
|
-
if ptrue?(transparency)
|
|
921
|
-
@writer.tag_elements(tag, attributes) do
|
|
922
|
-
write_a_alpha(transparency)
|
|
923
|
-
end
|
|
924
|
-
else
|
|
925
|
-
@writer.empty_tag(tag, attributes)
|
|
926
|
-
end
|
|
927
|
-
end
|
|
928
|
-
|
|
929
|
-
#
|
|
930
|
-
# Convert the user specified colour index or string to a rgb colour.
|
|
931
|
-
#
|
|
932
|
-
def color(color_code) # :nodoc:
|
|
933
|
-
if color_code and color_code =~ /^#[0-9a-fA-F]{6}$/
|
|
934
|
-
# Convert a HTML style #RRGGBB color.
|
|
935
|
-
color_code.sub(/^#/, '').upcase
|
|
936
|
-
else
|
|
937
|
-
index = Format.color(color_code)
|
|
938
|
-
raise "Unknown color '#{color_code}' used in chart formatting." unless index
|
|
939
|
-
|
|
940
|
-
palette_color_from_index(index)
|
|
941
|
-
end
|
|
942
|
-
end
|
|
943
|
-
|
|
944
|
-
#
|
|
945
|
-
# Get the font style attributes from a font hash.
|
|
946
|
-
#
|
|
947
|
-
def get_font_style_attributes(font)
|
|
948
|
-
return [] unless font
|
|
949
|
-
return [] unless font.respond_to?(:[])
|
|
950
|
-
|
|
951
|
-
attributes = []
|
|
952
|
-
attributes << ['sz', font[:_size]] if ptrue?(font[:_size])
|
|
953
|
-
attributes << ['b', font[:_bold]] if font[:_bold]
|
|
954
|
-
attributes << ['i', font[:_italic]] if font[:_italic]
|
|
955
|
-
attributes << %w[u sng] if font[:_underline]
|
|
956
|
-
|
|
957
|
-
# Turn off baseline when testing fonts that don't have it.
|
|
958
|
-
attributes << ['baseline', font[:_baseline]] if font[:_baseline] != -1
|
|
959
|
-
attributes
|
|
960
|
-
end
|
|
961
|
-
|
|
962
|
-
#
|
|
963
|
-
# Write the <a:endParaRPr> element.
|
|
964
|
-
#
|
|
965
|
-
def write_a_end_para_rpr # :nodoc:
|
|
966
|
-
@writer.empty_tag('a:endParaRPr', [%w[lang en-US]])
|
|
967
|
-
end
|
|
968
|
-
end
|
|
969
|
-
|
|
970
|
-
module WriteDPtPoint
|
|
971
|
-
#
|
|
972
|
-
# Write an individual <c:dPt> element. Override the parent method to add
|
|
973
|
-
# markers.
|
|
974
|
-
#
|
|
975
|
-
def write_d_pt_point(index, point)
|
|
976
|
-
@writer.tag_elements('c:dPt') do
|
|
977
|
-
# Write the c:idx element.
|
|
978
|
-
write_idx(index)
|
|
979
|
-
@writer.tag_elements('c:marker') do
|
|
980
|
-
# Write the c:spPr element.
|
|
981
|
-
write_sp_pr(point)
|
|
982
|
-
end
|
|
983
|
-
end
|
|
984
|
-
end
|
|
985
|
-
end
|
|
986
|
-
end
|