lib/write_xlsx/chart.rb in write_xlsx-0.81.1 vs lib/write_xlsx/chart.rb in write_xlsx-0.83.0
- old
+ new
@@ -139,11 +139,15 @@
attr_accessor :id, :name # :nodoc:
attr_writer :index, :palette, :protection # :nodoc:
attr_reader :embedded, :formula_ids, :formula_data # :nodoc:
attr_reader :x_scale, :y_scale, :x_offset, :y_offset # :nodoc:
attr_reader :width, :height # :nodoc:
- attr_reader :label_positions, :label_position_default
+ attr_reader :label_positions, :label_position_default, :combined # :nodoc:
+ attr_writer :date_category, :already_inserted
+ attr_writer :series_index
+ attr_writer :writer
+ attr_reader :x2_axis, :y2_axis, :axis2_ids
#
# Factory method for returning chart objects based on their class type.
#
def self.factory(current_subclass, subtype = nil) # :nodoc:
@@ -183,11 +187,11 @@
@subtype = subtype
@sheet_type = 0x0200
@series = []
@embedded = 0
- @id = ''
+ @id = -1
@series_index = 0
@style_id = 2
@formula_ids = {}
@formula_data = []
@protection = 0
@@ -195,10 +199,12 @@
@plotarea = ChartArea.new
@title = Caption.new(self)
@name = ''
@table = nil
set_default_properties
+ @combined = nil
+ @is_secondary = false
end
def set_xml_writer(filename) # :nodoc:
@writer.set_xml_writer(filename)
end
@@ -243,10 +249,15 @@
# Set the secondary axis properties.
x2_axis = params[:x2_axis]
y2_axis = params[:y2_axis]
+ # Store secondary status for combined charts.
+ if ptrue?(x2_axis) || ptrue?(y2_axis)
+ @is_secondary = true
+ end
+
# Set the gap and overlap for Bar/Column charts.
if params[:gap]
if ptrue?(y2_axis)
@series_gap_2 = params[:gap]
else
@@ -340,11 +351,11 @@
#
# Set on of the 42 built-in Excel chart styles. The default style is 2.
#
def set_style(style_id = 2)
- style_id = 2 if style_id < 0 || style_id > 42
+ style_id = 2 if style_id < 0 || style_id > 48
@style_id = style_id
end
#
# Set the option for displaying blank data in a chart. The default is 'gap'.
@@ -422,10 +433,17 @@
def set_high_low_lines(params = {})
@hi_low_lines = Chartline.new(params)
end
#
+ # Add another chart to create a combined chart.
+ #
+ def combine(chart)
+ @combined = chart
+ end
+
+ #
# Setup the default configuration data for an embedded chart.
#
def set_embedded_config_data
@embedded = 1
end
@@ -516,11 +534,16 @@
#
# Switch name and name_formula parameters if required.
#
def process_names(name = nil, name_formula = nil) # :nodoc:
# Name looks like a formula, use it to set name_formula.
- if name && name =~ /^=[^!]+!\$/
+ if name.respond_to?(:to_ary)
+ cell = xl_rowcol_to_cell(name[1], name[2], 1, 1)
+ name_formula = "#{quote_sheetname(name[0])}!#{cell}"
+ name = ''
+ elsif
+ name && name =~ /^=[^!]+!\$/
name_formula = name
name = ''
end
[name, name_formula]
@@ -554,10 +577,18 @@
end
id
end
+ def already_inserted?
+ @already_inserted
+ end
+
+ def is_secondary?
+ @is_secondary
+ end
+
private
def axis_setup
@axis_ids = []
@axis2_ids = []
@@ -661,15 +692,15 @@
@axis2_ids += ids
end
end
def ids
- chart_id = 1 + @id
+ chart_id = 5001 + @id
axis_count = 1 + @axis2_ids.size + @axis_ids.size
- id1 = sprintf('5%03d%04d', chart_id, axis_count)
- id2 = sprintf('5%03d%04d', chart_id, axis_count + 1)
+ id1 = sprintf('%04d%04d', chart_id, axis_count)
+ id2 = sprintf('%04d%04d', chart_id, axis_count + 1)
[id1, id2]
end
#
@@ -830,17 +861,39 @@
#
# Write the <c:plotArea> element.
#
def write_plot_area # :nodoc:
+ second_chart = @combined
@writer.tag_elements('c:plotArea') do
# Write the c:layout element.
write_layout(@plotarea.layout, 'plot')
# Write the subclass chart type elements for primary and secondary axes.
write_chart_type(:primary_axes => 1)
write_chart_type(:primary_axes => 0)
+ # Configure a combined chart if present.
+ if second_chart
+
+ # Secondary axis has unique id otherwise use same as primary.
+ if second_chart.is_secondary?
+ second_chart.id = 1000 + @id
+ else
+ second_chart.id = @id
+ end
+
+ # Share the same writer for writing.
+ second_chart.writer = @writer
+
+ # Share series index with primary chart.
+ second_chart.series_index = @series_index
+
+ # Write the subclass chart type elements for combined chart.
+ second_chart.write_chart_type(:primary_axes => 1)
+ second_chart.write_chart_type(:primary_axes => 0)
+ end
+
# Write the category and value elements for the primary axes.
params = {
:x_axis => @x_axis,
:y_axis => @y_axis,
:axis_ids => @axis_ids
@@ -850,21 +903,37 @@
write_date_axis(params)
else
write_cat_axis(params)
end
- write_val_axis(params)
+ write_val_axis(@x_axis, @y_axis, @axis_ids)
# Write the category and value elements for the secondary axes.
params = {
:x_axis => @x2_axis,
:y_axis => @y2_axis,
:axis_ids => @axis2_ids
}
- write_val_axis(params)
+ write_val_axis(@x2_axis, @y2_axis, @axis2_ids)
+ # Write the secondary axis for the secondary chart.
+ if second_chart && second_chart.is_secondary?
+
+ params = {
+ :x_axis => second_chart.x2_axis,
+ :y_axis => second_chart.y2_axis,
+ :axis_ids => second_chart.axis2_ids
+ }
+
+ second_chart.write_val_axis(
+ second_chart.x2_axis,
+ second_chart.y2_axis,
+ second_chart.axis2_ids
+ )
+ end
+
if @date_category
write_date_axis(params)
else
write_cat_axis(params)
end
@@ -935,43 +1004,48 @@
#
# Write the <c:ser> element.
#
def write_ser(series) # :nodoc:
- index = @series_index
- @series_index += 1
-
@writer.tag_elements('c:ser') do
- # Write the c:idx element.
- write_idx(index)
- # Write the c:order element.
- write_order(index)
- # Write the series name.
- write_series_name(series)
- # Write the c:spPr element.
- write_sp_pr(series)
- # Write the c:marker element.
- write_marker(series.marker)
- # Write the c:invertIfNegative element.
- write_c_invert_if_negative(series.invert_if_negative)
- # Write the c:dPt element.
- write_d_pt(series.points)
- # Write the c:dLbls element.
- write_d_lbls(series.labels)
- # Write the c:trendline element.
- write_trendline(series.trendline)
- # Write the c:errBars element.
- write_error_bars(series.error_bars)
+ write_ser_base(series) do
+ write_c_invert_if_negative(series.invert_if_negative)
+ end
# Write the c:cat element.
write_cat(series)
# Write the c:val element.
write_val(series)
# Write the c:smooth element.
write_c_smooth(series.smooth) if ptrue?(@smooth_allowed)
end
+ @series_index += 1
end
+ def write_ser_base(series)
+ # Write the c:idx element.
+ write_idx(@series_index)
+ # Write the c:order element.
+ write_order(@series_index)
+ # Write the series name.
+ write_series_name(series)
+ # Write the c:spPr element.
+ write_sp_pr(series)
+ # Write the c:marker element.
+ write_marker(series.marker)
+
+ yield if block_given?
+
+ # Write the c:dPt element.
+ write_d_pt(series.points)
+ # Write the c:dLbls element.
+ write_d_lbls(series.labels)
+ # Write the c:trendline element.
+ write_trendline(series.trendline)
+ # Write the c:errBars element.
+ write_error_bars(series.error_bars)
+ end
+
#
# Write the <c:idx> element.
#
def write_idx(val) # :nodoc:
@writer.empty_tag('c:idx', [ ['val', val] ])
@@ -1175,11 +1249,11 @@
if @show_crosses || ptrue?(x_axis.visible)
write_crossing(y_axis.crossing)
end
# Write the c:auto element.
- write_auto(1)
+ write_auto(1) unless x_axis.text_axis
# Write the c:labelAlign element.
write_label_align('ctr')
# Write the c:labelOffset element.
write_label_offset(100)
# Write the c:tickLblSkip element.
@@ -1188,21 +1262,20 @@
end
#
# Write the <c:valAx> element. Usually the Y axis.
#
- def write_val_axis(params)
- axis_ids = params[:axis_ids]
+ def write_val_axis(x_axis, y_axis, axis_ids, position = nil)
return unless axis_ids && !axis_ids.empty?
- x_axis = params[:x_axis]
- y_axis = params[:y_axis]
- axis_ids_0 = axis_ids[0]
- axis_ids_1 = axis_ids[1]
- position = y_axis.position || params[:position] || @val_axis_position
-
- write_val_axis_base(x_axis, y_axis, axis_ids_0, axis_ids_1, position)
+ write_val_axis_base(
+ x_axis, y_axis,
+ axis_ids[0],
+ axis_ids[1],
+ y_axis.position || position || @val_axis_position
+ )
end
+ public :write_val_axis
def write_val_axis_base(x_axis, y_axis, axis_ids_0, axis_ids_1, position) # :nodoc:
@writer.tag_elements('c:valAx') do
write_axis_id(axis_ids_1)