summaryrefslogtreecommitdiffhomepage
path: root/lib
diff options
context:
space:
mode:
authorRandy Morgan <[email protected]>2011-11-23 12:28:10 +0900
committerRandy Morgan <[email protected]>2011-11-23 12:28:10 +0900
commit6739c249e7bf3cf7d2132b2aa49b6faf6bebec29 (patch)
treec68e1527212c3665464debeebd2d97c127b0887e /lib
parent099a1d5a7824b7a6392bfe2f124ebeaf9d8122db (diff)
downloadcaxlsx-6739c249e7bf3cf7d2132b2aa49b6faf6bebec29.tar.gz
caxlsx-6739c249e7bf3cf7d2132b2aa49b6faf6bebec29.zip
-refactoring chart position and axis data/category for chart.
-additional specs and documentation improvements.
Diffstat (limited to 'lib')
-rw-r--r--lib/axlsx/drawing/axis.rb13
-rw-r--r--lib/axlsx/drawing/bar_3D_chart.rb42
-rw-r--r--lib/axlsx/drawing/bar_series.rb41
-rw-r--r--lib/axlsx/drawing/cat_axis.rb18
-rw-r--r--lib/axlsx/drawing/cat_axis_data.rb34
-rw-r--r--lib/axlsx/drawing/chart.rb69
-rw-r--r--lib/axlsx/drawing/drawing.rb26
-rw-r--r--lib/axlsx/drawing/graphic_frame.rb1
-rw-r--r--lib/axlsx/drawing/line_3D_chart.rb12
-rw-r--r--lib/axlsx/drawing/line_series.rb50
-rw-r--r--lib/axlsx/drawing/pie_3D_chart.rb51
-rw-r--r--lib/axlsx/drawing/pie_series.rb56
-rw-r--r--lib/axlsx/drawing/ser_axis.rb27
-rw-r--r--lib/axlsx/drawing/series.rb5
-rw-r--r--lib/axlsx/drawing/series_title.rb2
-rw-r--r--lib/axlsx/drawing/two_cell_anchor.rb44
-rw-r--r--lib/axlsx/drawing/val_axis.rb8
-rw-r--r--lib/axlsx/drawing/val_axis_data.rb28
-rw-r--r--lib/axlsx/drawing/view_3D.rb18
-rw-r--r--lib/axlsx/util/simple_typed_list.rb9
-rw-r--r--lib/axlsx/workbook/worksheet/worksheet.rb10
21 files changed, 265 insertions, 299 deletions
diff --git a/lib/axlsx/drawing/axis.rb b/lib/axlsx/drawing/axis.rb
index facc2a67..7e48801a 100644
--- a/lib/axlsx/drawing/axis.rb
+++ b/lib/axlsx/drawing/axis.rb
@@ -1,9 +1,8 @@
module Axlsx
- # the access class defines common properties and values for chart axis
+ # the access class defines common properties and values for a chart axis.
class Axis
-
- # the id of the axis
+ # the id of the axis.
# @return [Integer]
attr_reader :axId
@@ -12,6 +11,7 @@ module Axlsx
attr_reader :crossAx
# The scaling of the axis
+ # @see Scaling
# @return [Scaling]
attr_reader :scaling
@@ -25,8 +25,8 @@ module Axlsx
# @return [Symbol]
attr_accessor :tickLblPos
-
# The number format format code for this axis
+ # default :General
# @return [String]
attr_accessor :format_code
@@ -41,15 +41,16 @@ module Axlsx
# @option options [Symbol] axPos
# @option options [Symbol] crosses
# @option options [Symbol] tickLblPos
+ # @raise [ArgumentError] If axId or crossAx are not unsigned integers
def initialize(axId, crossAx, options={})
Axlsx::validate_unsigned_int(axId)
Axlsx::validate_unsigned_int(crossAx)
@axId = axId
@crossAx = crossAx
+ @scaling = Scaling.new(:orientation=>:minMax)
self.axPos = :l
self.tickLblPos = :nextTo
- @scaling = Scaling.new(:orientation=>:minMax)
- @formatCode = ""
+ self.format_code = "General"
self.crosses = :autoZero
options.each do |o|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
diff --git a/lib/axlsx/drawing/bar_3D_chart.rb b/lib/axlsx/drawing/bar_3D_chart.rb
index 1d7e2bba..3d7f6296 100644
--- a/lib/axlsx/drawing/bar_3D_chart.rb
+++ b/lib/axlsx/drawing/bar_3D_chart.rb
@@ -1,43 +1,17 @@
module Axlsx
# The Bar3DChart is a three dimentional barchart (who would have guessed?) that you can add to your worksheet.
- # @example Creating a chart
- # # This example creates two charts in a single sheet.
- # # The first uses data directly fed to the sheet, while the second references cells withing the worksheet for data.
- #
- # require "rubygems" # if that is your preferred way to manage gems!
- # require "axlsx"
- #
- # p = Axlsx::Package.new
- # ws = p.workbook.add_worksheet
- # ws.add_row :values => ["This is a chart with no data in the sheet"]
- #
- # chart = ws.add_chart(Axlsx::Bar3DChart, :start_at=> [0,1], :end_at=>[0,6], :title=>"Most Popular Pets")
- # chart.add_series :data => [1, 9, 10], :labels => ["Slimy Reptiles", "Fuzzy Bunnies", "Rottweiler"]
- #
- # ws.add_row :values => ["This chart uses the data below"]
- # title_row = ws.add_row :values => ["Least Popular Pets"]
- # label_row = ws.add_row :values => ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"]
- # data_row = ws.add_row :values => ["Votes", 6, 4, 1]
- #
- # chart = ws.add_chart(Axlsx::Pie3DChart, :start_at => [0,11], :end_at =>[0,16], :title => title_row.cells.last)
- # chart.add_series :data => data_row.cells[(1..-1)], :labels => label_row.cells
- #
- # f = File.open('example_pie_3d_chart.xlsx', 'w')
- # p.serialize(f)
- #
# @see Worksheet#add_chart
- # @see Worksheet#add_row
# @see Chart#add_series
- # @see Series
# @see Package#serialize
+ # @see README for an example
class Bar3DChart < Chart
# the category axis
# @return [CatAxis]
attr_reader :catAxis
- # the category axis
+ # the valueaxis
# @return [ValAxis]
attr_reader :valAxis
@@ -60,7 +34,7 @@ module Axlsx
attr_accessor :grouping
# The shabe of the bars or columns
- # must be one of [:percentStacked, :clustered, :standard, :stacked]
+ # must be one of [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax]
# @return [Symbol]
attr_accessor :shape
@@ -76,6 +50,14 @@ module Axlsx
# @option options [String] gapWidth
# @option options [String] gapDepth
# @option options [Symbol] shape
+ # @option options [Integer] rotX
+ # @option options [String] hPercent
+ # @option options [Integer] rotY
+ # @option options [String] depthPercent
+ # @option options [Boolean] rAngAx
+ # @option options [Integer] perspective
+ # @see Chart
+ # @see View3D
def initialize(frame, options={})
@barDir = :bar
@grouping = :clustered
@@ -83,9 +65,9 @@ module Axlsx
@valAxId = rand(8 ** 8)
@catAxis = CatAxis.new(@catAxId, @valAxId)
@valAxis = ValAxis.new(@valAxId, @catAxId)
- @view3D = View3D.new(:rAngAx=>1)
super(frame, options)
@series_type = BarSeries
+ @view3D = View3D.new({:rAngAx=>1}.merge(options))
end
def barDir=(v)
diff --git a/lib/axlsx/drawing/bar_series.rb b/lib/axlsx/drawing/bar_series.rb
index 0f46af15..5e10eb0e 100644
--- a/lib/axlsx/drawing/bar_series.rb
+++ b/lib/axlsx/drawing/bar_series.rb
@@ -28,8 +28,8 @@ module Axlsx
def initialize(chart, options={})
@shape = :box
super(chart, options)
- self.data = options[:data] || []
- self.labels = options[:labels] || []
+ self.labels = CatAxisData.new(options[:labels]) unless options[:labels].nil?
+ self.data = ValAxisData.new(options[:data]) unless options[:data].nil?
end
def shape=(v)
@@ -42,37 +42,8 @@ module Axlsx
# @return [String]
def to_xml(xml)
super(xml) do |xml|
- if !labels.empty?
- xml.send('c:cat') {
- xml.send('c:strRef') {
- xml.send('c:f', Axlsx::cell_range(labels))
- xml.send('c:strCache') {
- xml.send('c:ptCount', :val=>labels.size)
- labels.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
- end
- xml.send('c:val') {
- xml.send('c:numRef') {
- xml.send('c:f', Axlsx::cell_range(data))
- xml.send('c:numCache') {
- xml.send('c:formatCode', 'General')
- xml.send('c:ptCount', :val=>data.size)
- data.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
+ @labels.to_xml(xml) unless @labels.nil?
+ @data.to_xml(xml) unless @data.nil?
xml.send('c:shape', :val=>@shape)
end
end
@@ -82,10 +53,10 @@ module Axlsx
# assigns the data for this series
- def data=(v) DataTypeValidator.validate "Series.data", [Array, SimpleTypedList], v; @data = v; end
+ def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end
# assigns the labels for this series
- def labels=(v) DataTypeValidator.validate "Series.labels", [Array, SimpleTypedList], v; @labels = v; end
+ def labels=(v) DataTypeValidator.validate "Series.labels", [SimpleTypedList], v; @labels = v; end
end
diff --git a/lib/axlsx/drawing/cat_axis.rb b/lib/axlsx/drawing/cat_axis.rb
index f2458ffc..083eac68 100644
--- a/lib/axlsx/drawing/cat_axis.rb
+++ b/lib/axlsx/drawing/cat_axis.rb
@@ -1,6 +1,7 @@
module Axlsx
#A CatAxis object defines a chart category axis
class CatAxis < Axis
+
# 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.
# @return [Boolean]
attr_accessor :auto
@@ -18,23 +19,20 @@ module Axlsx
# regex for validating label offset
LBL_OFFSET_REGEX = /0*(([0-9])|([1-9][0-9])|([1-9][0-9][0-9])|1000)%/
- # Creates a new CatAxis 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
+ # Creates a new CatAxis 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 [Boolean] auto
# @option options [Symbol] lblAlgn
# @option options [Integer] lblOffset
def initialize(axId, crossAx, options={})
- super(axId, crossAx, options)
self.auto = true
self.lblAlgn = :ctr
self.lblOffset = "100%"
- options.each do |o|
- self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
- end
+ super(axId, crossAx, options)
end
def auto=(v) Axlsx::validate_boolean(v); @auto = v; end
diff --git a/lib/axlsx/drawing/cat_axis_data.rb b/lib/axlsx/drawing/cat_axis_data.rb
new file mode 100644
index 00000000..83dfa56e
--- /dev/null
+++ b/lib/axlsx/drawing/cat_axis_data.rb
@@ -0,0 +1,34 @@
+module Axlsx
+ # The CatAxisData class serializes the category axis data for a chart
+ class CatAxisData < SimpleTypedList
+
+ # Create a new CatAxisData object
+ # @param [Array, SimpleTypedList] data the data for this category axis. This can be a simple array or a simple typed list of cells.
+ def initialize(data=[])
+ super Object
+ @list.concat data if data.is_a?(Array)
+ end
+
+ # Serializes the category axis data
+ # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
+ # @return [String]
+ def to_xml(xml)
+ xml.send('c:cat') {
+ xml.send('c:strRef') {
+ xml.send('c:f', Axlsx::cell_range(@list))
+ xml.send('c:strCache') {
+ xml.send('c:ptCount', :val=>size)
+ each_with_index do |item, index|
+ v = item.is_a?(Cell) ? item.value : item
+ xml.send('c:pt', :idx=>index) {
+ xml.send('c:v', v)
+ }
+ end
+ }
+ }
+ }
+ end
+
+ end
+
+end
diff --git a/lib/axlsx/drawing/chart.rb b/lib/axlsx/drawing/chart.rb
index 315d9499..bf4a1bff 100644
--- a/lib/axlsx/drawing/chart.rb
+++ b/lib/axlsx/drawing/chart.rb
@@ -2,19 +2,12 @@
module Axlsx
# A Chart is the superclass for specific charts
# @note Worksheet#add_chart is the recommended way to create charts for your worksheets.
+ # @see README for examples
class Chart
- # The title object for the chart.
- # @return [Title]
- attr_accessor :title
-
- # The style for the chart.
- # see ECMA Part 1 §21.2.2.196
- # @return [Integer]
- attr_accessor :style
# The 3D view properties for the chart
- attr_accessor :view3D
+ attr_reader :view3D
# A reference to the graphic frame that owns this chart
# @return [GraphicFrame]
@@ -24,7 +17,7 @@ module Axlsx
# @return [SimpleTypedList]
attr_reader :series
- # The type of series to use for this chart
+ # The type of series to use for this chart.
# @return [Series]
attr_reader :series_type
@@ -39,13 +32,14 @@ module Axlsx
#TODO data labels!
#attr_accessor :dLabls
- # The starting marker for this chart
- # @return [Marker]
- attr_reader :start_at
+ # The title object for the chart.
+ # @return [Title]
+ attr_accessor :title
- # The ending marker for this chart
- # @return [Marker]
- attr_reader :end_at
+ # The style for the chart.
+ # see ECMA Part 1 §21.2.2.196
+ # @return [Integer]
+ attr_accessor :style
# Show the legend in the chart
# @return [Boolean]
@@ -65,6 +59,8 @@ module Axlsx
options.each do |o|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
end
+ start_at *options[:start_at] if options[:start_at]
+ end_at *options[:end_at] if options[:start_at]
yield self if block_given?
end
@@ -76,8 +72,6 @@ module Axlsx
"#{CHART_PN % (index+1)}"
end
- def view3D=(v) DataTypeValidator.validate "#{self.class}.view3D", View3D, v; @view3D = v; end
-
def title=(v)
v = Title.new(v) if v.is_a?(String) || v.is_a?(Cell)
DataTypeValidator.validate "#{self.class}.title", Title, v
@@ -88,6 +82,19 @@ module Axlsx
def style=(v) DataTypeValidator.validate "Chart.style", Integer, v, lambda { |v| v >= 1 && v <= 48 }; @style = v; end
+ # backwards compatibility to allow chart.to and chart.from access to anchor markers
+ # @note This will be disconinued in version 2.0.0. Please use the end_at method
+ def to
+ @graphic_frame.anchor.to
+ end
+
+ # backwards compatibility to allow chart.to and chart.from access to anchor markers
+ # @note This will be disconinued in version 2.0.0. please use the start_at method
+ #
+ def from
+ @graphic_frame.anchor.from
+ end
+
# Adds a new series to the chart's series collection.
# @return [Series]
# @see Series
@@ -122,10 +129,30 @@ module Axlsx
builder.to_xml
end
+ # This is a short cut method to set the start anchor position
+ # If you need finer granularity in positioning use
+ # graphic_frame.anchor.from.colOff / rowOff
+ # @param [Integer] x The column
+ # @param [Integer] y The row
+ # @return [Marker]
+ def start_at(x, y)
+ @graphic_frame.anchor.from.col = x
+ @graphic_frame.anchor.from.row = y
+ end
+
+ # This is a short cut method to set the end anchor position
+ # If you need finer granularity in positioning use
+ # graphic_frame.anchor.to.colOff / rowOff
+ # @param [Integer] x The column
+ # @param [Integer] y The row
+ # @return [Marker]
+ def end_at(x, y)
+ @graphic_frame.anchor.to.col = x
+ @graphic_frame.anchor.to.row = y
+ end
+
private
-
- def start_at=(v) DataTypeValidator.validate "#{self.class}.start_at", Marker, v; @start_at = v; end
- def end_at=(v) DataTypeValidator.validate "#{self.class}.end_at", Marker, v; @end_at = v; end
+ def view3D=(v) DataTypeValidator.validate "#{self.class}.view3D", View3D, v; @view3D = v; end
end
end
diff --git a/lib/axlsx/drawing/drawing.rb b/lib/axlsx/drawing/drawing.rb
index 83902143..385cd592 100644
--- a/lib/axlsx/drawing/drawing.rb
+++ b/lib/axlsx/drawing/drawing.rb
@@ -6,35 +6,39 @@ module Axlsx
require 'axlsx/drawing/bar_series.rb'
require 'axlsx/drawing/line_series.rb'
+ require 'axlsx/drawing/scaling.rb'
require 'axlsx/drawing/axis.rb'
require 'axlsx/drawing/ser_axis.rb'
require 'axlsx/drawing/cat_axis.rb'
require 'axlsx/drawing/val_axis.rb'
- require 'axlsx/drawing/view_3D.rb'
- require 'axlsx/drawing/scaling.rb'
- require 'axlsx/drawing/graphic_frame.rb'
+ require 'axlsx/drawing/cat_axis_data.rb'
+ require 'axlsx/drawing/val_axis_data.rb'
+
require 'axlsx/drawing/marker.rb'
require 'axlsx/drawing/two_cell_anchor.rb'
+ require 'axlsx/drawing/graphic_frame.rb'
+ require 'axlsx/drawing/view_3D.rb'
require 'axlsx/drawing/chart.rb'
require 'axlsx/drawing/pie_3D_chart.rb'
require 'axlsx/drawing/bar_3D_chart.rb'
require 'axlsx/drawing/line_3D_chart.rb'
- # A Drawing is a canvas for charts. Each worksheet has a single drawing that can specify multiple anchors which reference charts.
- # @note The recommended way to manage drawings is to use the Worksheet.add_chart method, specifying the chart class, start and end marker locations.
+ # A Drawing is a canvas for charts. Each worksheet has a single drawing that manages anchors.
+ # The anchors reference the charts via graphical frames. This is not a trivial relationship so please do follow the advice in the note.
+ # @note The recommended way to manage drawings is to use the Worksheet.add_chart method.
# @see Worksheet#add_chart
- # @see TwoCellAnchor
# @see Chart
+ # see README for an example of how to create a chart.
class Drawing
# The worksheet that owns the drawing
# @return [Worksheet]
attr_reader :worksheet
-
# A collection of anchors for this drawing
+ # only TwoCellAnchors are supported in this version
# @return [SimpleTypedList]
attr_reader :anchors
@@ -72,12 +76,10 @@ module Axlsx
end
- # Adds a chart to the drawing.
- # @note The recommended way to manage charts is to use Worksheet.add_chart.
- # @param [Chart] chart_type The class of the chart to be added to the drawing
- # @param [Hash] options
+ # Adds a chart to the drawing.
+ # @note The recommended way to manage charts is to use Worksheet.add_chart. Please refer to that method for documentation.
+ # @see Worksheet#add_chart
def add_chart(chart_type, options={})
- DataTypeValidator.validate "Drawing.chart_type", Chart, chart_type
TwoCellAnchor.new(self, chart_type, options)
@anchors.last.graphic_frame.chart
end
diff --git a/lib/axlsx/drawing/graphic_frame.rb b/lib/axlsx/drawing/graphic_frame.rb
index 3fe71976..5e09fb8a 100644
--- a/lib/axlsx/drawing/graphic_frame.rb
+++ b/lib/axlsx/drawing/graphic_frame.rb
@@ -22,6 +22,7 @@ module Axlsx
# @param [TwoCellAnchor] anchor
# @param [Class] chart_type
def initialize(anchor, chart_type, options)
+ DataTypeValidator.validate "Drawing.chart_type", Chart, chart_type
@anchor = anchor
@chart = chart_type.new(self, options)
end
diff --git a/lib/axlsx/drawing/line_3D_chart.rb b/lib/axlsx/drawing/line_3D_chart.rb
index 39500f75..6fb34afb 100644
--- a/lib/axlsx/drawing/line_3D_chart.rb
+++ b/lib/axlsx/drawing/line_3D_chart.rb
@@ -46,8 +46,18 @@ module Axlsx
# 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
+ # @see Chart
+ # @see View3D
def initialize(frame, options={})
@grouping = :standard
@catAxId = rand(8 ** 8)
@@ -56,9 +66,9 @@ module Axlsx
@catAxis = CatAxis.new(@catAxId, @valAxId)
@valAxis = ValAxis.new(@valAxId, @catAxId)
@serAxis = SerAxis.new(@serAxId, @valAxId)
- @view3D = View3D.new(:perspective=>30)
super(frame, options)
@series_type = LineSeries
+ @view3D = View3D.new({:perspective=>30}.merge(options))
end
def grouping=(v)
diff --git a/lib/axlsx/drawing/line_series.rb b/lib/axlsx/drawing/line_series.rb
index db509d38..eea1e0ee 100644
--- a/lib/axlsx/drawing/line_series.rb
+++ b/lib/axlsx/drawing/line_series.rb
@@ -6,11 +6,11 @@ module Axlsx
class LineSeries < Series
# The data for this series.
- # @return [Array, SimpleTypedList]
+ # @return [ValAxisData]
attr_reader :data
# The labels for this series.
- # @return [Array, SimpleTypedList]
+ # @return [CatAxisData]
attr_reader :labels
# Creates a new series
@@ -19,58 +19,28 @@ module Axlsx
# @param [Chart] chart
def initialize(chart, options={})
super(chart, options)
- self.data = options[:data] || []
- self.labels = options[:labels] || []
+ self.labels = CatAxisData.new(options[:labels]) unless options[:labels].nil?
+ self.data = ValAxisData.new(options[:data]) unless options[:data].nil?
end
# Serializes the series
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
# @return [String]
+ # TODO create series_cat and series_val classes as this serialization is duplicated
def to_xml(xml)
super(xml) do |xml|
- if !labels.empty?
- xml.send('c:cat') {
- xml.send('c:strRef') {
- xml.send('c:f', Axlsx::cell_range(labels))
- xml.send('c:strCache') {
- xml.send('c:ptCount', :val=>labels.size)
- labels.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
- end
- xml.send('c:val') {
- xml.send('c:numRef') {
- xml.send('c:f', Axlsx::cell_range(data))
- xml.send('c:numCache') {
- xml.send('c:formatCode', 'General')
- xml.send('c:ptCount', :val=>data.size)
- data.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
+ @labels.to_xml(xml) unless @labels.nil?
+ @data.to_xml(xml) unless @data.nil?
end
end
-
- private
+ private
# assigns the data for this series
- def data=(v) DataTypeValidator.validate "Series.data", [Array, SimpleTypedList], v; @data = v; end
+ def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end
# assigns the labels for this series
- def labels=(v) DataTypeValidator.validate "Series.labels", [Array, SimpleTypedList], v; @labels = v; end
+ def labels=(v) DataTypeValidator.validate "Series.labels", [SimpleTypedList], v; @labels = v; end
end
-
end
diff --git a/lib/axlsx/drawing/pie_3D_chart.rb b/lib/axlsx/drawing/pie_3D_chart.rb
index cf835bfd..dacba313 100644
--- a/lib/axlsx/drawing/pie_3D_chart.rb
+++ b/lib/axlsx/drawing/pie_3D_chart.rb
@@ -2,47 +2,30 @@ module Axlsx
# The Pie3DChart is a three dimentional piechart (who would have guessed?) that you can add to your worksheet.
- # @example Creating a chart
- # # This example creates two charts in a single sheet.
- # # The first uses data directly fed to the sheet, while the second references cells withing the worksheet for data.
- #
- # require "rubygems" # if that is your preferred way to manage gems!
- # require "axlsx"
- #
- # p = Axlsx::Package.new
- # ws = p.workbook.add_worksheet
- # ws.add_row :values => ["This is a chart with no data in the sheet"]
- #
- # chart = ws.add_chart(Axlsx::Pie3DChart, :start_at=> [0,1], :end_at=>[0,6], :title=>"Most Popular Pets")
- # chart.add_series :data => [1, 9, 10], :labels => ["Slimy Reptiles", "Fuzzy Bunnies", "Rottweiler"]
- #
- # ws.add_row :values => ["This chart uses the data below"]
- # title_row = ws.add_row :values => ["Least Popular Pets"]
- # label_row = ws.add_row :values => ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"]
- # data_row = ws.add_row :values => ["Votes", 6, 4, 1]
- #
- # chart = ws.add_chart(Axlsx::Pie3DChart, :start_at => [0,11], :end_at =>[0,16], :title => title_row.cells.last)
- # chart.add_series :data => data_row.cells[(1..-1)], :labels => label_row.cells
- #
- # f = File.open('example_pie_3d_chart.xlsx', 'w')
- # p.serialize(f)
- #
# @see Worksheet#add_chart
- # @see Worksheet#add_row
# @see Chart#add_series
- # @see Series
- # @see Package#serialize
+ # @see README for an example
class Pie3DChart < Chart
-
# Creates a new pie chart object
- # @param [Workbook] workbook The workbook that owns this chart.
+ # @param [GraphicFrame] frame The workbook that owns this chart.
# @option options [Cell, String] title
- def initialize(workbook, options={})
- # this charts series type
- super(workbook, options)
+ # @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
+ # @see Chart
+ # @see View3D
+ def initialize(frame, options={})
+ super(frame, options)
@series_type = PieSeries
- @view3D = View3D.new(:rotX => 30, :perspective => 30)
+ @view3D = View3D.new({:rotX=>30, :perspective=>30}.merge(options))
+
end
# Serializes the pie chart
diff --git a/lib/axlsx/drawing/pie_series.rb b/lib/axlsx/drawing/pie_series.rb
index 98b61728..1f20058d 100644
--- a/lib/axlsx/drawing/pie_series.rb
+++ b/lib/axlsx/drawing/pie_series.rb
@@ -1,22 +1,20 @@
module Axlsx
- # A PieSeries defines the title, data and labels for pie charts
+ # A PieSeries defines the data and labels and explosion for pie charts series.
# @note The recommended way to manage series is to use Chart#add_series
# @see Worksheet#add_chart
# @see Chart#add_series
class PieSeries < Series
# The data for this series.
- # @return [Array, SimpleTypedList]
+ # @return [SimpleTypedList]
attr_reader :data
-
# The labels for this series.
- # @return [Array, SimpleTypedList]
+ # @return [SimpleTypedList]
attr_reader :labels
-
# The explosion for this series
- # @return [Array, SimpleTypedList]
+ # @return [Integert]
attr_accessor :explosion
# Creates a new series
@@ -27,61 +25,29 @@ module Axlsx
# @param [Chart] chart
def initialize(chart, options={})
super(chart, options)
- self.data = options[:data] || []
- self.labels = options[:labels] || []
+ self.labels = CatAxisData.new(options[:labels]) unless options[:labels].nil?
+ self.data = ValAxisData.new(options[:data]) unless options[:data].nil?
end
def explosion=(v) Axlsx::validate_unsigned_int(v); @explosion = v; end
+
# Serializes the series
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
# @return [String]
def to_xml(xml)
super(xml) do |xml|
xml.send('c:explosion', :val=>@explosion) unless @explosion.nil?
- if !labels.empty?
- xml.send('c:cat') {
- xml.send('c:strRef') {
- xml.send('c:f', Axlsx::cell_range(labels))
- xml.send('c:strCache') {
- xml.send('c:ptCount', :val=>labels.size)
- labels.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
- end
- xml.send('c:val') {
- xml.send('c:numRef') {
- xml.send('c:f', Axlsx::cell_range(data))
- xml.send('c:numCache') {
- xml.send('c:formatCode', 'General')
- xml.send('c:ptCount', :val=>data.size)
- data.each_with_index do |cell, index|
- v = cell.is_a?(Cell) ? cell.value : cell
- xml.send('c:pt', :idx=>index) {
- xml.send('c:v', v)
- }
- end
- }
- }
- }
-
+ @labels.to_xml(xml) unless @labels.nil?
+ @data.to_xml(xml) unless @data.nil?
end
end
-
-
private
-
# assigns the data for this series
- def data=(v) DataTypeValidator.validate "Series.data", [Array, SimpleTypedList], v; @data = v; end
+ def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end
# assigns the labels for this series
- def labels=(v) DataTypeValidator.validate "Series.labels", [Array, SimpleTypedList], v; @labels = v; end
+ def labels=(v) DataTypeValidator.validate "Series.labels", [SimpleTypedList], v; @labels = v; end
end
diff --git a/lib/axlsx/drawing/ser_axis.rb b/lib/axlsx/drawing/ser_axis.rb
index 091a7d64..a086b23c 100644
--- a/lib/axlsx/drawing/ser_axis.rb
+++ b/lib/axlsx/drawing/ser_axis.rb
@@ -1,30 +1,29 @@
module Axlsx
- #A SarAxis object defines a series axis
+ #A SerAxis object defines a series axis
class SerAxis < Axis
- # @return [Boolean]
+ # The number of tick lables to skip between labels
+ # @return [Integer]
attr_accessor :tickLblSkip
+ # The number of tickmarks to be skipped before the next one is rendered.
# @return [Boolean]
attr_accessor :tickMarkSkip
# Creates a new SerAxis 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 [Boolean] tickLblSkip
- # @option options [Symbol] tickMarkSkip
+ # @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={})
super(axId, crossAx, options)
- options.each do |o|
- self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
- end
end
- def tickLblSkip=(v) Axlsx::validate_boolean(v); @tickLblSkip = v; end
- def tickMarkSkip=(v) Axlsx::validate_boolean(v); @tickMarkSkip = v; end
+ def tickLblSkip=(v) Axlsx::validate_unsigned_int(v); @tickLblSkip = v; end
+ def tickMarkSkip=(v) Axlsx::validate_unsigned_int(v); @tickMarkSkip = v; end
# Serializes the series axis
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
diff --git a/lib/axlsx/drawing/series.rb b/lib/axlsx/drawing/series.rb
index 51957acc..cb5d6a8d 100644
--- a/lib/axlsx/drawing/series.rb
+++ b/lib/axlsx/drawing/series.rb
@@ -1,5 +1,5 @@
module Axlsx
- # A Series defines the title, data and labels for chart data.
+ # A Series defines the common series attributes and is the super class for all concrete series types.
# @note The recommended way to manage series is to use Chart#add_series
# @see Worksheet#add_chart
# @see Chart#add_series
@@ -13,7 +13,7 @@ module Axlsx
# @return [Integer]
attr_reader :index
- # The order of this series in the chart's series.
+ # The order of this series in the chart's series. By default the order is the index of the series.
# @return [Integer]
attr_accessor :order
@@ -33,7 +33,6 @@ module Axlsx
end
end
- # retrieves the series index in the chart's series collection
def index
@chart.series.index(self)
end
diff --git a/lib/axlsx/drawing/series_title.rb b/lib/axlsx/drawing/series_title.rb
index 32b5b102..bfb1b56f 100644
--- a/lib/axlsx/drawing/series_title.rb
+++ b/lib/axlsx/drawing/series_title.rb
@@ -1,5 +1,5 @@
module Axlsx
- # A series title is a Title with a slightly different serialization
+ # A series title is a Title with a slightly different serialization than chart titles.
class SeriesTitle < Title
# Serializes the series title
diff --git a/lib/axlsx/drawing/two_cell_anchor.rb b/lib/axlsx/drawing/two_cell_anchor.rb
index aa9c04aa..62491b8c 100644
--- a/lib/axlsx/drawing/two_cell_anchor.rb
+++ b/lib/axlsx/drawing/two_cell_anchor.rb
@@ -23,51 +23,24 @@ module Axlsx
# @return [Integer]
attr_reader :index
- # Creates a new TwoCellAnchor object
+ # Creates a new TwoCellAnchor object and sets up a reference to the from and to markers in the
+ # graphic_frame's chart. That means that you can do stuff like
+ # c = worksheet.add_chart Axlsx::Chart
+ # c.start_at 5, 9
# @param [Drawing] drawing
- # @param [Chart] chart
- # @option options [Array] start_at
- # @option options [Array] end_at
+ # @param [Class] chart_type This is passed to the graphic frame for instantiation. must be Chart or a subclass of Chart
+ # @option options [Array] start_at the col, row to start at
+ # @option options [Array] end_at the col, row to end at
def initialize(drawing, chart_type, options)
@drawing = drawing
drawing.anchors << self
-
@from, @to = Marker.new, Marker.new(:col => 5, :row=>10)
@graphic_frame = GraphicFrame.new(self, chart_type, options)
-
- self.start_at(options[:start_at][0], options[:start_at][1]) if options[:start_at].is_a?(Array)
- self.end_at(options[:end_at][0], options[:end_at][1]) if options[:end_at].is_a?(Array)
- # passing a reference to our start and end markers for convenience
- # this lets us access the markers directly from the chart.
- @graphic_frame.chart.send(:start_at=, @from)
- @graphic_frame.chart.send(:end_at=, @to)
end
def index
@drawing.anchors.index(self)
end
-
-
- # This is a short cut method to set the start anchor position
- # @param [Integer] x The column
- # @param [Integer] y The row
- # @return [Marker]
- def start_at(x, y)
- @from.col = x
- @from.row = y
- @from
- end
-
- # This is a short cut method to set the end anchor position
- # @param [Integer] x The column
- # @param [Integer] y The row
- # @return [Marker]
- def end_at(x, y)
- @to.col = x
- @to.row = y
- @to
- end
-
# Serializes the two cell anchor
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
# @return [String]
@@ -84,5 +57,8 @@ module Axlsx
xml.send('xdr:clientData')
}
end
+
+ private
+
end
end
diff --git a/lib/axlsx/drawing/val_axis.rb b/lib/axlsx/drawing/val_axis.rb
index fae6adec..10a070f6 100644
--- a/lib/axlsx/drawing/val_axis.rb
+++ b/lib/axlsx/drawing/val_axis.rb
@@ -2,7 +2,7 @@ module Axlsx
# the ValAxis class defines a chart value axis.
class ValAxis < Axis
- # This element specifies whether the value axis crosses the category axis between categories.
+ # This element specifies how the value axis crosses the category axis.
# must be one of [:between, :midCat]
# @return [Symbol]
attr_accessor :crossBetween
@@ -11,17 +11,17 @@ module Axlsx
# @param [Integer] axId the id of this axis
# @param [Integer] crossAx the id of the perpendicular axis
# @option options [Symbol] axPos
- # @option options [Symbol] crosses
# @option options [Symbol] tickLblPos
+ # @option options [Symbol] crosses
# @option options [Symbol] crossesBetween
def initialize(axId, crossAx, options={})
- @crossBetween = :between
+ self.crossBetween = :between
super(axId, crossAx, options)
end
def crossBetween=(v) RestrictionValidator.validate "ValAxis.crossBetween", [:between, :midCat], v; @crossBetween = v; end
- # Serializes the value axis
+ # Serializes the value axis
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
# @return [String]
def to_xml(xml)
diff --git a/lib/axlsx/drawing/val_axis_data.rb b/lib/axlsx/drawing/val_axis_data.rb
new file mode 100644
index 00000000..6a24a1ef
--- /dev/null
+++ b/lib/axlsx/drawing/val_axis_data.rb
@@ -0,0 +1,28 @@
+module Axlsx
+ # The ValAxisData class manages the values for a chart value series.
+ class ValAxisData < CatAxisData
+
+ # Serializes the value axis data
+ # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
+ # @return [String]
+ def to_xml(xml)
+ xml.send('c:val') {
+ xml.send('c:numRef') {
+ xml.send('c:f', Axlsx::cell_range(@list))
+ xml.send('c:numCache') {
+ xml.send('c:formatCode', 'General')
+ xml.send('c:ptCount', :val=>size)
+ each_with_index do |item, index|
+ v = item.is_a?(Cell) ? item.value : item
+ xml.send('c:pt', :idx=>index) {
+ xml.send('c:v', v)
+ }
+ end
+ }
+ }
+ }
+ end
+
+ end
+
+end
diff --git a/lib/axlsx/drawing/view_3D.rb b/lib/axlsx/drawing/view_3D.rb
index 36a869cf..1065d778 100644
--- a/lib/axlsx/drawing/view_3D.rb
+++ b/lib/axlsx/drawing/view_3D.rb
@@ -1,6 +1,13 @@
module Axlsx
# 3D attributes for a chart.
class View3D
+
+ # Validation for hPercent
+ H_PERCENT_REGEX = /0*(([5-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/
+
+ # validation for depthPercent
+ DEPTH_PERCENT_REGEX = /0*(([2-9][0-9])|([1-9][0-9][0-9])|(1[0-9][0-9][0-9])|2000)%/
+
# x rotation for the chart
# must be between -90 and 90
# @return [Integer]
@@ -41,18 +48,17 @@ module Axlsx
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
end
end
-
- # Validation for hPercent
- H_PERCENT_REGEX = /0*(([5-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/
-
- # validation for depthPercent
- DEPTH_PERCENT_REGEX = /0*(([2-9][0-9])|([1-9][0-9][0-9])|(1[0-9][0-9][0-9])|2000)%/
def rotX=(v) DataTypeValidator.validate "#{self.class}.rotX", [Integer, Fixnum], v, lambda {|v| v >= -90 && v <= 90 }; @rotX = v; end
+
def hPercent=(v) RegexValidator.validate "#{self.class}.rotX", H_PERCENT_REGEX, v; @hPercent = v; end
+
def rotY=(v) DataTypeValidator.validate "#{self.class}.rotY", [Integer, Fixnum], v, lambda {|v| v >= 0 && v <= 360 }; @rotY = v; end
+
def depthPercent=(v) RegexValidator.validate "#{self.class}.depthPercent", DEPTH_PERCENT_REGEX, v; @depthPercent = v; end
+
def rAngAx=(v) Axlsx::validate_boolean(v); @rAngAx = v; end
+
def perspective=(v) DataTypeValidator.validate "#{self.class}.perspective", [Integer, Fixnum], v, lambda {|v| v >= 0 && v <= 240 }; @perspective = v; end
# Serializes the view3D properties
diff --git a/lib/axlsx/util/simple_typed_list.rb b/lib/axlsx/util/simple_typed_list.rb
index 7bb656cd..53b7b994 100644
--- a/lib/axlsx/util/simple_typed_list.rb
+++ b/lib/axlsx/util/simple_typed_list.rb
@@ -100,6 +100,11 @@ module Axlsx
index < @locked_at
end
+ # override the equality method so that this object can be compared to a simple array.
+ # if this object's list is equal to the specifiec array, we return true.
+ def ==(v)
+ v == @list
+ end
# method_mission override to pass allowed methods to the list.
# @note
# the following methods are not allowed
@@ -123,12 +128,12 @@ module Axlsx
# :drop_while
# :delete_if
# :clear
- # :concat
def method_missing(meth, *args, &block)
- raise ArgumentError, "#{meth} not supported" if [:replace, :insert, :collect!, :map!, :pop, :delete_if, :reverse!, :shift, :shuffle!, :slice!, :sort!, :uniq!, :unshift, :zip, :flatten!, :fill, :drop, :drop_while, :delete_if, :clear, :concat].include? meth.to_sym
+ raise ArgumentError, "#{meth} not supported" if [:replace, :insert, :collect!, :map!, :pop, :delete_if, :reverse!, :shift, :shuffle!, :slice!, :sort!, :uniq!, :unshift, :zip, :flatten!, :fill, :drop, :drop_while, :delete_if, :clear].include? meth.to_sym
if @list.respond_to? meth
@list.send(meth, *args, &block)
else
+ puts "method:#{meth.inspect}"
super
end
end
diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb
index 4cc9d783..c82dbde9 100644
--- a/lib/axlsx/workbook/worksheet/worksheet.rb
+++ b/lib/axlsx/workbook/worksheet/worksheet.rb
@@ -100,11 +100,19 @@ module Axlsx
@rows.last
end
- # Adds a chart to this worksheets drawing.
+ # Adds a chart to this worksheets drawing. This is the recommended way to create charts for your worksheet. This method wraps the complexity of dealing with ooxml drawing, anchors, markers graphic frames chart objects and all the other dirty details.
# @param [Class] chart_type
# @option options [Array] start_at
# @option options [Array] end_at
# @option options [Cell, String] title
+ # @option options [Boolean] show_legend
+ # @option options [Integer] style
+ # @note each chart type also specifies additional options
+ # @see Chart
+ # @see Pie3DChart
+ # @see Bar3DChart
+ # @see Line3DChart
+ # @see README for examples
def add_chart(chart_type, options={})
chart = drawing.add_chart(chart_type, options)
yield chart if block_given?