lib/write_xlsx/chart.rb in write_xlsx-0.75.0 vs lib/write_xlsx/chart.rb in write_xlsx-0.76.0

- old
+ new

@@ -33,10 +33,108 @@ def attributes [ ['val', 1] ] end end + class ChartArea + include Writexlsx::Utility + + attr_reader :line, :fill, :layout + + def initialize(params = {}) + @layout = layout_properties(params[:layout]) + + # Allow 'border' as a synonym for 'line'. + border = params_to_border(params) + + # Set the line properties for the chartarea. + @line = border ? line_properties(border) : line_properties(params[:line]) + + # Map deprecated Spreadsheet::WriteExcel fill colour. + fill = params[:color] ? { :color => params[:color] } : params[:fill] + @fill = fill_properties(fill) + end + + private + + def params_to_border(params) + line_weight = params[:line_weight] + + # Map deprecated Spreadsheet::WriteExcel line_weight. + border = params[:border] + border = { :width => swe_line_weight(line_weight) } if line_weight + + # Map deprecated Spreadsheet::WriteExcel line_pattern. + if params[:line_pattern] + pattern = swe_line_pattern(params[:line_pattern]) + if pattern == 'none' + border = { :none => 1 } + else + border[:dash_type] = pattern + end + end + + # Map deprecated Spreadsheet::WriteExcel line colour. + border[:color] = params[:line_color] if params[:line_color] + border + end + + # + # Get the Spreadsheet::WriteExcel line pattern for backward compatibility. + # + def swe_line_pattern(val) + swe_line_pattern_hash[numeric_or_downcase(val)] || 'solid' + end + + def swe_line_pattern_hash + { + 0 => 'solid', + 1 => 'dash', + 2 => 'dot', + 3 => 'dash_dot', + 4 => 'long_dash_dot_dot', + 5 => 'none', + 6 => 'solid', + 7 => 'solid', + 8 => 'solid', + 'solid' => 'solid', + 'dash' => 'dash', + 'dot' => 'dot', + 'dash-dot' => 'dash_dot', + 'dash-dot-dot' => 'long_dash_dot_dot', + 'none' => 'none', + 'dark-gray' => 'solid', + 'medium-gray' => 'solid', + 'light-gray' => 'solid' + } + end + + # + # Get the Spreadsheet::WriteExcel line weight for backward compatibility. + # + def swe_line_weight(val) + swe_line_weight_hash[numeric_or_downcase(val)] || 1 + end + + def swe_line_weight_hash + { + 1 => 0.25, + 2 => 1, + 3 => 2, + 4 => 3, + 'hairline' => 0.25, + 'narrow' => 1, + 'medium' => 2, + 'wide' => 3 + } + end + + def numeric_or_downcase(val) + val.respond_to?(:coerce) ? val : val.downcase + end + end + class Chart include Writexlsx::Utility attr_accessor :id, :name # :nodoc: attr_writer :index, :palette, :protection # :nodoc: @@ -79,49 +177,23 @@ def initialize(subtype) # :nodoc: @writer = Package::XMLWriterSimple.new @subtype = subtype @sheet_type = 0x0200 - @orientation = 0x0 @series = [] @embedded = 0 @id = '' @series_index = 0 @style_id = 2 - @axis_ids = [] - @axis2_ids = [] - @cat_has_num_fmt = false - @requires_category = 0 - @legend_position = 'right' - @cat_axis_position = 'b' - @val_axis_position = 'l' @formula_ids = {} @formula_data = [] - @horiz_cat_axis = 0 - @horiz_val_axis = 1 @protection = 0 - @chartarea = {} - @plotarea = {} + @chartarea = ChartArea.new + @plotarea = ChartArea.new @title = Caption.new(self) - @x_axis = Axis.new(self) - @y_axis = Axis.new(self) - @x2_axis = Axis.new(self) - @y2_axis = Axis.new(self) @name = '' - @show_blanks = 'gap' - @show_hidden_data = false - @show_crosses = true - @width = 480 - @height = 288 - @x_scale = 1 - @y_scale = 1 - @x_offset = 0 - @y_offset = 0 @table = nil - @smooth_allowed = 0 - @cross_between = 'between' - set_default_properties end def set_xml_writer(filename) # :nodoc: @writer.set_xml_writer(filename) @@ -172,34 +244,38 @@ # # Set the properties of the x-axis. # def set_x_axis(params = {}) + @date_category = true if ptrue?(params[:date_axis]) @x_axis.merge_with_hash(params) end # # Set the properties of the Y-axis. # # The set_y_axis() method is used to set properties of the Y axis. # The properties that can be set are the same as for set_x_axis, # def set_y_axis(params = {}) + @date_category = true if ptrue?(params[:date_axis]) @y_axis.merge_with_hash(params) end # # Set the properties of the secondary X-axis. # def set_x2_axis(params = {}) + @date_category = true if ptrue?(params[:date_axis]) @x2_axis.merge_with_hash(params) end # # Set the properties of the secondary Y-axis. # def set_y2_axis(params = {}) + @date_category = true if ptrue?(params[:date_axis]) @y2_axis.merge_with_hash(params) end # # Set the properties of the chart title. @@ -227,19 +303,19 @@ # # Set the properties of the chart plotarea. # def set_plotarea(params) # Convert the user defined properties to internal properties. - @plotarea = area_properties(params) + @plotarea = ChartArea.new(params) end # # Set the properties of the chart chartarea. # def set_chartarea(params) # Convert the user defined properties to internal properties. - @chartarea = area_properties(params) + @chartarea = ChartArea.new(params) end # # Set on of the 42 built-in Excel chart styles. The default style is 2. # @@ -304,39 +380,27 @@ end end # Set the up and down bar properties. @up_down_bars = { - :_up => { - :_line => line_properties(params[:up][:line]), - :_fill => line_properties(params[:up][:fill]) - }, - :_down => { - :_line => line_properties(params[:down][:line]), - :_fill => line_properties(params[:down][:fill]) - } + :_up => Chartline.new(params[:up]), + :_down => Chartline.new(params[:down]) } end # # Set properties for the chart drop lines. # def set_drop_lines(params = {}) - # Set the drop line properties. - line = line_properties(params[:line]) - - @drop_lines = { :_line => line } + @drop_lines = Chartline.new(params) end # # Set properties for the chart high-low lines. # def set_high_low_lines(params = {}) - # Set the drop line properties. - line = line_properties(params[:line]) - - @hi_low_lines = { :_line => line } + @hi_low_lines = Chartline.new(params) end # # Setup the default configuration data for an embedded chart. # @@ -388,11 +452,25 @@ # # Convert user defined font values into private hash values. # def convert_font_args(params) return unless params - font = { + font = params_to_font(params) + + # Convert font size units. + font[:_size] *= 100 if font[:_size] && font[:_size] != 0 + + # Convert rotation into 60,000ths of a degree. + if ptrue?(font[:_rotation]) + font[:_rotation] = 60_000 * font[:_rotation].to_i + end + + font + end + + def params_to_font(params) + { :_name => params[:name], :_color => params[:color], :_size => params[:size], :_bold => params[:bold], :_italic => params[:italic], @@ -400,20 +478,10 @@ :_pitch_family => params[:pitch_family], :_charset => params[:charset], :_baseline => params[:baseline] || 0, :_rotation => params[:rotation] } - - # Convert font size units. - font[:_size] *= 100 if font[:_size] && font[:_size] != 0 - - # Convert rotation into 60,000ths of a degree. - if ptrue?(font[:_rotation]) - font[:_rotation] = 60_000 * font[:_rotation].to_i - end - - font end # # Switch name and name_formula parameters if required. # @@ -433,61 +501,66 @@ # has user specified data associated with it then that is also stored. This # data is used to populate cached Excel data when creating a chart. # If there is no user defined data then it will be populated by the parent # workbook in Workbook::_add_chart_data # - def get_data_id(formula, data) # :nodoc: - # Ignore series without a range formula. - return unless formula + def data_id(full_formula, data) # :nodoc: + return unless full_formula # Strip the leading '=' from the formula. - formula = formula.sub(/^=/, '') + formula = full_formula.sub(/^=/, '') # Store the data id in a hash keyed by the formula and store the data # in a separate array with the same id. - if !@formula_ids.has_key?(formula) - # Haven't seen this formula before. - id = @formula_data.size - - @formula_data << data - @formula_ids[formula] = id - else + if @formula_ids.has_key?(formula) # Formula already seen. Return existing id. id = @formula_ids[formula] - # Store user defined data if it isn't already there. - @formula_data[id] = data unless @formula_data[id] + @formula_data[id] ||= data + else + # Haven't seen this formula before. + id = @formula_ids[formula] = @formula_data.size + @formula_data << data end id end - # - # Convert user defined layout properties to the format required internally. - # - def layout_properties(args, is_text = false) - return unless ptrue?(args) + private - properties = is_text ? [:x, :y] : [:x, :y, :width, :height] + def axis_setup + @axis_ids = [] + @axis2_ids = [] + @cat_has_num_fmt = false + @requires_category = 0 + @cat_axis_position = 'b' + @val_axis_position = 'l' + @horiz_cat_axis = 0 + @horiz_val_axis = 1 + @x_axis = Axis.new(self) + @y_axis = Axis.new(self) + @x2_axis = Axis.new(self) + @y2_axis = Axis.new(self) + end - # Check for valid properties. - allowable = Hash.new - allowable[properties.size] = nil - - # Set the layout properties - layout = Hash.new - properties.each do |property| - value = args[property] - # Convert to the format used by Excel for easier testing. - layout[property] = sprintf("%.17g", value) - end - - layout + def display_setup + @orientation = 0x0 + @width = 480 + @height = 288 + @x_scale = 1 + @y_scale = 1 + @x_offset = 0 + @y_offset = 0 + @legend_position = 'right' + @smooth_allowed = 0 + @cross_between = 'between' + @date_category = false + @show_blanks = 'gap' + @show_hidden_data = false + @show_crosses = true end - private - # # retun primary/secondary series by :primary_axes flag # def axes_series(params) if params[:primary_axes] != 0 @@ -518,158 +591,22 @@ end # # Convert the user specified colour index or string to a rgb colour. # - def get_color(color) # :nodoc: - # Convert a HTML style #RRGGBB color. - if color and color =~ /^#[0-9a-fA-F]{6}$/ - color = color.sub(/^#/, '') - return color.upcase + def color(color_code) # :nodoc: + if color_code and color_code =~ /^#[0-9a-fA-F]{6}$/ + # Convert a HTML style #RRGGBB color. + color_code.sub(/^#/, '').upcase + else + index = Format.color(color_code) + raise "Unknown color '#{color_code}' used in chart formatting." unless index + palette_color(index) end - - index = Format.get_color(color) - - # Set undefined colors to black. - unless index - index = 0x08 - raise "Unknown color '#{color}' used in chart formatting." - end - - get_palette_color(index) end # - # Convert from an Excel internal colour index to a XML style #RRGGBB index - # based on the default or user defined values in the Workbook palette. - # Note: This version doesn't add an alpha channel. - # - def get_palette_color(index) # :nodoc: - palette = @palette - - # Adjust the colour index. - index -= 8 - - # Palette is passed in from the Workbook class. - rgb = palette[index] - - sprintf("%02X%02X%02X", *rgb) - end - - # - # Get the Spreadsheet::WriteExcel line pattern for backward compatibility. - # - def get_swe_line_pattern(val) - value = val.downcase - default = 'solid' - - patterns = { - 0 => 'solid', - 1 => 'dash', - 2 => 'dot', - 3 => 'dash_dot', - 4 => 'long_dash_dot_dot', - 5 => 'none', - 6 => 'solid', - 7 => 'solid', - 8 => 'solid', - 'solid' => 'solid', - 'dash' => 'dash', - 'dot' => 'dot', - 'dash-dot' => 'dash_dot', - 'dash-dot-dot' => 'long_dash_dot_dot', - 'none' => 'none', - 'dark-gray' => 'solid', - 'medium-gray' => 'solid', - 'light-gray' => 'solid' - } - - patterns[value] || default - end - - # - # Get the Spreadsheet::WriteExcel line weight for backward compatibility. - # - def get_swe_line_weight(val) - value = val.downcase - default = 1 - - weights = { - 1 => 0.25, - 2 => 1, - 3 => 2, - 4 => 3, - 'hairline' => 0.25, - 'narrow' => 1, - 'medium' => 2, - 'wide' => 3 - } - - weights[value] || default - end - - # - # Convert user defined fill properties to the structure required internally. - # - def fill_properties(fill) # :nodoc: - return { :_defined => 0 } unless fill - - fill[:_defined] = 1 - - fill - end - - # - # Convert user defined area properties to the structure required internally. - # - def area_properties(arg) # :nodoc: - area = {} - - # Map deprecated Spreadsheet::WriteExcel fill colour. - arg[:fill] = { :color => arg[:color] } if arg[:color] - - # Map deprecated Spreadsheet::WriteExcel line_weight. - if arg[:line_weight] - width = get_swe_line_weight(arg[:line_weight]) - arg[:border] = { :width => width } - end - - # Map deprecated Spreadsheet::WriteExcel line_pattern. - if arg[:line_pattern] - pattern = get_swe_line_pattern(arg[:line_pattern]) - if pattern == 'none' - arg[:border] = { :none => 1 } - else - arg[:border][:dash_type] = pattern - end - end - - # Map deprecated Spreadsheet::WriteExcel line colour. - arg[:border][:color] = arg[:line_color] if arg[:line_color] - - # Handle Excel::Writer::XLSX style properties. - - # Set the line properties for the chartarea. - line = line_properties(arg[:line]) - - # Allow 'border' as a synonym for 'line'. - line = line_properties(arg[:border]) if (arg[:border]) - - # Set the fill properties for the chartarea. - fill = fill_properties(arg[:fill]) - - # Set the plotarea layout. - layout = layout_properties(arg[:layout]) - - area[:_line] = line - area[:_fill] = fill - area[:_layout] = layout - - return area - end - - # # Returns series which use the primary axes. # def get_primary_axes_series @series.reject {|s| s.y2_axis} end @@ -738,42 +675,59 @@ end # # Setup the default properties for a chart. # def set_default_properties # :nodoc: - # Set the default axis properties. - @x_axis.defaults = { + display_setup + axis_setup + set_axis_defaults + + set_x_axis + set_y_axis + + set_x2_axis + set_y2_axis + end + + def set_axis_defaults + @x_axis.defaults = x_axis_defaults + @y_axis.defaults = y_axis_defaults + @x2_axis.defaults = x2_axis_defaults + @y2_axis.defaults = y2_axis_defaults + end + + def x_axis_defaults + { :num_format => 'General', :major_gridlines => { :visible => 0 } } + end - @y_axis.defaults = { + def y_axis_defaults + { :num_format => 'General', :major_gridlines => { :visible => 1 } } + end - @x2_axis.defaults = { + def x2_axis_defaults + { :num_format => 'General', :label_position => 'none', :crossing => 'max', :visible => 0 } + end - @y2_axis.defaults = { + def y2_axis_defaults + { :num_format => 'General', :major_gridlines => { :visible => 0 }, :position => 'right', :visible => 1 } - - set_x_axis - set_y_axis - - set_x2_axis - set_y2_axis end - # # Write the <c:chartSpace> element. # def write_chart_space # :nodoc: @writer.tag_elements('c:chartSpace', chart_space_attributes) do @@ -844,57 +798,56 @@ end # # Write the <c:plotArea> element. # - def write_plot_area # :nodoc: - write_plot_area_base - end - - def write_plot_area_base(type = nil) # :nodoc: @writer.tag_elements('c:plotArea') do # Write the c:layout element. - write_layout(@plotarea[:_layout], 'plot') + 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) - # Write the c:catAx elements for series using primary axes. + # Write the category and value elements for the primary axes. params = { :x_axis => @x_axis, :y_axis => @y_axis, :axis_ids => @axis_ids } - write_cat_or_date_axis(params, type) + + if @date_category + write_date_axis(params) + else + write_cat_axis(params) + end + write_val_axis(params) - # Write c:valAx and c:catAx elements for series using secondary axes. + # 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_cat_or_date_axis(params, type) + if @date_category + write_date_axis(params) + else + write_cat_axis(params) + end + # Write the c:dTable element. write_d_table # Write the c:spPr element for the plotarea formatting. write_sp_pr(@plotarea) end end - def write_cat_or_date_axis(params, type) - if type == :stock - write_date_axis(params) - else - write_cat_axis(params) - end - end - # # Write the <c:layout> element. # def write_layout(layout = nil, type = nil) # :nodoc: tag = 'c:layout' @@ -966,11 +919,11 @@ # 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_neg) + 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. @@ -1201,33 +1154,24 @@ end # # Write the <c:valAx> element. Usually the Y axis. # - # TODO. Maybe should have a _write_cat_val_axis method as well for scatter. - # - def write_val_axis(params, cat = false) # :nodoc: + def write_val_axis(params) axis_ids = params[:axis_ids] - position = params[:position] || @val_axis_position - horiz = @horiz_val_axis - if cat - x_axis = params[:y_axis] - y_axis = params[:x_axis] - axis_ids_0 = axis_ids[1] - axis_ids_1 = axis_ids[0] - else - x_axis = params[:x_axis] - y_axis = params[:y_axis] - axis_ids_0 = axis_ids[0] - axis_ids_1 = axis_ids[1] - end - return unless axis_ids && !axis_ids.empty? - # OVerwrite the default axis position with a user supplied value. - position = y_axis.position || position + 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) + end + + 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) # Write the c:scaling element. write_scaling_with_param(y_axis) @@ -1243,13 +1187,13 @@ # Write the c:minorGridlines element. write_minor_gridlines(y_axis.minor_gridlines) # Write the axis title elements. if y_axis.formula - write_title_formula(y_axis, horiz, nil, y_axis.layout) + write_title_formula(y_axis, @horiz_val_axis, nil, y_axis.layout) elsif y_axis.name - write_title_rich(y_axis, horiz, y_axis.layout) + write_title_rich(y_axis, @horiz_val_axis, y_axis.layout) end # Write the c:numberFormat element. write_number_format(y_axis) @@ -1277,20 +1221,10 @@ write_c_minor_unit(y_axis.minor_unit) end end # - # Write the <c:valAx> element. - # This is for the second valAx in scatter plots. - # - # Usually the X axis. - # - def write_cat_val_axis(params) # :nodoc: - write_val_axis(params, true) - end - - # # Write the <c:dateAx> element. Usually the X axis. # def write_date_axis(params) # :nodoc: x_axis = params[:x_axis] y_axis = params[:y_axis] @@ -1348,19 +1282,15 @@ # Write the c:tickLblSkip element. write_tick_lbl_skip(x_axis.interval_unit) # Write the c:majorUnit element. write_c_major_unit(x_axis.major_unit) # Write the c:majorTimeUnit element. - if !x_axis.major_unit.nil? - write_c_major_time_unit(x_axis.major_unit_type) - end + write_c_major_time_unit(x_axis.major_unit_type) if x_axis.major_unit # Write the c:minorUnit element. write_c_minor_unit(x_axis.minor_unit) # Write the c:minorTimeUnit element. - if !x_axis.minor_unit.nil? - write_c_minor_time_unit(x_axis.minor_unit_type) - end + write_c_minor_time_unit(x_axis.minor_unit_type) if x_axis.minor_unit end end def write_crossing(crossing) # Note, the category crossing comes from the value axis. @@ -1417,22 +1347,18 @@ # # Write the <c:max> element. # def write_c_max(max = nil) # :nodoc: - return if max.nil? - - @writer.empty_tag('c:max', [ ['val', max] ]) + @writer.empty_tag('c:max', [ ['val', max] ]) if max end # # Write the <c:min> element. # def write_c_min(min = nil) # :nodoc: - return if min.nil? - - @writer.empty_tag('c:min', [ ['val', min] ]) + @writer.empty_tag('c:min', [ ['val', min] ]) if min end # # Write the <c:axPos> element. # @@ -1548,12 +1474,18 @@ def write_minor_gridlines(gridlines) # :nodoc: write_gridlines_base('c:minorGridlines', gridlines) end def write_gridlines_base(tag, gridlines) # :nodoc: + return unless gridlines return if gridlines.respond_to?(:[]) and !ptrue?(gridlines[:_visible]) - write_lines_base(tag, gridlines) + + if gridlines.line_defined? + @writer.tag_elements(tag) { write_sp_pr(gridlines) } + else + @writer.empty_tag(tag) + end end # # Write the <c:crossBetween> element. # @@ -1601,53 +1533,38 @@ # # Write the <c:legend> element. # def write_legend # :nodoc: - position = @legend_position - overlay = false + position = @legend_position.sub(/^overlay_/, '') + return if position == 'none' || (not position_allowed.has_key?(position)) - if @legend_delete_series && @legend_delete_series.kind_of?(Array) - @delete_series = @legend_delete_series - end - - if position =~ /^overlay_/ - position.sub!(/^overlay_/, '') - overlay = true if position - end - - allowed = { - 'right' => 'r', - 'left' => 'l', - 'top' => 't', - 'bottom' => 'b' - } - - return if position == 'none' - return unless allowed.has_key?(position) - - position = allowed[position] - + @delete_series = @legend_delete_series if @legend_delete_series.kind_of?(Array) @writer.tag_elements('c:legend') do # Write the c:legendPos element. - write_legend_pos(position) + write_legend_pos(position_allowed[position]) # Remove series labels from the legend. - @delete_series.each do |index| - # Write the c:legendEntry element. - write_legend_entry(index) - end if @delete_series + # Write the c:legendEntry element. + @delete_series.each { |i| write_legend_entry(i) } if @delete_series # Write the c:layout element. write_layout(@legend_layout, 'legend') # Write the c:txPr element. - if ptrue?(@legend_font) - write_tx_pr(nil, @legend_font) - end + write_tx_pr(nil, @legend_font) if ptrue?(@legend_font) # Write the c:overlay element. - write_overlay if overlay + write_overlay if @legend_position =~ /^overlay_/ end end + def position_allowed + { + 'right' => 'r', + 'left' => 'l', + 'top' => 't', + 'bottom' => 'b' + } + end + # # Write the <c:legendPos> element. # def write_legend_pos(val) # :nodoc: @writer.empty_tag('c:legendPos', [ ['val', val] ]) @@ -1960,17 +1877,17 @@ # def write_marker(marker = nil) # :nodoc: marker ||= @default_marker return unless ptrue?(marker) - return if ptrue?(marker[:automatic]) + return if ptrue?(marker.automatic?) @writer.tag_elements('c:marker') do # Write the c:symbol element. - write_symbol(marker[:type]) + write_symbol(marker.type) # Write the c:size element. - size = marker[:size] + size = marker.size write_marker_size(size) if ptrue?(size) # Write the c:spPr element. write_sp_pr(marker) end end @@ -2000,12 +1917,12 @@ # # Write the <c:spPr> element. # def write_sp_pr(series) # :nodoc: - line = series.respond_to?(:line) ? series.line : series[:_line] - fill = series.respond_to?(:fill) ? series.fill : series[:_fill] + line = series.line + fill = series.fill return if (!line || !ptrue?(line[:_defined])) && (!fill || !ptrue?(fill[:_defined])) @writer.tag_elements('c:spPr') do @@ -2029,11 +1946,12 @@ # def write_a_ln(line) # :nodoc: attributes = [] # Add the line width as an attribute. - if width = line[:width] + if line[:width] + width = line[:width] # Round width to nearest 0.25, like Excel. width = ((width + 0.125) * 4).to_i / 4.0 # Convert to internal units. width = (0.5 + (12700 * width)).to_i @@ -2049,13 +1967,13 @@ elsif ptrue?(line[:color]) # Write the a:solidFill element. write_a_solid_fill(line) end # Write the line/dash type. - if type = line[:dash_type] + if line[:dash_type] # Write the a:prstDash element. - write_a_prst_dash(type) + write_a_prst_dash(line[:dash_type]) end end end # @@ -2068,16 +1986,12 @@ # # Write the <a:solidFill> element. # def write_a_solid_fill(line) # :nodoc: @writer.tag_elements('a:solidFill') do - if line[:color] - color = get_color(line[:color]) - - # Write the a:srgbClr element. - write_a_srgb_clr(color) - end + # Write the a:srgbClr element. + write_a_srgb_clr(color(line[:color])) if line[:color] end end # # Write the <a:srgbClr> element. @@ -2099,23 +2013,23 @@ def write_trendline(trendline) # :nodoc: return unless trendline @writer.tag_elements('c:trendline') do # Write the c:name element. - write_name(trendline[:name]) + write_name(trendline.name) # Write the c:spPr element. write_sp_pr(trendline) # Write the c:trendlineType element. - write_trendline_type(trendline[:type]) + write_trendline_type(trendline.type) # Write the c:order element for polynomial trendlines. - write_trendline_order(trendline[:order]) if trendline[:type] == 'poly' + write_trendline_order(trendline.order) if trendline.type == 'poly' # Write the c:period element for moving average trendlines. - write_period(trendline[:period]) if trendline[:type] == 'movingAvg' + write_period(trendline.period) if trendline.type == 'movingAvg' # Write the c:forward element. - write_forward(trendline[:forward]) + write_forward(trendline.forward) # Write the c:backward element. - write_backward(trendline[:backward]) + write_backward(trendline.backward) end end # # Write the <c:trendlineType> element. @@ -2167,27 +2081,24 @@ # # Write the <c:hiLowLines> element. # def write_hi_low_lines # :nodoc: - write_lines_base('c:hiLowLines', @hi_low_lines) + write_lines_base(@hi_low_lines, 'c:hiLowLines') end # # Write the <c:dropLines> elent. # def write_drop_lines - write_lines_base('c:dropLines', @drop_lines) + write_lines_base(@drop_lines, 'c:dropLines') end - # - # used from write_drop_lines and write_hi_low_lines - # - def write_lines_base(tag, lines) + def write_lines_base(lines, tag) return unless lines - if lines[:_line] && ptrue?(lines[:_line][:_defined]) + if lines.line_defined? @writer.tag_elements(tag) { write_sp_pr(lines) } else @writer.empty_tag(tag) end end @@ -2444,29 +2355,29 @@ @writer.tag_elements('c:errBars') do # Write the c:errDir element. write_err_dir(direction) # Write the c:errBarType element. - write_err_bar_type(error_bars[:_direction]) + write_err_bar_type(error_bars.direction) # Write the c:errValType element. - write_err_val_type(error_bars[:_type]) + write_err_val_type(error_bars.type) - unless ptrue?(error_bars[:_endcap]) + unless ptrue?(error_bars.endcap) # Write the c:noEndCap element. write_no_end_cap end - case error_bars[:_type] + case error_bars.type when 'stdErr' # Don't need to write a c:errValType tag. when 'cust' # Write the custom error tags. write_custom_error(error_bars) else # Write the c:val element. - write_error_val(error_bars[:_value]) + write_error_val(error_bars.value) end # Write the c:spPr element. write_sp_pr(error_bars) end @@ -2509,30 +2420,30 @@ # # Write the custom error bars type. # def write_custom_error(error_bars) - if ptrue?(error_bars[:_plus_values]) - # Write the c:plus element. - @writer.tag_elements('c:plus') do - if error_bars[:_plus_values] =~ /^=/ # '=Sheet1!$A$1:$A$5' - write_num_ref(error_bars[:_plus_values], error_bars[:_plus_data], 'num') - else # [1, 2, 3] - write_num_lit(error_bars[:_plus_values]) - end - end - # Write the c:minus element. - @writer.tag_elements('c:minus') do - if error_bars[:_minus_values] =~ /^=/ # '=Sheet1!$A$1:$A$5' - write_num_ref(error_bars[:_minus_values], error_bars[:_minus_data], 'num') - else # [1, 2, 3] - write_num_lit(error_bars[:_minus_values]) - end - end + if ptrue?(error_bars.plus_values) + write_custom_error_base('c:plus', error_bars.plus_values, error_bars.plus_data) + write_custom_error_base('c:minus', error_bars.minus_values, error_bars.minus_data) end end + def write_custom_error_base(tag, values, data) + @writer.tag_elements(tag) do + write_num_ref_or_lit(values, data) + end + end + + def write_num_ref_or_lit(values, data) + if values =~ /^=/ # '=Sheet1!$A$1:$A$5' + write_num_ref(values, data, 'num') + else # [1, 2, 3] + write_num_lit(values) + end + end + # # Write the <c:upDownBars> element. # def write_up_down_bars return unless ptrue?(@up_down_bars) @@ -2582,10 +2493,10 @@ @writer.empty_tag('c:smooth', attributes) end def write_bars_base(tag, format) - if ptrue?(format[:_line][:_defined]) || ptrue?(format[:_fill][:_defined]) + if format.line_defined? || format.fill_defined? @writer.tag_elements(tag) { write_sp_pr(format) } else @writer.empty_tag(tag) end end