diff options
| author | Randy Morgan <[email protected]> | 2013-03-17 15:38:55 +0900 |
|---|---|---|
| committer | Randy Morgan <[email protected]> | 2013-03-17 15:38:55 +0900 |
| commit | ae75ef360e3e0da253188d408a3cbc81ed3897e6 (patch) | |
| tree | 9bf184d72c4a78b3f14731af511aad26002a51ad /lib | |
| parent | 17f135ab215ba05b85ef92a15ed0038ea7556de9 (diff) | |
| download | caxlsx-ae75ef360e3e0da253188d408a3cbc81ed3897e6.tar.gz caxlsx-ae75ef360e3e0da253188d408a3cbc81ed3897e6.zip | |
Fixed LineChart and refactored chart axes management
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/axlsx/drawing/axes.rb | 40 | ||||
| -rw-r--r-- | lib/axlsx/drawing/axis.rb | 27 | ||||
| -rw-r--r-- | lib/axlsx/drawing/bar_3D_chart.rb | 25 | ||||
| -rw-r--r-- | lib/axlsx/drawing/cat_axis.rb | 12 | ||||
| -rw-r--r-- | lib/axlsx/drawing/d_lbls.rb | 2 | ||||
| -rw-r--r-- | lib/axlsx/drawing/drawing.rb | 1 | ||||
| -rw-r--r-- | lib/axlsx/drawing/line_3D_chart.rb | 54 | ||||
| -rw-r--r-- | lib/axlsx/drawing/line_chart.rb | 51 | ||||
| -rw-r--r-- | lib/axlsx/drawing/line_series.rb | 1 | ||||
| -rw-r--r-- | lib/axlsx/drawing/scatter_chart.rb | 41 | ||||
| -rw-r--r-- | lib/axlsx/drawing/ser_axis.rb | 31 | ||||
| -rw-r--r-- | lib/axlsx/drawing/val_axis.rb | 27 |
12 files changed, 181 insertions, 131 deletions
diff --git a/lib/axlsx/drawing/axes.rb b/lib/axlsx/drawing/axes.rb new file mode 100644 index 00000000..99565cb6 --- /dev/null +++ b/lib/axlsx/drawing/axes.rb @@ -0,0 +1,40 @@ +module Axlsx + + class Axes + + def initialize(options={}) + options.each do |name, axis_class| + add_axis(name, axis_class) + end + end + + def [](name) + axes.assoc(name)[1] + end + + def to_xml_string(str = '', options = {}) + if options[:ids] + axes.inject(str) { |string, axis| string << '<c:axId val="' << axis[1].id.to_s << '"/>' } + else + axes.each { |axis| axis[1].to_xml_string(str) } + end + end + + def add_axis(name, axis_class) + axis = axis_class.new + set_cross_axis(axis) + axes << [name, axis] + end + + private + + def axes + @axes ||= [] + end + + def set_cross_axis(axis) + axes.first[1].cross_axis = axis if axes.size == 1 + axis.cross_axis = axes.first[1] unless axes.empty? + end + end +end diff --git a/lib/axlsx/drawing/axis.rb b/lib/axlsx/drawing/axis.rb index 1b55bece..16c087a2 100644 --- a/lib/axlsx/drawing/axis.rb +++ b/lib/axlsx/drawing/axis.rb @@ -7,17 +7,13 @@ module Axlsx include Axlsx::OptionsParser # Creates an Axis object - # @param [Integer] ax_id the id of this axis - # @param [Integer] cross_ax the id of the perpendicular axis + # @param [Integer] cross_axis the perpendicular axis # @option options [Symbol] ax_pos # @option options [Symbol] crosses # @option options [Symbol] tick_lbl_pos # @raise [ArgumentError] If axi_id or cross_ax are not unsigned integers - def initialize(ax_id, cross_ax, options={}) - Axlsx::validate_unsigned_int(ax_id) - Axlsx::validate_unsigned_int(cross_ax) - @ax_id = ax_id - @cross_ax = cross_ax + def initialize(options={}) + @id = rand(8 ** 8) @format_code = "General" @delete = @label_rotation = 0 @scaling = Scaling.new(:orientation=>:minMax) @@ -37,13 +33,13 @@ module Axlsx # the id of the axis. # @return [Integer] - attr_reader :ax_id - alias :axID :ax_id + attr_reader :id + alias :axID :id # The perpendicular axis # @return [Integer] - attr_reader :cross_ax - alias :crossAx :cross_ax + attr_reader :cross_axis + alias :crossAx :cross_axis # The scaling of the axis # @see Scaling @@ -95,6 +91,11 @@ module Axlsx @color = color_rgb end + def cross_axis=(axis) + DataTypeValidator.validate "#{self.class}.cross_axis", [Axis], axis + @cross_axis = axis + end + # The position of the axis # must be one of [:l, :r, :t, :b] def ax_pos=(v) RestrictionValidator.validate "#{self.class}.ax_pos", [:l, :r, :b, :t], v; @ax_pos = v; end @@ -147,7 +148,7 @@ module Axlsx # @param [String] str # @return [String] def to_xml_string(str = '') - str << '<c:axId val="' << @ax_id.to_s << '"/>' + str << '<c:axId val="' << @id.to_s << '"/>' @scaling.to_xml_string str str << '<c:delete val="'<< @delete.to_s << '"/>' str << '<c:axPos val="' << @ax_pos.to_s << '"/>' @@ -175,7 +176,7 @@ module Axlsx end # some potential value in implementing this in full. Very detailed! str << '<c:txPr><a:bodyPr rot="' << @label_rotation.to_s << '"/><a:lstStyle/><a:p><a:pPr><a:defRPr/></a:pPr><a:endParaRPr/></a:p></c:txPr>' - str << '<c:crossAx val="' << @cross_ax.to_s << '"/>' + str << '<c:crossAx val="' << @cross_axis.id.to_s << '"/>' str << '<c:crosses val="' << @crosses.to_s << '"/>' end diff --git a/lib/axlsx/drawing/bar_3D_chart.rb b/lib/axlsx/drawing/bar_3D_chart.rb index 6f69f703..0e2b37bb 100644 --- a/lib/axlsx/drawing/bar_3D_chart.rb +++ b/lib/axlsx/drawing/bar_3D_chart.rb @@ -10,12 +10,16 @@ module Axlsx # the category axis # @return [CatAxis] - attr_reader :cat_axis + def cat_axis + axes[:cat_axis] + end alias :catAxis :cat_axis # the value axis # @return [ValAxis] - attr_reader :val_axis + def val_axis + axes[:val_axis] + end alias :valAxis :val_axis # The direction of the bars in the chart @@ -75,10 +79,6 @@ module Axlsx def initialize(frame, options={}) @vary_colors = true @gap_width, @gap_depth, @shape = nil, nil, nil - @cat_ax_id = rand(8 ** 8) - @val_ax_id = rand(8 ** 8) - @cat_axis = CatAxis.new(@cat_ax_id, @val_ax_id) - @val_axis = ValAxis.new(@val_ax_id, @cat_ax_id, :tick_lbl_pos => :low, :ax_pos => :l) super(frame, options) @series_type = BarSeries @view_3D = View3D.new({:r_ang_ax=>1}.merge(options)) @@ -131,17 +131,18 @@ module Axlsx str_inner << '<c:grouping val="' << grouping.to_s << '"/>' str_inner << '<c:varyColors val="' << vary_colors.to_s << '"/>' @series.each { |ser| ser.to_xml_string(str_inner) } - @d_lbls.to_xml_string(str) if @d_lbls + @d_lbls.to_xml_string(str_inner) if @d_lbls str_inner << '<c:gapWidth val="' << @gap_width.to_s << '"/>' unless @gap_width.nil? str_inner << '<c:gapDepth val="' << @gap_depth.to_s << '"/>' unless @gap_depth.nil? str_inner << '<c:shape val="' << @shape.to_s << '"/>' unless @shape.nil? - str_inner << '<c:axId val="' << @cat_ax_id.to_s << '"/>' - str_inner << '<c:axId val="' << @val_ax_id.to_s << '"/>' - str_inner << '<c:axId val="0"/>' + axes.to_xml_string(str_inner, :ids => true) str_inner << '</c:bar3DChart>' - @cat_axis.to_xml_string str_inner - @val_axis.to_xml_string str_inner + axes.to_xml_string(str_inner) end end + + def axes + @axes ||= Axes.new(:val_axis => ValAxis, :cat_axis => CatAxis) + end end end diff --git a/lib/axlsx/drawing/cat_axis.rb b/lib/axlsx/drawing/cat_axis.rb index ba392ce6..f32c23c9 100644 --- a/lib/axlsx/drawing/cat_axis.rb +++ b/lib/axlsx/drawing/cat_axis.rb @@ -4,23 +4,15 @@ module Axlsx class CatAxis < Axis # Creates a new CatAxis object - # @param [Integer] ax_id the id of this axis. Inherited - # @param [Integer] cross_ax the id of the perpendicular axis. Inherited - # @option options [Symbol] ax_pos. Inherited - # @option options [Symbol] tick_lbl_pos. Inherited - # @option options [Symbol] crosses. Inherited - # @option options [Boolean] auto - # @option options [Symbol] lbl_algn - # @option options [Integer] lbl_offset # @option options [Integer] tick_lbl_skip # @option options [Integer] tick_mark_skip - def initialize(ax_id, cross_ax, options={}) + def initialize(options={}) @tick_lbl_skip = 1 @tick_mark_skip = 1 self.auto = 1 self.lbl_algn = :ctr self.lbl_offset = "100" - super(ax_id, cross_ax, options) + super(options) end # From the docs: This element specifies that this axis is a date or text axis based on the data that is used for the axis labels, not a specific choice. diff --git a/lib/axlsx/drawing/d_lbls.rb b/lib/axlsx/drawing/d_lbls.rb index 3685e7d2..74c01350 100644 --- a/lib/axlsx/drawing/d_lbls.rb +++ b/lib/axlsx/drawing/d_lbls.rb @@ -10,7 +10,7 @@ module Axlsx include Axlsx::OptionsParser # creates a new DLbls object def initialize(chart_type, options={}) - raise ArgumentError, 'chart_type must inherit from Chart' unless chart_type.superclass == Chart + raise ArgumentError, 'chart_type must inherit from Chart' unless [Chart, LineChart].include?(chart_type.superclass) @chart_type = chart_type initialize_defaults parse_options options diff --git a/lib/axlsx/drawing/drawing.rb b/lib/axlsx/drawing/drawing.rb index 7567dea1..58f0f81e 100644 --- a/lib/axlsx/drawing/drawing.rb +++ b/lib/axlsx/drawing/drawing.rb @@ -22,6 +22,7 @@ module Axlsx require 'axlsx/drawing/ser_axis.rb' require 'axlsx/drawing/cat_axis.rb' require 'axlsx/drawing/val_axis.rb' + require 'axlsx/drawing/axes.rb' require 'axlsx/drawing/marker.rb' diff --git a/lib/axlsx/drawing/line_3D_chart.rb b/lib/axlsx/drawing/line_3D_chart.rb index 627cfe83..183f3250 100644 --- a/lib/axlsx/drawing/line_3D_chart.rb +++ b/lib/axlsx/drawing/line_3D_chart.rb @@ -11,7 +11,7 @@ module Axlsx # ws = p.workbook.add_worksheet # ws.add_row ["This is a chart with no data in the sheet"] # - # chart = ws.add_chart(Axlsx::Line3DChart, :start_at=> [0,1], :end_at=>[0,6], :title=>"Most Popular Pets") + # chart = ws.add_chart(Axlsx::Line3DChart, :start_at=> [0,1], :end_at=>[0,6], :t#itle=>"Most Popular Pets") # chart.add_series :data => [1, 9, 10], :labels => ["Slimy Reptiles", "Fuzzy Bunnies", "Rottweiler"] # # @see Worksheet#add_chart @@ -19,48 +19,50 @@ module Axlsx # @see Chart#add_series # @see Series # @see Package#serialize - class Line3DChart < LineChart + class Line3DChart < Axlsx::LineChart # space between bar or column clusters, as a percentage of the bar or column width. # @return [String] - attr_reader :gapDepth + attr_reader :gap_depth + alias :gapDepth :gap_depth # validation regex for gap amount percent GAP_AMOUNT_PERCENT = /0*(([0-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/ + # the category axis + # @return [Axis] + def ser_axis + axes[:ser_axis] + end + alias :serAxis :ser_axis + # Creates a new line chart object - # @param [GraphicFrame] frame The workbook that owns this chart. - # @option options [Cell, String] title - # @option options [Boolean] show_legend - # @option options [Symbol] grouping - # @option options [String] gapDepth - # @option options [Integer] rotX - # @option options [String] hPercent - # @option options [Integer] rotY - # @option options [String] depthPercent - # @option options [Boolean] rAngAx - # @option options [Integer] perspective + # @option options [String] gap_depth # @see Chart + # @see lineChart # @see View3D def initialize(frame, options={}) - @gapDepth = nil + @gap_depth = nil + @view_3D = View3D.new({:r_ang_ax=>1}.merge(options)) super(frame, options) - @view_3D = View3D.new({:perspective=>30}.merge(options)) + axes.add_axis :ser_axis, SerAxis end + # @see gapDepth - def gapDepth=(v) - RegexValidator.validate "Bar3DChart.gapWidth", GAP_AMOUNT_PERCENT, v - @gapDepth=(v) + def gap_depth=(v) + RegexValidator.validate "Line3DChart.gapWidth", GAP_AMOUNT_PERCENT, v + @gap_depth=(v) end + alias :gapDepth= :gap_depth= - # Serializes the object - # @param [String] str - # @return [String] - def to_xml_string(str = '') - super(str) do |str_inner| - str_inner << '<c:gapDepth val="' << @gapDepth.to_s << '"/>' unless @gapDepth.nil? + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + super(str) do |str_inner| + str_inner << '<c:gapDepth val="' << @gap_depth.to_s << '"/>' unless @gap_depth.nil? + end end - end end end diff --git a/lib/axlsx/drawing/line_chart.rb b/lib/axlsx/drawing/line_chart.rb index 7bf925e6..afe6154e 100644 --- a/lib/axlsx/drawing/line_chart.rb +++ b/lib/axlsx/drawing/line_chart.rb @@ -23,17 +23,19 @@ module Axlsx # the category axis # @return [CatAxis] - attr_reader :catAxis + def cat_axis + axes[:cat_axis] + end + alias :catAxis :cat_axis # the category axis # @return [ValAxis] - attr_reader :valAxis - - # the category axis - # @return [Axis] - attr_reader :serAxis + def val_axis + axes[:val_axis] + end + alias :valAxis :val_axis - # must be one of [:percentStacked, :clustered, :standard, :stacked] + # must be one of [:percentStacked, :clustered, :standard, :stacked] # @return [Symbol] attr_reader :grouping @@ -46,12 +48,6 @@ module Axlsx def initialize(frame, options={}) @vary_colors = false @grouping = :standard - @catAxId = rand(8 ** 8) - @valAxId = rand(8 ** 8) - @serAxId = rand(8 ** 8) - @catAxis = CatAxis.new(@catAxId, @valAxId) - @valAxis = ValAxis.new(@valAxId, @catAxId) - @serAxis = SerAxis.new(@serAxId, @valAxId) super(frame, options) @series_type = LineSeries @d_lbls = nil @@ -59,29 +55,38 @@ module Axlsx # @see grouping def grouping=(v) - RestrictionValidator.validate "Bar3DChart.grouping", [:percentStacked, :standard, :stacked], v + RestrictionValidator.validate "LineChart.grouping", [:percentStacked, :standard, :stacked], v @grouping = v end + def node_name + path = self.class.to_s + if i = path.rindex('::') + path = path[(i+2)..-1] + end + path[0] = path[0].chr.downcase + path + end + # Serializes the object # @param [String] str # @return [String] def to_xml_string(str = '') super(str) do |str_inner| - str_inner << "<c:#{self.class.name.demodulize.camelcase(:lower)}>" + str_inner << "<c:" << node_name << ">" str_inner << '<c:grouping val="' << grouping.to_s << '"/>' str_inner << '<c:varyColors val="' << vary_colors.to_s << '"/>' @series.each { |ser| ser.to_xml_string(str_inner) } - @d_lbls.to_xml_string(str) if @d_lbls + @d_lbls.to_xml_string(str_inner) if @d_lbls yield str_inner if block_given? - str_inner << '<c:axId val="' << @catAxId.to_s << '"/>' - str_inner << '<c:axId val="' << @valAxId.to_s << '"/>' - str_inner << '<c:axId val="' << @serAxId.to_s << '"/>' - str_inner << "</c:#{self.class.name.demodulize.camelcase(:lower)}>" - @catAxis.to_xml_string str_inner - @valAxis.to_xml_string str_inner - @serAxis.to_xml_string str_inner + axes.to_xml_string(str_inner, :ids => true) + str_inner << "</c:" << node_name << ">" + axes.to_xml_string(str_inner) end end + + def axes + @axes ||= Axes.new(:cat_axis => CatAxis, :val_axis => ValAxis) + end end end diff --git a/lib/axlsx/drawing/line_series.rb b/lib/axlsx/drawing/line_series.rb index f70bdb49..467dcc2d 100644 --- a/lib/axlsx/drawing/line_series.rb +++ b/lib/axlsx/drawing/line_series.rb @@ -28,6 +28,7 @@ module Axlsx # @option options [Array, SimpleTypedList] labels # @param [Chart] chart def initialize(chart, options={}) + @show_marker = false @labels, @data = nil, nil super(chart, options) @labels = AxDataSource.new(:data => options[:labels]) unless options[:labels].nil? diff --git a/lib/axlsx/drawing/scatter_chart.rb b/lib/axlsx/drawing/scatter_chart.rb index 2b801642..f069e346 100644 --- a/lib/axlsx/drawing/scatter_chart.rb +++ b/lib/axlsx/drawing/scatter_chart.rb @@ -12,35 +12,40 @@ module Axlsx # The Style for the scatter chart # must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker # return [Symbol] - attr_reader :scatterStyle + attr_reader :scatter_style + alias :scatterStyle :scatter_style # the x value axis # @return [ValAxis] - attr_reader :xValAxis + def x_val_axis + axes[:x_val_axis] + end + alias :xValAxis :x_val_axis # the y value axis # @return [ValAxis] - attr_reader :yValAxis + def y_val_axis + axes[:x_val_axis] + end + alias :yValAxis :y_val_axis # Creates a new scatter chart def initialize(frame, options={}) @vary_colors = 0 - @scatterStyle = :lineMarker - @xValAxId = rand(8 ** 8) - @yValAxId = rand(8 ** 8) - @xValAxis = ValAxis.new(@xValAxId, @yValAxId) - @yValAxis = ValAxis.new(@yValAxId, @xValAxId) - super(frame, options) + @scatter_style = :lineMarker + + super(frame, options) @series_type = ScatterSeries @d_lbls = nil parse_options options end # see #scatterStyle - def scatterStyle=(v) + def scatter_style=(v) Axlsx.validate_scatter_style(v) - @scatterStyle = v + @scatter_style = v end + alias :scatterStyle= :scatter_style= # Serializes the object # @param [String] str @@ -48,17 +53,19 @@ module Axlsx def to_xml_string(str = '') super(str) do |str_inner| str_inner << '<c:scatterChart>' - str_inner << '<c:scatterStyle val="' << scatterStyle.to_s << '"/>' + str_inner << '<c:scatterStyle val="' << scatter_style.to_s << '"/>' str_inner << '<c:varyColors val="' << vary_colors.to_s << '"/>' @series.each { |ser| ser.to_xml_string(str_inner) } - d_lbls.to_xml_string(str) if @d_lbls - str_inner << '<c:axId val="' << @xValAxId.to_s << '"/>' - str_inner << '<c:axId val="' << @yValAxId.to_s << '"/>' + d_lbls.to_xml_string(str_inner) if @d_lbls + axes.to_xml_string(str_inner, :ids => true) str_inner << '</c:scatterChart>' - @xValAxis.to_xml_string str_inner - @yValAxis.to_xml_string str_inner + axes.to_xml_string(str_inner) end str end + + def axes + @axes ||= Axes.new(:x_val_axis => ValAxis, :y_val_axis => ValAxis) + end end end diff --git a/lib/axlsx/drawing/ser_axis.rb b/lib/axlsx/drawing/ser_axis.rb index 00b04989..54e2c60e 100644 --- a/lib/axlsx/drawing/ser_axis.rb +++ b/lib/axlsx/drawing/ser_axis.rb @@ -5,30 +5,29 @@ module Axlsx # The number of tick lables to skip between labels # @return [Integer] - attr_reader :tickLblSkip + attr_reader :tick_lbl_skip + alias :tickLblSkip :tick_lbl_skip # The number of tickmarks to be skipped before the next one is rendered. # @return [Boolean] - attr_reader :tickMarkSkip + attr_reader :tick_mark_skip + alias :tickMarkSkip :tick_mark_skip # Creates a new SerAxis object - # @param [Integer] axId the id of this axis. Inherited - # @param [Integer] crossAx the id of the perpendicular axis. Inherited - # @option options [Symbol] axPos. Inherited - # @option options [Symbol] tickLblPos. Inherited - # @option options [Symbol] crosses. Inherited - # @option options [Integer] tickLblSkip - # @option options [Integer] tickMarkSkip - def initialize(axId, crossAx, options={}) - @tickLblSkip, @tickMarkSkip = 1, 1 - super(axId, crossAx, options) + # @option options [Integer] tick_lbl_skip + # @option options [Integer] tick_mark_skip + def initialize(options={}) + @tick_lbl_skip, @tick_mark_skip = 1, 1 + super(options) end # @see tickLblSkip - def tickLblSkip=(v) Axlsx::validate_unsigned_int(v); @tickLblSkip = v; end + def tick_lbl_skip=(v) Axlsx::validate_unsigned_int(v); @tick_lbl_skip = v; end + alias :tickLblSkip= :tick_lbl_skip= # @see tickMarkSkip - def tickMarkSkip=(v) Axlsx::validate_unsigned_int(v); @tickMarkSkip = v; end + def tick_mark_skip=(v) Axlsx::validate_unsigned_int(v); @tick_mark_skip = v; end + alias :tickMarkSkip= :tick_mark_skip= # Serializes the object # @param [String] str @@ -36,8 +35,8 @@ module Axlsx def to_xml_string(str = '') str << '<c:serAx>' super(str) - str << '<c:tickLblSkip val="' << @tickLblSkip.to_s << '"/>' unless @tickLblSkip.nil? - str << '<c:tickMarkSkip val="' << @tickMarkSkip.to_s << '"/>' unless @tickMarkSkip.nil? + str << '<c:tickLblSkip val="' << @tick_lbl_skip.to_s << '"/>' unless @tick_lbl_skip.nil? + str << '<c:tickMarkSkip val="' << @tick_mark_skip.to_s << '"/>' unless @tick_mark_skip.nil? str << '</c:serAx>' end end diff --git a/lib/axlsx/drawing/val_axis.rb b/lib/axlsx/drawing/val_axis.rb index 6e55c8ea..0e7a0800 100644 --- a/lib/axlsx/drawing/val_axis.rb +++ b/lib/axlsx/drawing/val_axis.rb @@ -6,21 +6,22 @@ module Axlsx # This element specifies how the value axis crosses the category axis. # must be one of [:between, :midCat] # @return [Symbol] - attr_reader :crossBetween + attr_reader :cross_between + alias :crossBetween :cross_between # Creates a new ValAxis object - # @param [Integer] axId the id of this axis - # @param [Integer] crossAx the id of the perpendicular axis - # @option options [Symbol] axPos - # @option options [Symbol] tickLblPos - # @option options [Symbol] crosses - # @option options [Symbol] crossesBetween - def initialize(axId, crossAx, options={}) - self.crossBetween = :between - super(axId, crossAx, options) + # @option options [Symbol] crosses_between + def initialize(options={}) + self.cross_between = :between + super(options) end - # @see crossBetween - def crossBetween=(v) RestrictionValidator.validate "ValAxis.crossBetween", [:between, :midCat], v; @crossBetween = v; end + + # @see cross_between + def cross_between=(v) + RestrictionValidator.validate "ValAxis.cross_between", [:between, :midCat], v + @cross_between = v + end + alias :crossBetween= :cross_between= # Serializes the object # @param [String] str @@ -28,7 +29,7 @@ module Axlsx def to_xml_string(str = '') str << '<c:valAx>' super(str) - str << '<c:crossBetween val="' << @crossBetween.to_s << '"/>' + str << '<c:crossBetween val="' << @cross_between.to_s << '"/>' str << '</c:valAx>' end |
