To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / lib / SVG / Graph / Bar.rb @ 441:cbce1fd3b1b7

History | View | Annotate | Download (4.26 KB)

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