lib/write_xlsx/chart.rb in write_xlsx-0.62.0 vs lib/write_xlsx/chart.rb in write_xlsx-0.64.0

- old
+ new

@@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- require 'write_xlsx/package/xml_writer_simple' require 'write_xlsx/utility' +require 'write_xlsx/chart/axis' module Writexlsx class Table include Writexlsx::Utility @@ -466,11 +467,11 @@ 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 + attr_reader :width, :height # :nodoc: # # Factory method for returning chart objects based on their class type. # def self.factory(current_subclass, subtype = nil) # :nodoc: @@ -525,14 +526,14 @@ @horiz_cat_axis = 0 @horiz_val_axis = 1 @protection = 0 @chartarea = {} @plotarea = {} - @x_axis = {} - @y_axis = {} - @x2_axis = {} - @y2_axis = {} + @x_axis = Axis.new + @y_axis = Axis.new + @x2_axis = Axis.new + @y2_axis = Axis.new @name = '' @show_blanks = 'gap' @show_hidden_data = false @show_crosses = true @width = 480 @@ -697,26 +698,33 @@ cat_id = get_data_id(categories, params[:categories_data]) val_id = get_data_id(values, params[:values_data]) name_id = get_data_id(name_formula, params[:name_data]) # Set the line properties for the series. - line = get_line_properties(params[:line]) + line = line_properties(params[:line]) # Allow 'border' as a synonym for 'line' in bar/column style charts. - line = get_line_properties(params[:border]) if params[:border] + line = line_properties(params[:border]) if params[:border] # Set the fill properties for the series. - fill = get_fill_properties(params[:fill]) + fill = fill_properties(params[:fill]) # Set the marker properties for the series. - marker = get_marker_properties(params[:marker]) + marker = marker_properties(params[:marker]) # Set the trendline properties for the series. - trendline = get_trendline_properties(params[:trendline]) + trendline = trendline_properties(params[:trendline]) + # Set the error bars properties for the series. + y_error_bars = error_bars_properties(params[:y_error_bars]) + x_error_bars = error_bars_properties(params[:x_error_bars]) + + # Set the point properties for the series. + points = points_properties(params[:points]) + # Set the labels properties for the series. - labels = get_labels_properties(params[:data_labels]) + labels = labels_properties(params[:data_labels]) # Set the "invert if negative" fill property. invert_if_neg = params[:invert_if_negative] # Set the secondary axis properties. @@ -737,11 +745,16 @@ :_marker => marker, :_trendline => trendline, :_labels => labels, :_invert_if_neg => invert_if_neg, :_x2_axis => x2_axis, - :_y2_axis => y2_axis + :_y2_axis => y2_axis, + :_points => points, + :_error_bars => { + :_x_error_bars => x_error_bars, + :_y_error_bars => y_error_bars + } } end # # Set the properties of the X-axis. @@ -840,35 +853,35 @@ # :min => 10, # :max => 80 # ) # def set_x_axis(params = {}) - @x_axis = convert_axis_args(@x_axis, params) + @x_axis.merge_with_hash(self, 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 = {}) - @y_axis = convert_axis_args(@y_axis, params) + @y_axis.merge_with_hash(self, params) end # # Set the properties of the secondary X-axis. # def set_x2_axis(params = {}) - @x2_axis = convert_axis_args(@x2_axis, params) + @x2_axis.merge_with_hash(self, params) end # # Set the properties of the secondary Y-axis. # def set_y2_axis(params = {}) - @y2_axis = convert_axis_args(@y2_axis, params) + @y2_axis.merge_with_hash(self, params) end # # Set the properties of the chart title. # @@ -882,11 +895,10 @@ # chart. The name can also be a formula such as =Sheet1!$A$1. The name # property is optional. The default is to have no chart title. # def set_title(params) name, name_formula = process_names(params[:name], params[:name_formula]) - data_id = get_data_id(name_formula, params[:data]) @title_name = name @title_formula = name_formula @title_data_id = data_id @@ -939,11 +951,11 @@ # writeexcel gem. However, it can be simulated using the # set_style() method. # def set_plotarea(params) # Convert the user defined properties to internal properties. - @plotarea = get_area_properties(params) + @plotarea = area_properties(params) end # # Set the properties of the chart chartarea. # @@ -954,11 +966,11 @@ # writeexcel gem. However, it can be simulated using the # set_style() method. # def set_chartarea(params) # Convert the user defined properties to internal properties. - @chartarea = get_area_properties(params) + @chartarea = area_properties(params) end # # Set on of the 42 built-in Excel chart styles. The default style is 2. # @@ -1035,10 +1047,56 @@ def set_table(params = {}) @table = Table.new(params) end # + # Set properties for the chart up-down bars. + # + def set_up_down_bars(params = {}) + # Map border to line. + [:up, :down].each do |up_down| + if params[up_down] + params[up_down][:line] = params[up_down][:border] if params[up_down][:border] + else + params[up_down] = {} + 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]) + } + } + 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 } + 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 } + end + + # # Setup the default configuration data for an embedded chart. # def set_embedded_config_data @embedded = 1 end @@ -1074,71 +1132,55 @@ # Write the c:axId elements write_axis_ids(params) end end - private - # - # retun primary/secondary series by :primary_axes flag + # Switch name and name_formula parameters if required. # - def axes_series(params) - if params[:primary_axes] != 0 - primary_axes_series - else - secondary_axes_series + def process_names(name = nil, name_formula = nil) # :nodoc: + # Name looks like a formula, use it to set name_formula. + if name && name =~ /^=[^!]+!\$/ + name_formula = name + name = '' end + + [name, name_formula] end # - # Convert user defined axis values into private hash values. + # Assign an id to a each unique series formula or title/axis formula. Repeated + # formulas such as for categories get the same id. If the series or title + # 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 convert_axis_args(axis, params) # :nodoc: - arg = (axis[:_defaults] || {}).merge(params) - name, name_formula = process_names(arg[:name], arg[:name_formula]) + def get_data_id(formula, data) # :nodoc: + # Ignore series without a range formula. + return unless formula - data_id = get_data_id(name_formula, arg[:data]) + # Strip the leading '=' from the formula. + formula = formula.sub(/^=/, '') - axis = { - :_defaults => axis[:_defaults], - :_name => name, - :_formula => name_formula, - :_data_id => data_id, - :_reverse => arg[:reverse], - :_min => arg[:min], - :_max => arg[:max], - :_minor_unit => arg[:minor_unit], - :_major_unit => arg[:major_unit], - :_minor_unit_type => arg[:minor_unit_type], - :_major_unit_type => arg[:major_unit_type], - :_log_base => arg[:log_base], - :_crossing => arg[:crossing], - :_position => arg[:position], - :_label_position => arg[:label_position], - :_num_format => arg[:num_format], - :_num_format_linked => arg[:num_format_linked], - :_visible => arg[:visible] || 1 - } + # 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 - # Map major_gridlines properties. - if arg[:major_gridlines] && ptrue?(arg[:major_gridlines][:visible]) - axis[:_major_gridlines] = get_gridline_properties(arg[:major_gridlines]) - end + @formula_data << data + @formula_ids[formula] = id + else + # Formula already seen. Return existing id. + id = @formula_ids[formula] - # Map minor_gridlines properties. - if arg[:minor_gridlines] && ptrue?(arg[:minor_gridlines][:visible]) - axis[:_minor_gridlines] = get_gridline_properties(arg[:minor_gridlines]) + # Store user defined data if it isn't already there. + @formula_data[id] = data unless @formula_data[id] end - # Only use the first letter of bottom, top, left or right. - axis[:_position] = axis[:_position].downcase[0, 1] if axis[:_position] - - # Set the font properties if present. - axis[:_num_font] = convert_font_args(arg[:num_font]) - axis[:_name_font] = convert_font_args(arg[:name_font]) - - axis + id end # # Convert user defined font values into private hash values. # @@ -1161,29 +1203,61 @@ font end # - # Convert and aref of row col values to a range formula. + # Convert user defined line properties to the structure required internally. # - def aref_to_formula(data) # :nodoc: - # If it isn't an array ref it is probably a formula already. - return data unless data.kind_of?(Array) - xl_range_formula(*data) + def line_properties(line) # :nodoc: + return { :_defined => 0 } unless line + + dash_types = { + :solid => 'solid', + :round_dot => 'sysDot', + :square_dot => 'sysDash', + :dash => 'dash', + :dash_dot => 'dashDot', + :long_dash => 'lgDash', + :long_dash_dot => 'lgDashDot', + :long_dash_dot_dot => 'lgDashDotDot', + :dot => 'dot', + :system_dash_dot => 'sysDashDot', + :system_dash_dot_dot => 'sysDashDotDot' + } + + # Check the dash type. + dash_type = line[:dash_type] + + if dash_type + line[:dash_type] = value_or_raise(dash_types, dash_type, 'dash type') + end + + line[:_defined] = 1 + + line end + private + # - # Switch name and name_formula parameters if required. + # retun primary/secondary series by :primary_axes flag # - def process_names(name = nil, name_formula = nil) # :nodoc: - # Name looks like a formula, use it to set name_formula. - if name && name =~ /^=[^!]+!\$/ - name_formula = name - name = '' + def axes_series(params) + if params[:primary_axes] != 0 + primary_axes_series + else + secondary_axes_series end + end - [name, name_formula] + # + # Convert and aref of row col values to a range formula. + # + def aref_to_formula(data) # :nodoc: + # If it isn't an array ref it is probably a formula already. + return data unless data.kind_of?(Array) + xl_range_formula(*data) end # # Find the overall type of the data associated with a series. # @@ -1203,45 +1277,10 @@ # The series data was all numeric. 'num' end # - # Assign an id to a each unique series formula or title/axis formula. Repeated - # formulas such as for categories get the same id. If the series or title - # 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 - - # Strip the leading '=' from the formula. - formula = 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 - # 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] - end - - id - 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}$/ @@ -1328,56 +1367,24 @@ weights[value] || default end # - # Convert user defined line properties to the structure required internally. - # - def get_line_properties(line) # :nodoc: - return { :_defined => 0 } unless line - - dash_types = { - :solid => 'solid', - :round_dot => 'sysDot', - :square_dot => 'sysDash', - :dash => 'dash', - :dash_dot => 'dashDot', - :long_dash => 'lgDash', - :long_dash_dot => 'lgDashDot', - :long_dash_dot_dot => 'lgDashDotDot', - :dot => 'dot', - :system_dash_dot => 'sysDashDot', - :system_dash_dot_dot => 'sysDashDotDot' - } - - # Check the dash type. - dash_type = line[:dash_type] - - if dash_type - line[:dash_type] = value_or_raise(dash_types, dash_type, 'dash type') - end - - line[:_defined] = 1 - - line - end - - # # Convert user defined fill properties to the structure required internally. # - def get_fill_properties(fill) # :nodoc: + def fill_properties(fill) # :nodoc: return { :_defined => 0 } unless fill fill[:_defined] = 1 fill end # # Convert user defined marker properties to the structure required internally. # - def get_marker_properties(marker) # :nodoc: + def marker_properties(marker) # :nodoc: return unless marker types = { :automatic => 'automatic', :none => 'none', @@ -1402,28 +1409,28 @@ marker[:automatic] = 1 if marker_type == 'automatic' marker[:type] = value_or_raise(types, marker_type, 'maker type') end # Set the line properties for the marker.. - line = get_line_properties(marker[:line]) + line = line_properties(marker[:line]) # Allow 'border' as a synonym for 'line'. - line = get_line_properties(marker[:border]) if marker[:border] + line = line_properties(marker[:border]) if marker[:border] # Set the fill properties for the marker. - fill = get_fill_properties(marker[:fill]) + fill = fill_properties(marker[:fill]) marker[:_line] = line marker[:_fill] = fill marker end # # Convert user defined trendline properties to the structure required internally. # - def get_trendline_properties(trendline) # :nodoc: + def trendline_properties(trendline) # :nodoc: return unless trendline types = { :exponential => 'exp', :linear => 'linear', @@ -1437,41 +1444,86 @@ trend_type = trendline[:type] trendline[:type] = value_or_raise(types, trend_type, 'trendline type') # Set the line properties for the trendline.. - line = get_line_properties(trendline[:line]) + line = line_properties(trendline[:line]) # Allow 'border' as a synonym for 'line'. - line = get_line_properties(trendline[:border]) if trendline[:border] + line = line_properties(trendline[:border]) if trendline[:border] # Set the fill properties for the trendline. - fill = get_fill_properties(trendline[:fill]) + fill = fill_properties(trendline[:fill]) trendline[:_line] = line trendline[:_fill] = fill return trendline end # - # Convert user defined gridline properties to the structure required internally. + # Convert user defined error bars properties to structure required + # internally. # - def get_gridline_properties(args) - # Set the visible property for the gridline. - gridline = { :_visible => args[:visible] } + def error_bars_properties(params = {}) + return if !ptrue?(params) || params.empty? - # Set the line properties for the gridline. - gridline[:_line] = get_line_properties(args[:line]) + # Default values. + error_bars = { + :_type => 'fixedVal', + :_value => 1, + :_endcap => 1, + :_direction => 'both' + } - gridline + types = { + :fixed => 'fixedVal', + :percentage => 'percentage', + :standard_deviation => 'stdDev', + :standard_error => 'stdErr' + } + + # Check the error bars type. + error_type = params[:type].to_sym + + if types.key?(error_type) + error_bars[:_type] = types[error_type] + else + raise "Unknown error bars type '#{error_type}'\n" + end + + # Set the value for error types that require it. + if params.key?(:value) + error_bars[:_value] = params[:value] + end + + # Set the end-cap style. + if params.key?(:end_style) + error_bars[:_endcap] = params[:end_style] + end + + # Set the error bar direction. + if params.key?(:direction) + if params[:direction] == 'minus' + error_bars[:_direction] = 'minus' + elsif params[:direction] == 'plus' + error_bars[:_direction] = 'plus' + else + # Default to 'both' + end + end + + # Set the line properties for the error bars. + error_bars[:_line] = line_properties(params[:line]) + + error_bars end # # Convert user defined labels properties to the structure required internally. # - def get_labels_properties(labels) # :nodoc: + def labels_properties(labels) # :nodoc: return nil unless labels position = labels[:position] if position.nil? || position.empty? labels.delete(:position) @@ -1497,11 +1549,11 @@ end # # Convert user defined area properties to the structure required internally. # - def get_area_properties(arg) # :nodoc: + def area_properties(arg) # :nodoc: area = {} # Map deprecated Spreadsheet::WriteExcel fill colour. arg[:fill] = { :color => arg[:color] } if arg[:color] @@ -1525,24 +1577,53 @@ arg[:border][:color] = arg[:line_color] if arg[:line_color] # Handle Excel::Writer::XLSX style properties. # Set the line properties for the chartarea. - line = get_line_properties(arg[:line]) + line = line_properties(arg[:line]) # Allow 'border' as a synonym for 'line'. - line = get_line_properties(arg[:border]) if (arg[:border]) + line = line_properties(arg[:border]) if (arg[:border]) # Set the fill properties for the chartarea. - fill = get_fill_properties(arg[:fill]) + fill = fill_properties(arg[:fill]) area[:_line] = line area[:_fill] = fill return area end + # + # Convert user defined points properties to structure required internally. + # + def points_properties(user_points = nil) + return unless user_points + + points = [] + user_points.each do |user_point| + if user_point + # Set the lline properties for the point. + line = line_properties(user_point[:line]) + + # Allow 'border' as a synonym for 'line'. + if user_point[:border] + line = line_properties(user_point[:border]) + end + + # Set the fill properties for the chartarea. + fill = fill_properties(user_point[:fill]) + + point = {} + point[:_line] = line + point[:_fill] = fill + end + points << point + end + points + end + def value_or_raise(hash, key, msg) raise "Unknown #{msg} '#{key}'" unless hash[key.to_sym] hash[key.to_sym] end @@ -1611,28 +1692,28 @@ # # Setup the default properties for a chart. # def set_default_properties # :nodoc: # Set the default axis properties. - @x_axis[:_defaults] = { + @x_axis.defaults = { :num_format => 'General', :major_gridlines => { :visible => 0 } } - @y_axis[:_defaults] = { + @y_axis.defaults = { :num_format => 'General', :major_gridlines => { :visible => 1 } } - @x2_axis[:_defaults] = { + @x2_axis.defaults = { :num_format => 'General', :label_position => 'none', :crossing => 'max', :visible => 0 } - @y2_axis[:_defaults] = { + @y2_axis.defaults = { :num_format => 'General', :major_gridlines => { :visible => 0 }, :position => 'right', :visible => 1 } @@ -1711,29 +1792,20 @@ # # Write the <c:lang> element. # def write_lang # :nodoc: - val = 'en-US' - - attributes = ['val', val] - - @writer.empty_tag('c:lang', attributes) + @writer.empty_tag('c:lang', ['val', 'en-US']) end # # Write the <c:style> element. # def write_style # :nodoc: - style_id = @style_id + return if @style_id == 2 - # Don't write an element for the default style, 2. - return if style_id == 2 - - attributes = ['val', style_id] - - @writer.empty_tag('c:style', attributes) + @writer.empty_tag('c:style', ['val', @style_id]) end # # Write the <c:chart> element. # @@ -1760,18 +1832,13 @@ # # Write the <c:dispBlanksAs> element. # def write_disp_blanks_as - val = @show_blanks + return if @show_blanks == 'gap' - # Ignore the default value. - return if val == 'gap' - - attributes = ['val', val] - - @writer.empty_tag('c:dispBlanksAs', attributes) + @writer.empty_tag('c:dispBlanksAs', ['val', @show_blanks]) end # # Write the <c:plotArea> element. # @@ -1837,12 +1904,11 @@ # # Write the <c:grouping> element. # def write_grouping(val) # :nodoc: - attributes = ['val', val] - @writer.empty_tag('c:grouping', attributes) + @writer.empty_tag('c:grouping', ['val', val]) end # # Write the series elements. # @@ -1892,14 +1958,18 @@ 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 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 the c:cat element. write_cat(series) # Write the c:val element. write_val(series) end @@ -1907,22 +1977,18 @@ # # Write the <c:idx> element. # def write_idx(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:idx', attributes) + @writer.empty_tag('c:idx', ['val', val]) end # # Write the <c:order> element. # def write_order(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:order', attributes) + @writer.empty_tag('c:order', ['val', val]) end # # Write the series name. # @@ -2041,13 +2107,11 @@ # # Write the <c:axId> element. # def write_axis_id(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:axId', attributes) + @writer.empty_tag('c:axId', ['val', val]) end # # Write the <c:catAx> element. Usually the X axis. # @@ -2062,52 +2126,52 @@ position = @cat_axis_position horiz = @horiz_cat_axis # Overwrite the default axis position with a user supplied value. - position = x_axis[:_position] || position + position = x_axis.position || position @writer.tag_elements('c:catAx') do write_axis_id(axis_ids[0]) # Write the c:scaling element. - write_scaling(x_axis[:_reverse]) + write_scaling(x_axis.reverse) - write_delete(1) unless ptrue?(x_axis[:_visible]) + write_delete(1) unless ptrue?(x_axis.visible) # Write the c:axPos element. - write_axis_pos(position, y_axis[:_reverse]) + write_axis_pos(position, y_axis.reverse) # Write the c:majorGridlines element. - write_major_gridlines(x_axis[:_major_gridlines]) + write_major_gridlines(x_axis.major_gridlines) # Write the c:minorGridlines element. - write_minor_gridlines(x_axis[:_minor_gridlines]) + write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis[:_formula] - write_title_formula(title, @x_axis[:_data_id], horiz, @x_axis[:_name_font]) - elsif title = x_axis[:_name] - write_title_rich(title, horiz, x_axis[:_name_font]) + if title = x_axis.formula + write_title_formula(title, @x_axis.data_id, horiz, @x_axis.name_font) + elsif title = x_axis.name + write_title_rich(title, horiz, x_axis.name_font) end # Write the c:numFmt element. write_cat_number_format(x_axis) # Write the c:majorTickMark element. - write_major_tick_mark(x_axis[:_major_tick_mark]) + write_major_tick_mark(x_axis.major_tick_mark) # Write the c:tickLblPos element. - write_tick_label_pos(x_axis[:_label_position]) + write_tick_label_pos(x_axis.label_position) # Write the axis font elements. - write_axis_font(x_axis[:_num_font]) + write_axis_font(x_axis.num_font) # Write the c:crossAx element. write_cross_axis(axis_ids[1]) - if @show_crosses || ptrue?(x_axis[:_visible]) - write_crossing(y_axis[:_crossing]) + if @show_crosses || ptrue?(x_axis.visible) + write_crossing(y_axis.crossing) end # Write the c:auto element. write_auto(1) # Write the c:labelAlign element. write_label_align('ctr') @@ -2129,61 +2193,61 @@ horiz = @horiz_val_axis return unless axis_ids && !axis_ids.empty? # OVerwrite the default axis position with a user supplied value. - position = y_axis[:_position] || position + position = y_axis.position || position @writer.tag_elements('c:valAx') do write_axis_id(axis_ids[1]) # Write the c:scaling element. write_scaling_with_param(y_axis) - write_delete(1) unless ptrue?(y_axis[:_visible]) + write_delete(1) unless ptrue?(y_axis.visible) # Write the c:axPos element. - write_axis_pos(position, x_axis[:_reverse]) + write_axis_pos(position, x_axis.reverse) # Write the c:majorGridlines element. - write_major_gridlines(y_axis[:_major_gridlines]) + write_major_gridlines(y_axis.major_gridlines) # Write the c:minorGridlines element. - write_minor_gridlines(y_axis[:_minor_gridlines]) + write_minor_gridlines(y_axis.minor_gridlines) # Write the axis title elements. - if title = y_axis[:_formula] - write_title_formula(title, y_axis[:_data_id], horiz, y_axis[:_name_font]) - elsif title = y_axis[:_name] - write_title_rich(title, horiz, y_axis[:_name_font]) + if title = y_axis.formula + write_title_formula(title, y_axis.data_id, horiz, y_axis.name_font) + elsif title = y_axis.name + write_title_rich(title, horiz, y_axis.name_font) end # Write the c:numberFormat element. write_number_format(y_axis) # Write the c:majorTickMark element. - write_major_tick_mark(y_axis[:_major_tick_mark]) + write_major_tick_mark(y_axis.major_tick_mark) # Write the tickLblPos element. - write_tick_label_pos(y_axis[:_label_position]) + write_tick_label_pos(y_axis.label_position) # Write the axis font elements. - write_axis_font(y_axis[:_num_font]) + write_axis_font(y_axis.num_font) # Write the c:crossAx element. write_cross_axis(axis_ids[0]) - write_crossing(x_axis[:_crossing]) + write_crossing(x_axis.crossing) # Write the c:crossBetween element. write_cross_between # Write the c:majorUnit element. - write_c_major_unit(y_axis[:_major_unit]) + write_c_major_unit(y_axis.major_unit) # Write the c:minorUnit element. - write_c_minor_unit(y_axis[:_minor_unit]) + write_c_minor_unit(y_axis.minor_unit) end end # # Write the <c:valAx> element. @@ -2199,104 +2263,64 @@ horiz = @horiz_val_axis return unless axis_ids && !axis_ids.empty? # Overwrite the default axis position with a user supplied value. - position = x_axis[:_position] || position + position = x_axis.position || position @writer.tag_elements('c:valAx') do write_axis_id(axis_ids[0]) # Write the c:scaling element. write_scaling_with_param(x_axis) - write_delete(1) unless ptrue?(x_axis[:_visible]) + write_delete(1) unless ptrue?(x_axis.visible) # Write the c:axPos element. - write_axis_pos(position, y_axis[:_reverse]) + write_axis_pos(position, y_axis.reverse) # Write the c:majorGridlines element. - write_major_gridlines(x_axis[:_major_gridlines]) + write_major_gridlines(x_axis.major_gridlines) # Write the c:minorGridlines element. - write_minor_gridlines(x_axis[:_minor_gridlines]) + write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis[:_formula] - write_title_formula(title, y_axis[:_data_id], horiz, x_axis[:_name_font]) - elsif title = x_axis[:_name] - write_title_rich(title, horiz, x_axis[:_name_font]) + if title = x_axis.formula + write_title_formula(title, y_axis.data_id, horiz, x_axis.name_font) + elsif title = x_axis.name + write_title_rich(title, horiz, x_axis.name_font) end # Write the c:numberFormat element. write_number_format(x_axis) # Write the c:majorTickMark element. - write_major_tick_mark(x_axis[:_major_tick_mark]) + write_major_tick_mark(x_axis.major_tick_mark) # Write the c:tickLblPos element. - write_tick_label_pos(x_axis[:_label_position]) + write_tick_label_pos(x_axis.label_position) # Write the axis font elements. - write_axis_font(x_axis[:_num_font]) + write_axis_font(x_axis.num_font) # Write the c:crossAx element. write_cross_axis(axis_ids[1]) - write_crossing(y_axis[:_crossing]) + write_crossing(y_axis.crossing) # Write the c:crossBetween element. write_cross_between # Write the c:majorUnit element. - write_c_major_unit(x_axis[:_major_unit]) + write_c_major_unit(x_axis.major_unit) # Write the c:minorunit element. - write_c_minor_unit(x_axis[:_minor_unit]) + write_c_minor_unit(x_axis.minor_unit) end end - def write_val_axis_common(position, hide_major_gridlines, params) # :nodoc: - position ||= @val_axis_position - horiz = @horiz_val_axis - - # Overwrite the default axis position with a user supplied value. - position = params[:axis_position] || position - - @writer.tag_elements('c:valAx') do - write_axis_id(params[:axis_id]) - # Write the c:scaling element. - write_scaling_with_param(params[:scaling_axis]) - - # Write the c:axPos element. - write_axis_pos(position, params[:axis_position_element]) - # Write the c:majorGridlines element. - write_major_gridlines unless hide_major_gridlines - # Write the axis title elements. - if title = params[:title_axis][:_formula] - write_title_formula(title, @y_axis[:_data_id], horiz) - elsif title = params[:title_axis][:_name] - write_title_rich(title, horiz) - end - # Write the c:numberFormat element. - write_number_format - # Write the c:tickLblPos element. - write_tick_label_pos(params[:tick_label_pos]) - # Write the c:crossAx element. - write_cross_axis(params[:cross_axis]) - - write_crossing(params[:category_crossing]) - - # Write the c:crossBetween element. - write_cross_between - # Write the c:majorUnit element. - write_c_major_unit(params[:major_unit]) - # Write the c:minorUnit element. - write_c_minor_unit(params[:minor_unit]) - end - end - # # Write the <c:dateAx> element. Usually the X axis. # def write_date_axis(params) # :nodoc: x_axis = params[:x_axis] @@ -2306,65 +2330,65 @@ return unless axis_ids && !axis_ids.empty? position = @cat_axis_position # Overwrite the default axis position with a user supplied value. - position = x_axis[:_position] || position + position = x_axis.position || position @writer.tag_elements('c:dateAx') do write_axis_id(axis_ids[0]) # Write the c:scaling element. write_scaling_with_param(x_axis) - write_delete(1) unless ptrue?(x_axis[:_visible]) + write_delete(1) unless ptrue?(x_axis.visible) # Write the c:axPos element. - write_axis_pos(position, y_axis[:reverse]) + write_axis_pos(position, y_axis.reverse) # Write the c:majorGridlines element. - write_major_gridlines(x_axis[:_major_gridlines]) + write_major_gridlines(x_axis.major_gridlines) # Write the c:minorGridlines element. - write_minor_gridlines(x_axis[:_minor_gridlines]) + write_minor_gridlines(x_axis.minor_gridlines) # Write the axis title elements. - if title = x_axis[:_formula] - write_title_formula(title, x_axis[:_data_id], nil, x_axis[:_name_font]) - elsif title = x_axis[:_name] - write_title_rich(title, nil, x_axis[:_name_font]) + if title = x_axis.formula + write_title_formula(title, x_axis.data_id, nil, x_axis.name_font) + elsif title = x_axis.name + write_title_rich(title, nil, x_axis.name_font) end # Write the c:numFmt element. write_number_format(x_axis) # Write the c:majorTickMark element. - write_major_tick_mark(x_axis[:_major_tick_mark]) + write_major_tick_mark(x_axis.major_tick_mark) # Write the c:tickLblPos element. - write_tick_label_pos(x_axis[:_label_position]) + write_tick_label_pos(x_axis.label_position) # Write the font elements. - write_axis_font(x_axis[:_num_font]) + write_axis_font(x_axis.num_font) # Write the c:crossAx element. write_cross_axis(axis_ids[1]) - if @show_crosses || ptrue?(x_axis[:_visible]) - write_crossing(y_axis[:_crossing]) + if @show_crosses || ptrue?(x_axis.visible) + write_crossing(y_axis.crossing) end # Write the c:auto element. write_auto(1) # Write the c:labelOffset element. write_label_offset(100) # Write the c:majorUnit element. - write_c_major_unit(x_axis[:_major_unit]) + 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]) + if !x_axis.major_unit.nil? + write_c_major_time_unit(x_axis.major_unit_type) end # Write the c:minorUnit element. - write_c_minor_unit(x_axis[:_minor_unit]) + 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]) + if !x_axis.minor_unit.nil? + write_c_minor_time_unit(x_axis.minor_unit_type) end end end def write_crossing(crossing) @@ -2378,14 +2402,14 @@ end end def write_scaling_with_param(param) write_scaling( - param[:_reverse], - param[:_min], - param[:_max], - param[:_log_base] + param.reverse, + param.min, + param.max, + param.log_base ) end # # Write the <c:scaling> element. # @@ -2406,46 +2430,38 @@ # Write the <c:logBase> element. # def write_c_log_base(val) # :nodoc: return unless ptrue?(val) - attributes = ['val', val] - - @writer.empty_tag('c:logBase', attributes) + @writer.empty_tag('c:logBase', ['val', val]) end # # Write the <c:orientation> element. # def write_orientation(reverse = nil) # :nodoc: val = ptrue?(reverse) ? 'maxMin' : 'minMax' - attributes = ['val', val] - - @writer.empty_tag('c:orientation', attributes) + @writer.empty_tag('c:orientation', ['val', val]) end # # Write the <c:max> element. # def write_c_max(max = nil) # :nodoc: return if max.nil? - attributes = ['val', max] - - @writer.empty_tag('c:max', attributes) + @writer.empty_tag('c:max', ['val', max]) end # # Write the <c:min> element. # def write_c_min(min = nil) # :nodoc: return if min.nil? - attributes = ['val', min] - - @writer.empty_tag('c:min', attributes) + @writer.empty_tag('c:min', ['val', min]) end # # Write the <c:axPos> element. # @@ -2453,234 +2469,156 @@ if reverse val = 'r' if val == 'l' val = 't' if val == 'b' end - attributes = ['val', val] - - @writer.empty_tag('c:axPos', attributes) + @writer.empty_tag('c:axPos', ['val', val]) end # # Write the <c:numberFormat> element. Note: It is assumed that if a user # defined number format is supplied (i.e., non-default) then the sourceLinked # attribute is 0. The user can override this if required. # def write_number_format(axis) # :nodoc: - format_code = axis[:_num_format] - source_linked = 1 - - # Check if a user defined number format has been set. - if axis[:_defaults] && format_code != axis[:_defaults][:num_format] - source_linked = 0 - end - - # User override of sourceLinked. - if ptrue?(axis[:_num_format_linked]) - source_linked = 1 - end - - attributes = [ - 'formatCode', format_code, - 'sourceLinked', source_linked - ] - - @writer.empty_tag('c:numFmt', attributes) + axis.write_number_format(@writer) end # # Write the <c:numFmt> element. Special case handler for category axes which # don't always have a number format. # def write_cat_number_format(axis) - format_code = axis[:_num_format] - source_linked = 1 - default_format = true - - # Check if a user defined number format has been set. - if axis[:_defaults] && format_code != axis[:_defaults][:num_format] - source_linked = 0 - default_format = false - end - - # User override of linkedSource. - if axis[:_num_format_linked] - source_linked = 1 - end - - # Skip if cat doesn't have a num format (unless it is non-default). - if !@cat_has_num_fmt && default_format - return '' - end - - attributes = [ - 'formatCode', format_code, - 'sourceLinked', source_linked, - ] - - @writer.empty_tag('c:numFmt', attributes) + axis.write_cat_number_format(@writer, @cat_has_num_fmt) end # # Write the <c:majorTickMark> element. # def write_major_tick_mark(val) return unless ptrue?(val) - attributes = ['val', val] - - @writer.empty_tag('c:majorTickMark', attributes) + @writer.empty_tag('c:majorTickMark', ['val', val]) end # # Write the <c:tickLblPos> element. # def write_tick_label_pos(val) # :nodoc: val ||= 'nextTo' val = 'nextTo' if val == 'next_to' - attributes = ['val', val] - - @writer.empty_tag('c:tickLblPos', attributes) + @writer.empty_tag('c:tickLblPos', ['val', val]) end # # Write the <c:crossAx> element. # def write_cross_axis(val = 'autoZero') # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:crossAx', attributes) + @writer.empty_tag('c:crossAx', ['val', val]) end # # Write the <c:crosses> element. # def write_crosses(val) # :nodoc: val ||= 'autoZero' - attributes = ['val', val] - - @writer.empty_tag('c:crosses', attributes) + @writer.empty_tag('c:crosses', ['val', val]) end # # Write the <c:crossesAt> element. # def write_c_crosses_at(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:crossesAt', attributes) + @writer.empty_tag('c:crossesAt', ['val', val]) end # # Write the <c:auto> element. # def write_auto(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:auto', attributes) + @writer.empty_tag('c:auto', ['val', val]) end # # Write the <c:labelAlign> element. # def write_label_align(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:lblAlgn', attributes) + @writer.empty_tag('c:lblAlgn', ['val', val]) end # # Write the <c:labelOffset> element. # def write_label_offset(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:lblOffset', attributes) + @writer.empty_tag('c:lblOffset', ['val', val]) end # # Write the <c:majorGridlines> element. # def write_major_gridlines(gridlines) # :nodoc: - write_gridlines_common(gridlines, 'c:majorGridlines') + write_gridlines_base('c:majorGridlines', gridlines) end # # Write the <c:minorGridlines> element. # def write_minor_gridlines(gridlines) # :nodoc: - write_gridlines_common(gridlines, 'c:minorGridlines') + write_gridlines_base('c:minorGridlines', gridlines) end - def write_gridlines_common(gridlines, tag) # :nodoc: - return unless gridlines - return unless ptrue?(gridlines[:_visible]) - - if gridlines[:_line] && ptrue?(gridlines[:_line][:_defined]) - @writer.tag_elements(tag) do - # Write the c:spPr element. - write_sp_pr(gridlines) - end - else - @writer.empty_tag(tag) - end + def write_gridlines_base(tag, gridlines) # :nodoc: + return if gridlines.respond_to?(:[]) and !ptrue?(gridlines[:_visible]) + write_lines_base(tag, gridlines) end # # Write the <c:crossBetween> element. # def write_cross_between # :nodoc: val = @cross_between || 'between' - attributes = ['val', val] - - @writer.empty_tag('c:crossBetween', attributes) + @writer.empty_tag('c:crossBetween', ['val', val]) end # # Write the <c:majorUnit> element. # def write_c_major_unit(val = nil) # :nodoc: return unless val - attributes = ['val', val] - - @writer.empty_tag('c:majorUnit', attributes) + @writer.empty_tag('c:majorUnit', ['val', val]) end # # Write the <c:minorUnit> element. # def write_c_minor_unit(val = nil) # :nodoc: return unless val - attributes = ['val', val] - - @writer.empty_tag('c:minorUnit', attributes) + @writer.empty_tag('c:minorUnit', ['val', val]) end # # Write the <c:majorTimeUnit> element. # def write_c_major_time_unit(val) # :nodoc: val ||= 'days' - attributes = ['val', val] - @writer.empty_tag('c:majorTimeUnit', attributes) + @writer.empty_tag('c:majorTimeUnit', ['val', val]) end # # Write the <c:minorTimeUnit> element. # def write_c_minor_time_unit(val) # :nodoc: val ||= 'days' - attributes = ['val', val] - @writer.empty_tag('c:minorTimeUnit', attributes) + @writer.empty_tag('c:minorTimeUnit', ['val', val]) end # # Write the <c:legend> element. # @@ -2726,13 +2664,11 @@ # # Write the <c:legendPos> element. # def write_legend_pos(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:legendPos', attributes) + @writer.empty_tag('c:legendPos', ['val', val]) end # # Write the <c:legendEntry> element. # @@ -2747,15 +2683,11 @@ # # Write the <c:overlay> element. # def write_overlay # :nodoc: - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:overlay', attributes) + @writer.empty_tag('c:overlay', ['val', 1]) end # # Write the <c:plotVisOnly> element. # @@ -2763,13 +2695,11 @@ val = 1 # Ignore this element if we are plotting hidden data. return if @show_hidden_data - attributes = ['val', val] - - @writer.empty_tag('c:plotVisOnly', attributes) + @writer.empty_tag('c:plotVisOnly', ['val', val]) end # # Write the <c:printSettings> element. # @@ -2958,15 +2888,11 @@ # # Write the <a:endParaRPr> element. # def write_a_end_para_rpr # :nodoc: - lang = 'en-US' - - attributes = ['lang', lang] - - @writer.empty_tag('a:endParaRPr', attributes) + @writer.empty_tag('a:endParaRPr', ['lang', 'en-US']) end # # Write the <a:r> element. # @@ -3051,35 +2977,27 @@ # # Write the <c:marker> element without a sub-element. # def write_marker_value # :nodoc: - style = @default_marker + return unless @default_marker - return unless style - - attributes = ['val', 1] - - @writer.empty_tag('c:marker', attributes) + @writer.empty_tag('c:marker', ['val', 1]) end # # Write the <c:size> element. # def write_marker_size(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:size', attributes) + @writer.empty_tag('c:size', ['val', val]) end # # Write the <c:symbol> element. # def write_symbol(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:symbol', attributes) + @writer.empty_tag('c:symbol', ['val', val]) end # # Write the <c:spPr> element. # @@ -3160,22 +3078,18 @@ # # Write the <a:srgbClr> element. # def write_a_srgb_clr(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('a:srgbClr', attributes) + @writer.empty_tag('a:srgbClr', ['val', val]) end # # Write the <a:prstDash> element. # def write_a_prst_dash(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('a:prstDash', attributes) + @writer.empty_tag('a:prstDash', ['val', val]) end # # Write the <c:trendline> element. # @@ -3202,13 +3116,11 @@ # # Write the <c:trendlineType> element. # def write_trendline_type(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:trendlineType', attributes) + @writer.empty_tag('c:trendlineType', ['val', val]) end # # Write the <c:name> element. # @@ -3220,65 +3132,73 @@ # # Write the <c:order> element. # def write_trendline_order(val = 2) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:order', attributes) + @writer.empty_tag('c:order', ['val', val]) end # # Write the <c:period> element. # def write_period(val = 2) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:period', attributes) + @writer.empty_tag('c:period', ['val', val]) end # # Write the <c:forward> element. # def write_forward(val) # :nodoc: return unless val - attributes = ['val', val] - - @writer.empty_tag('c:forward', attributes) + @writer.empty_tag('c:forward', ['val', val]) end # # Write the <c:backward> element. # def write_backward(val) # :nodoc: return unless val - attributes = ['val', val] - - @writer.empty_tag('c:backward', attributes) + @writer.empty_tag('c:backward', ['val', val]) end # # Write the <c:hiLowLines> element. # def write_hi_low_lines # :nodoc: - @writer.empty_tag('c:hiLowLines') + write_lines_base('c:hiLowLines', @hi_low_lines) end # - # Write the <c:overlap> element. + # Write the <c:dropLines> elent. # - def write_overlap # :nodoc: - val = 100 + def write_drop_lines + write_lines_base('c:dropLines', @drop_lines) + end - attributes = ['val', val] + # + # used from write_drop_lines and write_hi_low_lines + # + def write_lines_base(tag, lines) + return unless lines - @writer.empty_tag('c:overlap', attributes) + if lines[:_line] && ptrue?(lines[:_line][:_defined]) + @writer.tag_elements(tag) { write_sp_pr(lines) } + else + @writer.empty_tag(tag) + end end # + # Write the <c:overlap> element. + # + def write_overlap # :nodoc: + @writer.empty_tag('c:overlap', ['val', 100]) + end + + # # Write the <c:numCache> element. # def write_num_cache(data) # :nodoc: @writer.tag_elements('c:numCache') do @@ -3326,13 +3246,11 @@ # # Write the <c:ptCount> element. # def write_pt_count(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:ptCount', attributes) + @writer.empty_tag('c:ptCount', ['val', val]) end # # Write the <c:pt> element. # @@ -3359,10 +3277,36 @@ @writer.empty_tag('c:protection') end # + # Write the <c:dPt> elements. + # + def write_d_pt(points = nil) + return unless ptrue?(points) + + index = -1 + points.each do |point| + index += 1 + next unless ptrue?(point) + + write_d_pt_point(index, point) + end + end + + # + # Write an individual <c:dPt> element. + # + def write_d_pt_point(index, point) + @writer.tag_elements('c:dPt') do + # Write the c:idx element. + write_idx(index) + # Write the c:spPr element. + write_sp_pr(point) + end + end + # # Write the <c:dLbls> element. # def write_d_lbls(labels) # :nodoc: return unless labels @@ -3384,90 +3328,62 @@ # # Write the <c:showVal> element. # def write_show_val # :nodoc: - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:showVal', attributes) + @writer.empty_tag('c:showVal', ['val', 1]) end # # Write the <c:showCatName> element. # def write_show_cat_name # :nodoc: - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:showCatName', attributes) + @writer.empty_tag('c:showCatName', ['val', 1]) end # # Write the <c:showSerName> element. # def write_show_ser_name # :nodoc: - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:showSerName', attributes) + @writer.empty_tag('c:showSerName', ['val', 1]) end # # Write the <c:showPercent> element. # def write_show_percent - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:showPercent', attributes) + @writer.empty_tag('c:showPercent', ['val', 1]) end # # Write the <c:showLeaderLines> element. # def write_show_leader_lines - val = 1 - - attributes = ['val', val] - - @writer.empty_tag('c:showLeaderLines', attributes) + @writer.empty_tag('c:showLeaderLines', ['val', 1]) end # # Write the <c:dLblPos> element. # def write_d_lbl_pos(val) - attributes = ['val', val] - - @writer.empty_tag('c:dLblPos', attributes) + @writer.empty_tag('c:dLblPos', ['val', val]) end # # Write the <c:delete> element. # def write_delete(val) # :nodoc: - attributes = ['val', val] - - @writer.empty_tag('c:delete', attributes) + @writer.empty_tag('c:delete', ['val', val]) end # # Write the <c:invertIfNegative> element. # def write_c_invert_if_negative(invert = nil) # :nodoc: - val = 1 + return unless ptrue?(invert) - return unless invert && invert != 0 - - attributes = ['val', val] - - @writer.empty_tag('c:invertIfNegative', attributes) + @writer.empty_tag('c:invertIfNegative', ['val', 1]) end # # Write the axis font elements. # @@ -3494,9 +3410,136 @@ # # Write the <c:dTable> element. # def write_d_table @table.write_d_table(@writer) if @table + end + + # + # Write the X and Y error bars. + # + def write_error_bars(error_bars) + return unless ptrue?(error_bars) + + if error_bars[:_x_error_bars] + write_err_bars('x', error_bars[:_x_error_bars]) + end + if error_bars[:_y_error_bars] + write_err_bars('y', error_bars[:_y_error_bars]) + end + end + + # + # Write the <c:errBars> element. + # + def write_err_bars(direction, error_bars) + return unless ptrue?(error_bars) + + @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 the c:errValType element. + write_err_val_type(error_bars[:_type]) + + unless ptrue?(error_bars[:_endcap]) + # Write the c:noEndCap element. + write_no_end_cap + end + + if error_bars[:_type] != 'stdErr' + # Write the c:val element. + write_error_val(error_bars[:_value]) + end + + # Write the c:spPr element. + write_sp_pr(error_bars) + end + end + + # + # Write the <c:errDir> element. + # + def write_err_dir(val) + @writer.empty_tag('c:errDir', ['val', val]) + end + + # + # Write the <c:errBarType> element. + # + def write_err_bar_type(val) + @writer.empty_tag('c:errBarType', ['val', val]) + end + + # + # Write the <c:errValType> element. + # + def write_err_val_type(val) + @writer.empty_tag('c:errValType', ['val', val]) + end + + # + # Write the <c:noEndCap> element. + # + def write_no_end_cap + @writer.empty_tag('c:noEndCap', ['val', 1]) + end + + # + # Write the <c:val> element. + # + def write_error_val(val) + @writer.empty_tag('c:val', ['val', val]) + end + + # + # Write the <c:upDownBars> element. + # + def write_up_down_bars + return unless ptrue?(@up_down_bars) + + @writer.tag_elements('c:upDownBars') do + # Write the c:gapWidth element. + write_gap_width + + # Write the c:upBars element. + write_up_bars(@up_down_bars[:_up]) + + # Write the c:downBars element. + write_down_bars(@up_down_bars[:_down]) + end + end + + # + # Write the <c:gapWidth> element. + # + def write_gap_width + @writer.empty_tag('c:gapWidth', ['val', 150]) + end + + # + # Write the <c:upBars> element. + # + def write_up_bars(format) + write_bars_base('c:upBars', format) + end + + # + # Write the <c:upBars> element. + # + def write_down_bars(format) + write_bars_base('c:downBars', format) + end + + def write_bars_base(tag, format) + if ptrue?(format[:_line][:_defined]) || ptrue?(format[:_fill][:_defined]) + @writer.tag_elements(tag) { write_sp_pr(format) } + else + @writer.empty_tag(tag) + end end def nil_or_max?(val) # :nodoc: val.nil? || val == 'max' end