# frozen_string_literal: true 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 include Axlsx::OptionsParser # Creates a new chart object # @param [GraphicalFrame] frame The frame that holds this chart. # @option options [Cell, String] title # @option options [Boolean] show_legend # @option options [Symbol] legend_position # @option options [Array|String|Cell] start_at The X, Y coordinates defining the top left corner of the chart. # @option options [Array|String|Cell] end_at The X, Y coordinates defining the bottom right corner of the chart. # @option options [Boolean] plot_visible_only (true) Whether only data from visible cells should be plotted. # @option options [Boolean] rounded_corners (true) Whether the chart area shall have rounded corners. def initialize(frame, options = {}) @style = 18 @view_3D = nil @graphic_frame = frame @graphic_frame.anchor.drawing.worksheet.workbook.charts << self @series = SimpleTypedList.new Series @show_legend = true @legend_position = :r @display_blanks_as = :gap @series_type = Series @title = Title.new @bg_color = nil @plot_visible_only = true @rounded_corners = true parse_options options start_at(*options[:start_at]) if options[:start_at] end_at(*options[:end_at]) if options[:end_at] yield self if block_given? end # The 3D view properties for the chart attr_reader :view_3D alias :view3D :view_3D # A reference to the graphic frame that owns this chart # @return [GraphicFrame] attr_reader :graphic_frame # A collection of series objects that are applied to the chart # @return [SimpleTypedList] attr_reader :series # The type of series to use for this chart. # @return [Series] attr_reader :series_type # TODO: data labels! def d_lbls @d_lbls ||= DLbls.new(self.class) end # Indicates that colors should be varied by datum # @return [Boolean] attr_reader :vary_colors # Configures the vary_colors options for this chart # @param [Boolean] v The value to set def vary_colors=(v) Axlsx.validate_boolean(v) @vary_colors = v end # The title object for the chart. # @return [Title] attr_reader :title # The style for the chart. # see ECMA Part 1 §21.2.2.196 # @return [Integer] attr_reader :style # Show the legend in the chart # @return [Boolean] attr_reader :show_legend # Set the location of the chart's legend # @return [Symbol] The position of this legend # @note # The following are allowed # :b # :l # :r # :t # :tr attr_reader :legend_position # How to display blank values # Options are # * gap: Display nothing # * span: Not sure what this does # * zero: Display as if the value were zero, not blank # @return [Symbol] # Default :gap (although this really should vary by chart type and grouping) attr_reader :display_blanks_as # Background color for the chart # @return [String] attr_reader :bg_color # Whether only data from visible cells should be plotted. # @return [Boolean] attr_reader :plot_visible_only # Whether the chart area shall have rounded corners. # @return [Boolean] attr_reader :rounded_corners # The relationship object for this chart. # @return [Relationship] def relationship Relationship.new(self, CHART_R, "../#{pn}") end # The index of this chart in the workbooks charts collection # @return [Integer] def index @graphic_frame.anchor.drawing.worksheet.workbook.charts.index(self) end # The part name for this chart # @return [String] def pn format(CHART_PN, index + 1) end # The title object for the chart. # @param [String, Cell] v # @return [Title] def title=(v) DataTypeValidator.validate "#{self.class}.title", [String, Cell], v if v.is_a?(String) @title.text = v elsif v.is_a?(Cell) @title.cell = v end end # The size of the Title object of the chart. # @param [String] v The size for the title object # @see Title def title_size=(v) @title.text_size = v unless v.to_s.empty? end # Show the legend in the chart # @param [Boolean] v # @return [Boolean] def show_legend=(v) Axlsx.validate_boolean(v) @show_legend = v end # How to display blank values # @see display_blanks_as # @param [Symbol] v # @return [Symbol] def display_blanks_as=(v) Axlsx.validate_display_blanks_as(v) @display_blanks_as = v end # The style for the chart. # see ECMA Part 1 §21.2.2.196 # @param [Integer] v must be between 1 and 48 def style=(v) DataTypeValidator.validate "Chart.style", Integer, v, ->(arg) { arg >= 1 && arg <= 48 } @style = v end # @see legend_position def legend_position=(v) RestrictionValidator.validate "Chart.legend_position", [:b, :l, :r, :t, :tr], v @legend_position = 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 def add_series(options = {}) @series_type.new(self, options) @series.last end # Assigns a background color to chart area def bg_color=(v) DataTypeValidator.validate(:color, Color, Color.new(rgb: v)) @bg_color = v end # Whether only data from visible cells should be plotted. # @param [Boolean] v # @return [Boolean] def plot_visible_only=(v) Axlsx.validate_boolean(v) @plot_visible_only = v end # Whether the chart area shall have rounded corners. # @param [Boolean] v # @return [Boolean] def rounded_corners=(v) Axlsx.validate_boolean(v) @rounded_corners = v end # Serializes the object # @param [String] str # @return [String] def to_xml_string(str = +'') str << '' str << '' str << '' str << '' str << '' str << '' @title.to_xml_string(str) unless @title.empty? str << '' @view_3D.to_xml_string(str) if @view_3D str << '' str << '' str << '' str << '' str << '' yield if block_given? str << '' if @show_legend str << '' str << '' str << '' str << '' str << '' end str << '' str << '' str << '' str << '' if bg_color str << '' str << '' str << '' str << '' str << '' str << '' str << '' str << '' end str << '' str << '' str << '' str << '' str << '' str << '' end # This is a short cut method to set the anchor start marker position # If you need finer granularity in positioning use # # This helper method acceps a fairly wide range of inputs exampled # below # # @example # # start_at 0, 5 # The anchor start marker is set to 6th row of # the first column # # start_at [0, 5] # The anchor start marker is set to start on the 6th row # of the first column # # start_at "C1" # The anchor start marker is set to start on the first row # of the third column # # start_at sheet.rows.first.cells.last # The anchor start # marker is set to the location of a specific cell. # # @param [Array|String|Cell] x the column, coordinates, string # reference or cell to use in setting the start marker position. # @param [Integer] y The row # @return [Marker] def start_at(x = 0, y = 0) @graphic_frame.anchor.start_at(x, 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 - default 10 # @param [Integer] y The row - default 10 # @return [Marker] # @see start_at def end_at(x = 10, y = 10) @graphic_frame.anchor.end_at(x, y) end # sets the view_3D object for the chart def view_3D=(v) DataTypeValidator.validate "#{self.class}.view_3D", View3D, v @view_3D = v end alias :view3D= :view_3D= end end