File: lib/SVG/Graph/Bar.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: SVG#5
  module: Graph#6
  class: Bar#58
includes
  REXML   
inherits from
  BarBase ( SVG::Graph )
has properties
method: set_defaults #62
method: get_x_labels #69
method: get_y_labels #73
method: x_label_offset / 1 #94
method: draw_data #98

Class Hierarchy

Object ( Builtin-Module )
Graph ( SVG::Graph )
BarBase ( SVG::Graph )
  Bar    #58

Code

   1  require 'rexml/document'
   2  require 'SVG/Graph/Graph'
   3  require 'SVG/Graph/BarBase'
   4 
   5  module SVG
   6    module Graph
   7      # === Create presentation quality SVG bar graphs easily
   8      #
   9      # = Synopsis
  10      #
  11      #   require 'SVG/Graph/Bar'
  12      #
  13      #   fields = %w(Jan Feb Mar);
  14      #   data_sales_02 = [12, 45, 21]
  15      #
  16      #   graph = SVG::Graph::Bar.new(
  17      #     :height => 500,
  18      #     :width => 300,
  19      #     :fields => fields
  20      #   )
  21      #
  22      #   graph.add_data(
  23      #     :data => data_sales_02,
  24      #     :title => 'Sales 2002'
  25      #   )
  26      #
  27      #   print "Content-type: image/svg+xml\r\n\r\n"
  28      #   print graph.burn
  29      #
  30      # = Description
  31      #
  32      # This object aims to allow you to easily create high quality
  33      # SVG[http://www.w3c.org/tr/svg bar graphs. You can either use the default
  34      # style sheet or supply your own. Either way there are many options which
  35      # can be configured to give you control over how the graph is generated -
  36      # with or without a key, data elements at each point, title, subtitle etc.
  37      #
  38      # = Notes
  39      #
  40      # The default stylesheet handles upto 12 data sets, if you
  41      # use more you must create your own stylesheet and add the
  42      # additional settings for the extra data sets. You will know
  43      # if you go over 12 data sets as they will have no style and
  44      # be in black.
  45      #
  46      # = Examples
  47      #
  48      # * http://germane-software.com/repositories/public/SVG/test/test.rb
  49      #
  50      # = See also
  51      #
  52      # * SVG::Graph::Graph
  53      # * SVG::Graph::BarHorizontal
  54      # * SVG::Graph::Line
  55      # * SVG::Graph::Pie
  56      # * SVG::Graph::Plot
  57      # * SVG::Graph::TimeSeries
  58      class Bar < BarBase
  59        include REXML
  60 
  61        # See Graph::initialize and BarBase::set_defaults
  62        def set_defaults 
  63          super
  64          self.top_align = self.top_font = 1
  65        end
  66 
  67        protected
  68 
  69        def get_x_labels
  70          @config[:fields]
  71        end
  72 
  73        def get_y_labels
  74          maxvalue = max_value
  75          minvalue = min_value
  76          range = maxvalue - minvalue
  77 
  78          top_pad = range == 0 ? 10 : range / 20.0
  79          scale_range = (maxvalue + top_pad) - minvalue
  80 
  81          scale_division = scale_divisions || (scale_range / 10.0)
  82 
  83          if scale_integers
  84            scale_division = scale_division < 1 ? 1 : scale_division.round
  85          end
  86 
  87          rv = []
  88          maxvalue = maxvalue%scale_division == 0 ? 
  89            maxvalue : maxvalue + scale_division
  90          minvalue.step( maxvalue, scale_division ) {|v| rv << v}
  91          return rv
  92        end
  93 
  94        def x_label_offset( width )
  95          width / 2.0
  96        end
  97 
  98        def draw_data
  99          minvalue = min_value
 100          fieldwidth = field_width
 101 
 102          unit_size =  (@graph_height.to_f - font_size*2*top_font) / 
 103                            (get_y_labels.max - get_y_labels.min)
 104          bargap = bar_gap ? (fieldwidth < 10 ? fieldwidth / 2 : 10) : 0
 105 
 106          bar_width = fieldwidth - bargap
 107          bar_width /= @data.length if stack == :side
 108          x_mod = (@graph_width-bargap)/2 - (stack==:side ? bar_width/2 : 0)
 109   
 110          bottom = @graph_height
 111 
 112          field_count = 0
 113          @config[:fields].each_index { |i|
 114            dataset_count = 0
 115            for dataset in @data
 116            
 117              # cases (assume 0 = +ve):
 118              #   value  min  length
 119              #    +ve   +ve  value - min
 120              #    +ve   -ve  value - 0
 121              #    -ve   -ve  value.abs - 0
 122            
 123              value = dataset[:data][i]
 124              
 125              left = (fieldwidth * field_count)
 126              
 127              length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
 128              # top is 0 if value is negative
 129              top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
 130              left += bar_width * dataset_count if stack == :side
 131   
 132              @graph.add_element( "rect", {
 133                "x" => left.to_s,
 134                "y" => top.to_s,
 135                "width" => bar_width.to_s,
 136                "height" => length.to_s,
 137                "class" => "fill#{dataset_count+1}"
 138              })
 139 
 140              make_datapoint_text(left + bar_width/2.0, top - 6, value.to_s)
 141              dataset_count += 1
 142            end
 143            field_count += 1
 144          }
 145        end
 146      end
 147    end
 148  end