To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
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
|