1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
require File.dirname(__FILE__) + '/base'
##
# Graph with individual horizontal bars instead of vertical bars.
class Gruff::SideBar < Gruff::Base
# Spacing factor applied between bars
attr_accessor :bar_spacing
def draw
@has_left_labels = true
super
return unless @has_data
draw_bars
end
protected
def draw_bars
# Setup spacing.
#
@bar_spacing ||= 0.9
@bars_width = @graph_height / @column_count.to_f
@bar_width = @bars_width / @norm_data.size
@d = @d.stroke_opacity 0.0
height = Array.new(@column_count, 0)
length = Array.new(@column_count, @graph_left)
padding = (@bar_width * (1 - @bar_spacing)) / 2
# if we're a side stacked bar then we don't need to draw ourself at all
# because sometimes (due to different heights/min/max) you can actually
# see both graphs and it looks like crap
return if self.is_a?(Gruff::SideStackedBar)
@norm_data.each_with_index do |data_row, row_index|
@d = @d.fill data_row[DATA_COLOR_INDEX]
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
# Using the original calcs from the stacked bar chart
# to get the difference between
# part of the bart chart we wish to stack.
temp1 = @graph_left + (@graph_width - data_point * @graph_width - height[point_index])
temp2 = @graph_left + @graph_width - height[point_index]
difference = temp2 - temp1
left_x = length[point_index] - 1
left_y = @graph_top + (@bars_width * point_index) + (@bar_width * row_index) + padding
right_x = left_x + difference
right_y = left_y + @bar_width * @bar_spacing
height[point_index] += (data_point * @graph_width)
@d = @d.rectangle(left_x, left_y, right_x, right_y)
# Calculate center based on bar_width and current row
if @use_data_label
label_center = @graph_top + (@bar_width * (row_index+point_index) + @bar_width / 2)
draw_label(label_center, row_index, @norm_data[row_index][DATA_LABEL_INDEX])
else
label_center = @graph_top + (@bars_width * point_index + @bars_width / 2)
draw_label(label_center, point_index)
end
if @show_labels_for_bar_values
val = (@label_formatting || '%.2f') % @norm_data[row_index][3][point_index]
draw_value_label(right_x+40, (@graph_top + (((row_index+point_index+1) * @bar_width) - (@bar_width / 2)))-12, val.commify, true)
end
end
end
@d.draw(@base_image)
end
# Instead of base class version, draws vertical background lines and label
def draw_line_markers
return if @hide_line_markers
@d = @d.stroke_antialias false
# Draw horizontal line markers and annotate with numbers
@d = @d.stroke(@marker_color)
@d = @d.stroke_width 1
number_of_lines = @marker_count || 5
number_of_lines = 1 if number_of_lines == 0
# TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
increment = significant(@spread.to_f / number_of_lines)
(0..number_of_lines).each do |index|
line_diff = (@graph_right - @graph_left) / number_of_lines
x = @graph_right - (line_diff * index) - 1
@d = @d.line(x, @graph_bottom, x, @graph_top)
diff = index - number_of_lines
marker_label = diff.abs * increment + @minimum_value
unless @hide_line_numbers
@d.fill = @font_color
@d.font = @font if @font
@d.stroke = 'transparent'
@d.pointsize = scale_fontsize(@marker_font_size)
@d.gravity = CenterGravity
# TODO Center text over line
@d = @d.annotate_scaled(@base_image,
0, 0, # Width of box to draw text in
x, @graph_bottom + (LABEL_MARGIN * 2.0), # Coordinates of text
marker_label.to_s, @scale)
end # unless
@d = @d.stroke_antialias true
end
end
##
# Draw on the Y axis instead of the X
def draw_label(y_offset, index, label=nil)
if !@labels[index].nil? && @labels_seen[index].nil?
lbl = (@use_data_label) ? label : @labels[index]
@d.fill = @font_color
@d.font = @font if @font
@d.stroke = 'transparent'
@d.font_weight = NormalWeight
@d.pointsize = scale_fontsize(@marker_font_size)
@d.gravity = EastGravity
@d = @d.annotate_scaled(@base_image,
1, 1,
-@graph_left + LABEL_MARGIN * 2.0, y_offset,
lbl, @scale)
@labels_seen[index] = 1
end
end
end
|