lib/write_xlsx/chart/series.rb in write_xlsx-0.75.0 vs lib/write_xlsx/chart/series.rb in write_xlsx-0.76.0
- old
+ new
@@ -1,281 +1,263 @@
# -*- coding: utf-8 -*-
-class Series
- include Writexlsx::Utility
+module Writexlsx
+ class Chart
+ class Chartline
+ include Writexlsx::Utility
- attr_reader :values, :categories, :name, :name_formula, :name_id
- attr_reader :cat_data_id, :val_data_id, :fill
- attr_reader :trendline, :smooth, :labels, :invert_if_neg
- attr_reader :x2_axis, :y2_axis, :error_bars, :points
- attr_accessor :line, :marker
+ attr_reader :line, :fill, :type
- def initialize(chart, params = {})
- @values = aref_to_formula(params[:values])
- @categories = aref_to_formula(params[:categories])
- @name, @name_formula =
- chart.process_names(params[:name], params[:name_formula])
- @cat_data_id = chart.get_data_id(@categories, params[:categories_data])
- @val_data_id = chart.get_data_id(@values, params[:values_data])
- @name_id = chart.get_data_id(@name_formula, params[:name_data])
- if params[:border]
- @line = line_properties(params[:border])
- else
- @line = line_properties(params[:line])
+ def initialize(params)
+ @line = params[:line]
+ @fill = params[:fill]
+ # Set the line properties for the marker..
+ @line = line_properties(@line)
+ # Allow 'border' as a synonym for 'line'.
+ @line = line_properties(params[:border]) if params[:border]
+
+ # Set the fill properties for the marker.
+ @fill = fill_properties(@fill)
+ end
+
+ def line_defined?
+ line && ptrue?(line[:_defined])
+ end
+
+ def fill_defined?
+ fill && ptrue?(fill[:_defined])
+ end
end
- @fill = fill_properties(params[:fill])
- @marker = marker_properties(params[:marker])
- @trendline = trendline_properties(params[:trendline])
- @smooth = params[:smooth]
- @error_bars = {
- :_x_error_bars => error_bars_properties(params[:x_error_bars]),
- :_y_error_bars => error_bars_properties(params[:y_error_bars])
- }
- @points = points_properties(params[:points])
- @labels = labels_properties(params[:data_labels])
- @invert_if_neg = params[:invert_if_negative]
- @x2_axis = params[:x2_axis]
- @y2_axis = params[:y2_axis]
- end
- def ==(other)
- methods = %w[categories values name name_formula name_id
- cat_data_id val_data_id
- line fill marker trendline
- smooth labels invert_if_neg x2_axis y2_axis error_bars points ]
- methods.each do |method|
- return false unless self.instance_variable_get("@#{method}") == other.instance_variable_get("@#{method}")
+ class Point < Chartline
end
- true
- end
- private
+ class Gridline < Chartline
+ attr_reader :visible
- #
- # 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
+ def initialize(params)
+ super(params)
+ @visible = params[:visible]
+ end
+ end
- #
- # Convert user defined fill properties to the structure required internally.
- #
- def fill_properties(fill) # :nodoc:
- return { :_defined => 0 } unless fill
+ class Trendline < Chartline
+ attr_reader :name, :forward, :backward, :order, :period
- fill[:_defined] = 1
+ def initialize(params)
+ super(params)
- fill
- end
+ @name = params[:name]
+ @forward = params[:forward]
+ @backward = params[:backward]
+ @order = params[:order]
+ @period = params[:period]
+ @type = value_or_raise(types, params[:type], 'trendline type')
+ end
- #
- # Convert user defined marker properties to the structure required internally.
- #
- def marker_properties(marker) # :nodoc:
- return unless marker
+ private
- types = {
- :automatic => 'automatic',
- :none => 'none',
- :square => 'square',
- :diamond => 'diamond',
- :triangle => 'triangle',
- :x => 'x',
- :star => 'star',
- :dot => 'dot',
- :short_dash => 'dot',
- :dash => 'dash',
- :long_dash => 'dash',
- :circle => 'circle',
- :plus => 'plus',
- :picture => 'picture'
- }
+ def types
+ {
+ :exponential => 'exp',
+ :linear => 'linear',
+ :log => 'log',
+ :moving_average => 'movingAvg',
+ :polynomial => 'poly',
+ :power => 'power'
+ }
+ end
+ end
- # Check for valid types.
- marker_type = marker[:type]
+ class Marker < Chartline
+ attr_reader :size
- if marker_type
- marker[:automatic] = 1 if marker_type == 'automatic'
- marker[:type] = value_or_raise(types, marker_type, 'maker type')
- end
+ def initialize(params)
+ super(params)
- # Set the line properties for the marker..
- line = line_properties(marker[:line])
+ if params[:type]
+ @type = value_or_raise(types, params[:type], 'maker type')
+ end
- # Allow 'border' as a synonym for 'line'.
- line = line_properties(marker[:border]) if marker[:border]
+ @size = params[:size]
+ @automatic = false
+ @automatic = true if @type == 'automatic'
+ end
- # Set the fill properties for the marker.
- fill = fill_properties(marker[:fill])
+ def automatic?
+ @automatic
+ end
- marker[:_line] = line
- marker[:_fill] = fill
+ private
- marker
- end
+ def types
+ {
+ :automatic => 'automatic',
+ :none => 'none',
+ :square => 'square',
+ :diamond => 'diamond',
+ :triangle => 'triangle',
+ :x => 'x',
+ :star => 'star',
+ :dot => 'dot',
+ :short_dash => 'dot',
+ :dash => 'dash',
+ :long_dash => 'dash',
+ :circle => 'circle',
+ :plus => 'plus',
+ :picture => 'picture'
+ }
+ end
+ end
- #
- # Convert user defined trendline properties to the structure required internally.
- #
- def trendline_properties(trendline) # :nodoc:
- return unless trendline
+ class Errorbars
+ include Writexlsx::Utility
- types = {
- :exponential => 'exp',
- :linear => 'linear',
- :log => 'log',
- :moving_average => 'movingAvg',
- :polynomial => 'poly',
- :power => 'power'
- }
+ attr_reader :type, :direction, :endcap, :value, :line, :fill
+ attr_reader :plus_values, :minus_values, :plus_data, :minus_data
- # Check the trendline type.
- trend_type = trendline[:type]
+ def initialize(params)
+ @type = types[params[:type].to_sym] || 'fixedVal'
+ @value = params[:value] || 1 # value for error types that require it.
+ @endcap = params[:end_style] || 1 # end-cap style.
- trendline[:type] = value_or_raise(types, trend_type, 'trendline type')
+ # Set the error bar direction.
+ @direction = error_bar_direction(params[:direction])
- # Set the line properties for the trendline..
- line = line_properties(trendline[:line])
+ # Set any custom values
+ @plus_values = params[:plus_values] || [1]
+ @minus_values = params[:minus_values] || [1]
+ @plus_data = params[:plus_data] || []
+ @minus_data = params[:minus_data] || []
- # Allow 'border' as a synonym for 'line'.
- line = line_properties(trendline[:border]) if trendline[:border]
+ # Set the line properties for the error bars.
+ @line = line_properties(params[:line])
+ @fill = params[:fill]
+ end
- # Set the fill properties for the trendline.
- fill = fill_properties(trendline[:fill])
+ private
- trendline[:_line] = line
- trendline[:_fill] = fill
+ def types
+ {
+ :fixed => 'fixedVal',
+ :percentage => 'percentage',
+ :standard_deviation => 'stdDev',
+ :standard_error => 'stdErr',
+ :custom => 'cust'
+ }
+ end
- return trendline
- end
+ def error_bar_direction(direction)
+ case direction
+ when 'minus'
+ 'minus'
+ when 'plus'
+ 'plus'
+ else
+ 'both'
+ end
+ end
+ end
- #
- # Convert user defined error bars properties to structure required
- # internally.
- #
- def error_bars_properties(params = {})
- return if !ptrue?(params) || params.empty?
+ class Series
+ include Writexlsx::Utility
- # Default values.
- error_bars = {
- :_type => 'fixedVal',
- :_value => 1,
- :_endcap => 1,
- :_direction => 'both',
- :_plus_values => [1],
- :_minus_values => [1],
- :_plus_data => [],
- :_minus_data => []
- }
+ attr_reader :values, :categories, :name, :name_formula, :name_id
+ attr_reader :cat_data_id, :val_data_id, :fill
+ attr_reader :trendline, :smooth, :labels, :invert_if_negative
+ attr_reader :x2_axis, :y2_axis, :error_bars, :points
+ attr_accessor :line, :marker
- types = {
- :fixed => 'fixedVal',
- :percentage => 'percentage',
- :standard_deviation => 'stdDev',
- :standard_error => 'stdErr',
- :custom => 'cust'
- }
+ def initialize(chart, params = {})
+ @values = aref_to_formula(params[:values])
+ @categories = aref_to_formula(params[:categories])
+ @name, @name_formula =
+ chart.process_names(params[:name], params[:name_formula])
- # Check the error bars type.
- error_type = params[:type].to_sym
+ set_data_ids(chart, params)
- if types.key?(error_type)
- error_bars[:_type] = types[error_type]
- else
- raise "Unknown error bars type '#{error_type}'\n"
- end
+ @line = line_properties(params[:border] || params[:line])
+ @fill = fill_properties(params[:fill])
- # Set the value for error types that require it.
- if params.key?(:value)
- error_bars[:_value] = params[:value]
- end
+ @marker = Marker.new(params[:marker]) if params[:marker]
+ @trendline = Trendline.new(params[:trendline]) if params[:trendline]
+ @error_bars = errorbars(params[:x_error_bars], params[:y_error_bars])
+ @points = params[:points].collect { |p| p ? Point.new(p) : p } if params[:points]
+ @labels = labels_properties(params[:data_labels])
- # Set the end-cap style.
- if params.key?(:end_style)
- error_bars[:_endcap] = params[:end_style]
- end
+ [:smooth, :invert_if_negative, :x2_axis, :y2_axis].
+ each { |key| instance_variable_set("@#{key}", params[key]) }
+ 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'
+ def ==(other)
+ methods = %w[categories values name name_formula name_id
+ cat_data_id val_data_id
+ line fill marker trendline
+ smooth labels invert_if_neg x2_axis y2_axis error_bars points ]
+ methods.each do |method|
+ return false unless self.instance_variable_get("@#{method}") == other.instance_variable_get("@#{method}")
+ end
+ true
end
- end
- # Set any custom values
- error_bars[:_plus_values] = params[:plus_values] if params[:plus_values]
- error_bars[:_minus_values] = params[:minus_values] if params[:minus_values]
- error_bars[:_plus_data] = params[:plus_data] if params[:plus_data]
- error_bars[:_minus_data] = params[:minus_data] if params[:minus_data]
+ def line_defined?
+ line && ptrue?(line[:_defined])
+ end
- # Set the line properties for the error bars.
- error_bars[:_line] = line_properties(params[:line])
+ private
- error_bars
- end
+ #
+ # 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
- #
- # Convert user defined points properties to structure required internally.
- #
- def points_properties(user_points = nil)
- return unless user_points
+ def set_data_ids(chart, params)
+ @cat_data_id = chart.data_id(@categories, params[:categories_data])
+ @val_data_id = chart.data_id(@values, params[:values_data])
+ @name_id = chart.data_id(@name_formula, params[:name_data])
+ end
- points = []
- user_points.each do |user_point|
- if user_point
- # Set the lline properties for the point.
- line = line_properties(user_point[:line])
+ def errorbars(x, y)
+ {
+ :_x_error_bars => x ? Errorbars.new(x) : nil,
+ :_y_error_bars => y ? Errorbars.new(y) : nil
+ }
+ end
- # Allow 'border' as a synonym for 'line'.
- if user_point[:border]
- line = line_properties(user_point[:border])
+ #
+ # Convert user defined labels properties to the structure required internally.
+ #
+ def labels_properties(labels) # :nodoc:
+ return nil unless labels
+
+ position = labels[:position]
+ if position.nil? || position.empty?
+ labels.delete(:position)
+ else
+ # Map user defined label positions to Excel positions.
+ labels[:position] = value_or_raise(positions, position, 'label position')
end
- # Set the fill properties for the chartarea.
- fill = fill_properties(user_point[:fill])
+ labels
+ end
- point = {}
- point[:_line] = line
- point[:_fill] = fill
+ def positions
+ {
+ :center => 'ctr',
+ :right => 'r',
+ :left => 'l',
+ :top => 't',
+ :above => 't',
+ :bottom => 'b',
+ :below => 'b',
+ :inside_end => 'inEnd',
+ :outside_end => 'outEnd',
+ :best_fit => 'bestFit'
+ }
end
- points << point
end
- points
- end
-
- #
- # Convert user defined labels properties to the structure required internally.
- #
- def labels_properties(labels) # :nodoc:
- return nil unless labels
-
- position = labels[:position]
- if position.nil? || position.empty?
- labels.delete(:position)
- else
- # Map user defined label positions to Excel positions.
- positions = {
- :center => 'ctr',
- :right => 'r',
- :left => 'l',
- :top => 't',
- :above => 't',
- :bottom => 'b',
- :below => 'b',
- :inside_end => 'inEnd',
- :outside_end => 'outEnd',
- :best_fit => 'bestFit'
- }
-
- labels[:position] = value_or_raise(positions, position, 'label position')
- end
-
- labels
end
end