ManageIQ/manageiq

View on GitHub
lib/manageiq/reporting/formatter/c3.rb

Summary

Maintainability
A
1 hr
Test Coverage
A
92%
require_dependency 'manageiq/reporting/formatter/c3_series'

module ManageIQ
  module Reporting
    module Formatter
      class C3 < Ruport::Formatter
        include ActionView::Helpers::UrlHelper
        include ChartCommon
        include MiqReport::Formatting
        renders :c3, :for => ReportRenderer

        # series handling methods
        def series_class
          ManageIQ::Reporting::Formatter::C3Series
        end

        CONVERT_TYPES = {
          "ColumnThreed"         => "Column",
          "ParallelThreedColumn" => "Column",
          "StackedThreedColumn"  => "StackedColumn",
          "PieThreed"            => "Pie",
          "AreaThreed"           => "Area",
          "StackedAreaThreed"    => "StackedArea"
        }
        def add_series(label, data)
          @counter ||= 0
          @counter += 1
          series_id = @counter.to_s
          limit = pie_type? ? LEGEND_LENGTH : LABEL_LENGTH

          if chart_is_2d?
            mri.chart[:data][:columns] << [series_id, *data.map { |a| a[:value] }]
            mri.chart[:data][:names][series_id] = slice_legend(_(label), limit)
            mri.chart[:miq][:name_table][series_id] = label
          else
            data.each_with_index do |a, index|
              id = index.to_s
              mri.chart[:data][:columns].push([id, a[:value]])
              mri.chart[:data][:names][id] = slice_legend(_(a[:tooltip]), limit)
              mri.chart[:miq][:name_table][id] = a[:tooltip]
            end
          end

          if chart_is_stacked?
            mri.chart[:data][:groups][0] << series_id
          end
        end

        def add_axis_category_text(categories)
          if chart_is_2d?
            category_labels = categories.collect { |c| c.kind_of?(Array) ? c.first : c }
            limit = pie_type? ? LEGEND_LENGTH : LABEL_LENGTH
            mri.chart[:axis][:x][:categories] = category_labels.collect { |c| slice_legend(_(c), limit) }
            mri.chart[:miq][:category_table] = category_labels
          end
        end

        # report building methods
        def build_document_header
          super
          type = c3_convert_type(mri.graph[:type].to_s)
          mri.chart = {
            :miqChart => type,
            :data     => {:columns => [], :names => {}, :empty => {:label => {:text => _('No data available.')}}},
            :axis     => {:x => {:tick => {}}, :y => {:tick => {}, :padding => {:bottom => 0}}},
            :tooltip  => {:format => {}},
            :miq      => {:name_table => {}, :category_table => {}},
            :legend   => {}
          }

          if chart_is_2d?
            mri.chart[:axis][:x] = {
              :categories => [],
              :tick       => {}
            }
          end

          if chart_is_stacked?
            mri.chart[:data][:groups] = [[]]
          end

          # chart is numeric
          if mri.graph[:mode] == 'values'
            custom_format   = Array(mri[:col_formats])[Array(mri[:col_order]).index(raw_column_name)]
            format, options = javascript_format(mri.graph[:column].split(/(?<!:):(?!:)/)[0], custom_format)

            if format
              axis_formatter = {:function => format, :options => options}
              mri.chart[:axis][:y] = {:tick => {:format => axis_formatter}}
            end
          end

          # C&U chart
          if graph_options[:chart_type] == :performance
            unless mri.graph[:type] == 'Donut' || mri.graph[:type] == 'Pie'
              mri.chart[:legend] = {:position => 'bottom'}
            end

            return if mri.graph[:columns].blank?

            column = grouped_by_tag_category? ? mri.graph[:columns][0].split(/_+/)[0..-2].join('_') : mri.graph[:columns][0]
            format, options = javascript_format(column, nil)
            return unless format

            axis_formatter = {:function => format, :options => options}
            mri.chart[:axis][:y][:tick] = {:format => axis_formatter}
            mri.chart[:miq][:format] = axis_formatter
          end
        end

        def c3_convert_type(type)
          CONVERT_TYPES[type] || type
        end

        def chart_is_2d?
          ['Bar', 'Column', 'StackedBar', 'StackedColumn', 'Line', 'Area', 'StackedArea'].include?(c3_convert_type(mri.graph[:type]))
        end

        def chart_is_stacked?
          %w[StackedBar StackedColumn StackedArea].include?(mri.graph[:type])
        end

        # change structure of chart JSON to performance chart with timeseries data
        def build_performance_chart_area(maxcols)
          super
          change_structure_to_timeseries
        end

        def no_records_found_chart(*)
          mri.chart = {
            :axis => {:y => {:show => false}},
            :data => {:columns => [], :empty => {:label => {:text => _('No data available.')}}},
            :miq  => {:empty => true},
          }
        end

        def finalize_document
          mri.chart
        end

        private

        # change structure of hash from standard chart to timeseries chart
        def change_structure_to_timeseries
          # add 'x' as first element and move mri.chart[:axis][:x][:categories] to mri.chart[:data][:columns] as first column
          x = mri.chart[:axis][:x][:categories]
          x.unshift('x')
          mri.chart[:data][:columns].unshift(x)
          mri.chart[:data][:x] = 'x'
          # set x axis type to timeseries and remove categories
          mri.chart[:axis][:x] = {:type => 'timeseries', :tick => {}}
          # set flag for performance chart
          mri.chart[:miq][:performance_chart] = true
          # this conditions are taken from build_performance_chart_area method from chart_commons.rb
          if mri.db.include?("Daily") || (mri.where_clause && mri.where_clause.include?("daily"))
            # set format for parsing
            mri.chart[:data][:xFormat] = '%m/%d'
            # set format for labels
            mri.chart[:axis][:x][:tick][:format] = '%m/%d'
          elsif mri.extras[:realtime] == true
            mri.chart[:data][:xFormat] = '%H:%M:%S'
            mri.chart[:axis][:x][:tick][:format] = '%H:%M:%S'
          else
            mri.chart[:data][:xFormat] = '%H:%M'
            mri.chart[:axis][:x][:tick][:format] = '%H:%M'
          end
        end

        def build_reporting_chart(_maxcols)
          mri.chart[:miq][:expand_tooltip] = true
          super
        end

        def build_reporting_chart_numeric(_maxcols)
          mri.chart[:miq][:expand_tooltip] = true
          super
        end

        def build_performance_chart_pie(_maxcols)
          mri.chart[:miq][:expand_tooltip] = true
          super
        end

        def grouped_by_tag_category?
          !!(mri.performance && mri.performance.fetch_path(:group_by_category))
        end
      end
    end
  end
end