write_xlsx 0.70.0 → 0.71.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/.gitignore +1 -0
- data/README.rdoc +7 -1
- data/lib/write_xlsx/chart.rb +133 -1713
- data/lib/write_xlsx/chart/axis.rb +6 -8
- data/lib/write_xlsx/chart/caption.rb +19 -0
- data/lib/write_xlsx/chart/scatter.rb +15 -15
- data/lib/write_xlsx/chart/series.rb +307 -0
- data/lib/write_xlsx/chart/stock.rb +5 -5
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +1 -1
- data/lib/write_xlsx/worksheet.rb +2 -2
- data/test/chart/test_add_series.rb +113 -115
- data/test/chart/test_write_d_lbls.rb +19 -18
- data/test/chart/test_write_number_format.rb +4 -4
- data/test/helper.rb +13 -0
- data/test/perl_output/comments2.xlsx +0 -0
- data/test/perl_output/demo.xlsx +0 -0
- data/test/regression/images/issue32.jpg +0 -0
- data/test/regression/images/issue32.png +0 -0
- data/test/regression/images/logo.png +0 -0
- data/test/regression/images/mylogo.png +0 -0
- data/test/regression/test_chart_area04.rb +44 -0
- data/test/regression/test_chart_bar24.rb +1 -2
- data/test/regression/test_chart_column04.rb +1 -1
- data/test/regression/test_chart_line02.rb +1 -1
- data/test/regression/test_chart_scatter07.rb +1 -1
- data/test/regression/test_chart_stock02.rb +1 -1
- data/test/regression/test_image10.rb +24 -0
- data/test/regression/test_image11.rb +24 -0
- data/test/regression/test_image12.rb +27 -0
- data/test/regression/test_image13.rb +27 -0
- data/test/regression/test_image14.rb +29 -0
- data/test/regression/test_image15.rb +29 -0
- data/test/regression/test_image16.rb +24 -0
- data/test/regression/test_image17.rb +27 -0
- data/test/regression/test_image18.rb +27 -0
- data/test/regression/xlsx_files/image10.xlsx +0 -0
- data/test/regression/xlsx_files/image11.xlsx +0 -0
- data/test/regression/xlsx_files/image12.xlsx +0 -0
- data/test/regression/xlsx_files/image13.xlsx +0 -0
- data/test/regression/xlsx_files/image14.xlsx +0 -0
- data/test/regression/xlsx_files/image15.xlsx +0 -0
- data/test/regression/xlsx_files/image16.xlsx +0 -0
- data/test/regression/xlsx_files/image17.xlsx +0 -0
- data/test/regression/xlsx_files/image18.xlsx +0 -0
- data/test/republic.png +0 -0
- data/test/test_example_match.rb +2 -4
- data/test/workbook/test_workbook_01.rb +1 -1
- data/test/workbook/test_workbook_02.rb +1 -1
- data/test/workbook/test_workbook_03.rb +1 -1
- data/write_xlsx.gemspec +1 -1
- metadata +53 -30
- data/html/en/doc_en.html +0 -7765
- data/html/index.html +0 -16
- data/html/style.css +0 -433
@@ -1,28 +1,27 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require 'write_xlsx/package/xml_writer_simple'
|
3
3
|
require 'write_xlsx/utility'
|
4
|
+
require 'write_xlsx/chart/caption'
|
4
5
|
|
5
6
|
module Writexlsx
|
6
7
|
class Chart
|
7
|
-
class Axis
|
8
|
+
class Axis < Caption
|
8
9
|
include Writexlsx::Utility
|
9
10
|
|
10
|
-
attr_accessor :defaults, :
|
11
|
+
attr_accessor :defaults, :reverse
|
11
12
|
attr_accessor :min, :max
|
12
13
|
attr_accessor :minor_unit, :major_unit, :minor_unit_type, :major_unit_type
|
13
14
|
attr_accessor :log_base, :crossing, :position, :label_position, :visible
|
14
|
-
attr_accessor :num_format, :num_format_linked, :num_font
|
15
|
+
attr_accessor :num_format, :num_format_linked, :num_font
|
15
16
|
attr_accessor :major_gridlines, :minor_gridlines, :major_tick_mark
|
16
17
|
|
17
18
|
#
|
18
19
|
# Convert user defined axis values into axis instance.
|
19
20
|
#
|
20
|
-
def merge_with_hash(
|
21
|
-
|
21
|
+
def merge_with_hash(params) # :nodoc:
|
22
|
+
super
|
22
23
|
args = (defaults || {}).merge(params)
|
23
24
|
|
24
|
-
@name, @formula = @chart.process_names(args[:name], args[:name_formula])
|
25
|
-
@data_id = @chart.get_data_id(@formula, args[:data])
|
26
25
|
@reverse = args[:reverse]
|
27
26
|
@min = args[:min]
|
28
27
|
@max = args[:max]
|
@@ -53,7 +52,6 @@ def merge_with_hash(chart, params) # :nodoc:
|
|
53
52
|
|
54
53
|
# Set the font properties if present.
|
55
54
|
@num_font = @chart.convert_font_args(args[:num_font])
|
56
|
-
@name_font = @chart.convert_font_args(args[:name_font])
|
57
55
|
end
|
58
56
|
|
59
57
|
#
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module Writexlsx
|
4
|
+
class Chart
|
5
|
+
class Caption
|
6
|
+
attr_accessor :name, :formula, :data_id, :name_font
|
7
|
+
|
8
|
+
def initialize(chart)
|
9
|
+
@chart = chart
|
10
|
+
end
|
11
|
+
|
12
|
+
def merge_with_hash(params) # :nodoc:
|
13
|
+
@name, @formula = @chart.process_names(params[:name], params[:name_formula])
|
14
|
+
@data_id = @chart.get_data_id(@formula, params[:data])
|
15
|
+
@name_font = @chart.convert_font_args(params[:name_font])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -110,24 +110,24 @@ def write_ser(series)
|
|
110
110
|
# Write the c:spPr element.
|
111
111
|
write_sp_pr(series)
|
112
112
|
# Write the c:marker element.
|
113
|
-
write_marker(series
|
113
|
+
write_marker(series.marker)
|
114
114
|
# Write the c:dPt element.
|
115
|
-
write_d_pt(series
|
115
|
+
write_d_pt(series.points)
|
116
116
|
# Write the c:dLbls element.
|
117
|
-
write_d_lbls(series
|
117
|
+
write_d_lbls(series.labels)
|
118
118
|
# Write the c:trendline element.
|
119
|
-
write_trendline(series
|
119
|
+
write_trendline(series.trendline)
|
120
120
|
# Write the c:errBars element.
|
121
|
-
write_error_bars(series
|
121
|
+
write_error_bars(series.error_bars)
|
122
122
|
# Write the c:xVal element.
|
123
123
|
write_x_val(series)
|
124
124
|
# Write the c:yVal element.
|
125
125
|
write_y_val(series)
|
126
126
|
# Write the c:smooth element.
|
127
|
-
if @subtype =~ /smooth/ && !series
|
127
|
+
if @subtype =~ /smooth/ && !series.smooth
|
128
128
|
write_c_smooth(1)
|
129
129
|
else
|
130
|
-
write_c_smooth(series
|
130
|
+
write_c_smooth(series.smooth)
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -188,8 +188,8 @@ def write_plot_area
|
|
188
188
|
# Write the <c:xVal> element.
|
189
189
|
#
|
190
190
|
def write_x_val(series)
|
191
|
-
formula = series
|
192
|
-
data_id = series
|
191
|
+
formula = series.categories
|
192
|
+
data_id = series.cat_data_id
|
193
193
|
data = @formula_data[data_id]
|
194
194
|
|
195
195
|
@writer.tag_elements('c:xVal') do
|
@@ -211,8 +211,8 @@ def write_x_val(series)
|
|
211
211
|
# Write the <c:yVal> element.
|
212
212
|
#
|
213
213
|
def write_y_val(series)
|
214
|
-
formula = series
|
215
|
-
data_id = series
|
214
|
+
formula = series.values
|
215
|
+
data_id = series.val_data_id
|
216
216
|
data = @formula_data[data_id]
|
217
217
|
|
218
218
|
@writer.tag_elements('c:yVal') do
|
@@ -244,8 +244,8 @@ def modify_series_formatting
|
|
244
244
|
# Go through each series and define default values.
|
245
245
|
@series.each do |series|
|
246
246
|
# Set a line type unless there is already a user defined type.
|
247
|
-
if series[:
|
248
|
-
series
|
247
|
+
if series.line[:_defined] == 0
|
248
|
+
series.line = { :width => 2.25, :none => 1, :_defined => 1 }
|
249
249
|
end
|
250
250
|
end
|
251
251
|
end
|
@@ -255,8 +255,8 @@ def modify_series_formatting
|
|
255
255
|
# Go through each series and define default values.
|
256
256
|
@series.each do |series|
|
257
257
|
# Set a marker type unless there is already a user defined type.
|
258
|
-
if !series
|
259
|
-
series
|
258
|
+
if !series.marker || series.marker[:_defined] == 0
|
259
|
+
series.marker = { :type => 'none', :_defined => 1 }
|
260
260
|
end
|
261
261
|
end
|
262
262
|
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
class Series
|
4
|
+
include Writexlsx::Utility
|
5
|
+
|
6
|
+
attr_reader :values, :categories, :name, :name_formula, :name_id
|
7
|
+
attr_reader :cat_data_id, :val_data_id, :fill
|
8
|
+
attr_reader :trendline, :smooth, :labels, :invert_if_neg
|
9
|
+
attr_reader :x2_axis, :y2_axis, :error_bars, :points
|
10
|
+
attr_accessor :line, :marker
|
11
|
+
|
12
|
+
def initialize(chart, params = {})
|
13
|
+
@values = aref_to_formula(params[:values])
|
14
|
+
@categories = aref_to_formula(params[:categories])
|
15
|
+
@name, @name_formula =
|
16
|
+
chart.process_names(params[:name], params[:name_formula])
|
17
|
+
@cat_data_id = chart.get_data_id(@categories, params[:categories_data])
|
18
|
+
@val_data_id = chart.get_data_id(@values, params[:values_data])
|
19
|
+
@name_id = chart.get_data_id(@name_formula, params[:name_data])
|
20
|
+
if params[:border]
|
21
|
+
@line = line_properties(params[:border])
|
22
|
+
else
|
23
|
+
@line = line_properties(params[:line])
|
24
|
+
end
|
25
|
+
@fill = fill_properties(params[:fill])
|
26
|
+
@marker = marker_properties(params[:marker])
|
27
|
+
@trendline = trendline_properties(params[:trendline])
|
28
|
+
@smooth = params[:smooth]
|
29
|
+
@error_bars = {
|
30
|
+
:_x_error_bars => error_bars_properties(params[:x_error_bars]),
|
31
|
+
:_y_error_bars => error_bars_properties(params[:y_error_bars])
|
32
|
+
}
|
33
|
+
@points = points_properties(params[:points])
|
34
|
+
@labels = labels_properties(params[:data_labels])
|
35
|
+
@invert_if_neg = params[:invert_if_negative]
|
36
|
+
@x2_axis = params[:x2_axis]
|
37
|
+
@y2_axis = params[:y2_axis]
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
methods = %w[categories values name name_formula name_id
|
42
|
+
cat_data_id val_data_id
|
43
|
+
line fill marker trendline
|
44
|
+
smooth labels invert_if_neg x2_axis y2_axis error_bars points ]
|
45
|
+
methods.each do |method|
|
46
|
+
return false unless self.instance_variable_get("@#{method}") == other.instance_variable_get("@#{method}")
|
47
|
+
end
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
#
|
54
|
+
# Convert and aref of row col values to a range formula.
|
55
|
+
#
|
56
|
+
def aref_to_formula(data) # :nodoc:
|
57
|
+
# If it isn't an array ref it is probably a formula already.
|
58
|
+
return data unless data.kind_of?(Array)
|
59
|
+
xl_range_formula(*data)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Convert user defined line properties to the structure required internally.
|
64
|
+
#
|
65
|
+
def line_properties(line) # :nodoc:
|
66
|
+
return { :_defined => 0 } unless line
|
67
|
+
|
68
|
+
dash_types = {
|
69
|
+
:solid => 'solid',
|
70
|
+
:round_dot => 'sysDot',
|
71
|
+
:square_dot => 'sysDash',
|
72
|
+
:dash => 'dash',
|
73
|
+
:dash_dot => 'dashDot',
|
74
|
+
:long_dash => 'lgDash',
|
75
|
+
:long_dash_dot => 'lgDashDot',
|
76
|
+
:long_dash_dot_dot => 'lgDashDotDot',
|
77
|
+
:dot => 'dot',
|
78
|
+
:system_dash_dot => 'sysDashDot',
|
79
|
+
:system_dash_dot_dot => 'sysDashDotDot'
|
80
|
+
}
|
81
|
+
|
82
|
+
# Check the dash type.
|
83
|
+
dash_type = line[:dash_type]
|
84
|
+
|
85
|
+
if dash_type
|
86
|
+
line[:dash_type] = value_or_raise(dash_types, dash_type, 'dash type')
|
87
|
+
end
|
88
|
+
|
89
|
+
line[:_defined] = 1
|
90
|
+
|
91
|
+
line
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Convert user defined fill properties to the structure required internally.
|
96
|
+
#
|
97
|
+
def fill_properties(fill) # :nodoc:
|
98
|
+
return { :_defined => 0 } unless fill
|
99
|
+
|
100
|
+
fill[:_defined] = 1
|
101
|
+
|
102
|
+
fill
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Convert user defined marker properties to the structure required internally.
|
107
|
+
#
|
108
|
+
def marker_properties(marker) # :nodoc:
|
109
|
+
return unless marker
|
110
|
+
|
111
|
+
types = {
|
112
|
+
:automatic => 'automatic',
|
113
|
+
:none => 'none',
|
114
|
+
:square => 'square',
|
115
|
+
:diamond => 'diamond',
|
116
|
+
:triangle => 'triangle',
|
117
|
+
:x => 'x',
|
118
|
+
:star => 'start',
|
119
|
+
:dot => 'dot',
|
120
|
+
:short_dash => 'dot',
|
121
|
+
:dash => 'dash',
|
122
|
+
:long_dash => 'dash',
|
123
|
+
:circle => 'circle',
|
124
|
+
:plus => 'plus',
|
125
|
+
:picture => 'picture'
|
126
|
+
}
|
127
|
+
|
128
|
+
# Check for valid types.
|
129
|
+
marker_type = marker[:type]
|
130
|
+
|
131
|
+
if marker_type
|
132
|
+
marker[:automatic] = 1 if marker_type == 'automatic'
|
133
|
+
marker[:type] = value_or_raise(types, marker_type, 'maker type')
|
134
|
+
end
|
135
|
+
|
136
|
+
# Set the line properties for the marker..
|
137
|
+
line = line_properties(marker[:line])
|
138
|
+
|
139
|
+
# Allow 'border' as a synonym for 'line'.
|
140
|
+
line = line_properties(marker[:border]) if marker[:border]
|
141
|
+
|
142
|
+
# Set the fill properties for the marker.
|
143
|
+
fill = fill_properties(marker[:fill])
|
144
|
+
|
145
|
+
marker[:_line] = line
|
146
|
+
marker[:_fill] = fill
|
147
|
+
|
148
|
+
marker
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# Convert user defined trendline properties to the structure required internally.
|
153
|
+
#
|
154
|
+
def trendline_properties(trendline) # :nodoc:
|
155
|
+
return unless trendline
|
156
|
+
|
157
|
+
types = {
|
158
|
+
:exponential => 'exp',
|
159
|
+
:linear => 'linear',
|
160
|
+
:log => 'log',
|
161
|
+
:moving_average => 'movingAvg',
|
162
|
+
:polynomial => 'poly',
|
163
|
+
:power => 'power'
|
164
|
+
}
|
165
|
+
|
166
|
+
# Check the trendline type.
|
167
|
+
trend_type = trendline[:type]
|
168
|
+
|
169
|
+
trendline[:type] = value_or_raise(types, trend_type, 'trendline type')
|
170
|
+
|
171
|
+
# Set the line properties for the trendline..
|
172
|
+
line = line_properties(trendline[:line])
|
173
|
+
|
174
|
+
# Allow 'border' as a synonym for 'line'.
|
175
|
+
line = line_properties(trendline[:border]) if trendline[:border]
|
176
|
+
|
177
|
+
# Set the fill properties for the trendline.
|
178
|
+
fill = fill_properties(trendline[:fill])
|
179
|
+
|
180
|
+
trendline[:_line] = line
|
181
|
+
trendline[:_fill] = fill
|
182
|
+
|
183
|
+
return trendline
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Convert user defined error bars properties to structure required
|
188
|
+
# internally.
|
189
|
+
#
|
190
|
+
def error_bars_properties(params = {})
|
191
|
+
return if !ptrue?(params) || params.empty?
|
192
|
+
|
193
|
+
# Default values.
|
194
|
+
error_bars = {
|
195
|
+
:_type => 'fixedVal',
|
196
|
+
:_value => 1,
|
197
|
+
:_endcap => 1,
|
198
|
+
:_direction => 'both'
|
199
|
+
}
|
200
|
+
|
201
|
+
types = {
|
202
|
+
:fixed => 'fixedVal',
|
203
|
+
:percentage => 'percentage',
|
204
|
+
:standard_deviation => 'stdDev',
|
205
|
+
:standard_error => 'stdErr'
|
206
|
+
}
|
207
|
+
|
208
|
+
# Check the error bars type.
|
209
|
+
error_type = params[:type].to_sym
|
210
|
+
|
211
|
+
if types.key?(error_type)
|
212
|
+
error_bars[:_type] = types[error_type]
|
213
|
+
else
|
214
|
+
raise "Unknown error bars type '#{error_type}'\n"
|
215
|
+
end
|
216
|
+
|
217
|
+
# Set the value for error types that require it.
|
218
|
+
if params.key?(:value)
|
219
|
+
error_bars[:_value] = params[:value]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Set the end-cap style.
|
223
|
+
if params.key?(:end_style)
|
224
|
+
error_bars[:_endcap] = params[:end_style]
|
225
|
+
end
|
226
|
+
|
227
|
+
# Set the error bar direction.
|
228
|
+
if params.key?(:direction)
|
229
|
+
if params[:direction] == 'minus'
|
230
|
+
error_bars[:_direction] = 'minus'
|
231
|
+
elsif params[:direction] == 'plus'
|
232
|
+
error_bars[:_direction] = 'plus'
|
233
|
+
else
|
234
|
+
# Default to 'both'
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Set the line properties for the error bars.
|
239
|
+
error_bars[:_line] = line_properties(params[:line])
|
240
|
+
|
241
|
+
error_bars
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Convert user defined points properties to structure required internally.
|
246
|
+
#
|
247
|
+
def points_properties(user_points = nil)
|
248
|
+
return unless user_points
|
249
|
+
|
250
|
+
points = []
|
251
|
+
user_points.each do |user_point|
|
252
|
+
if user_point
|
253
|
+
# Set the lline properties for the point.
|
254
|
+
line = line_properties(user_point[:line])
|
255
|
+
|
256
|
+
# Allow 'border' as a synonym for 'line'.
|
257
|
+
if user_point[:border]
|
258
|
+
line = line_properties(user_point[:border])
|
259
|
+
end
|
260
|
+
|
261
|
+
# Set the fill properties for the chartarea.
|
262
|
+
fill = fill_properties(user_point[:fill])
|
263
|
+
|
264
|
+
point = {}
|
265
|
+
point[:_line] = line
|
266
|
+
point[:_fill] = fill
|
267
|
+
end
|
268
|
+
points << point
|
269
|
+
end
|
270
|
+
points
|
271
|
+
end
|
272
|
+
|
273
|
+
#
|
274
|
+
# Convert user defined labels properties to the structure required internally.
|
275
|
+
#
|
276
|
+
def labels_properties(labels) # :nodoc:
|
277
|
+
return nil unless labels
|
278
|
+
|
279
|
+
position = labels[:position]
|
280
|
+
if position.nil? || position.empty?
|
281
|
+
labels.delete(:position)
|
282
|
+
else
|
283
|
+
# Map user defined label positions to Excel positions.
|
284
|
+
positions = {
|
285
|
+
:center => 'ctr',
|
286
|
+
:right => 'r',
|
287
|
+
:left => 'l',
|
288
|
+
:top => 't',
|
289
|
+
:above => 't',
|
290
|
+
:bottom => 'b',
|
291
|
+
:below => 'b',
|
292
|
+
:inside_end => 'inEnd',
|
293
|
+
:outside_end => 'outEnd',
|
294
|
+
:best_fit => 'bestFit'
|
295
|
+
}
|
296
|
+
|
297
|
+
labels[:position] = value_or_raise(positions, position, 'label position')
|
298
|
+
end
|
299
|
+
|
300
|
+
labels
|
301
|
+
end
|
302
|
+
|
303
|
+
def value_or_raise(hash, key, msg)
|
304
|
+
raise "Unknown #{msg} '#{key}'" unless hash[key.to_sym]
|
305
|
+
hash[key.to_sym]
|
306
|
+
end
|
307
|
+
end
|
@@ -95,19 +95,19 @@ def modify_series_formatting
|
|
95
95
|
array = []
|
96
96
|
@series.each do |series|
|
97
97
|
if index % 4 != 3
|
98
|
-
if series[:
|
99
|
-
series
|
98
|
+
if series.line[:_defined].nil? || series.line[:_defined] == 0
|
99
|
+
series.line = {
|
100
100
|
:width => 2.25,
|
101
101
|
:none => 1,
|
102
102
|
:_defined => 1
|
103
103
|
}
|
104
104
|
end
|
105
105
|
|
106
|
-
if series
|
106
|
+
if series.marker.nil? || series.marker == 0
|
107
107
|
if index % 4 == 2
|
108
|
-
series
|
108
|
+
series.marker = { :type => 'dot', :size => 3 }
|
109
109
|
else
|
110
|
-
series
|
110
|
+
series.marker = { :type => 'none' }
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|