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'
# Experimental!!! See also the Spider graph.
class Gruff::Net < Gruff::Base
# Hide parts of the graph to fit more datapoints, or for a different appearance.
attr_accessor :hide_dots
# Dimensions of lines and dots; calculated based on dataset size if left unspecified
attr_accessor :line_width
attr_accessor :dot_radius
def initialize(*args)
super
@hide_dots = false
@hide_line_numbers = true
@sorted_drawing = true
end
def draw
super
return unless @has_data
@radius = @graph_height / 2.0
@center_x = @graph_left + (@graph_width / 2.0)
@center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
@x_increment = @graph_width / (@column_count - 1).to_f
circle_radius = dot_radius ||
clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
@d = @d.stroke_opacity 1.0
@d = @d.stroke_width line_width ||
clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
if defined?(@norm_baseline)
level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
@d = @d.push
@d.stroke_color @baseline_color
@d.fill_opacity 0.0
@d.stroke_dasharray(10, 20)
@d.stroke_width 5
@d.line(@graph_left, level, @graph_left + @graph_width, level)
@d = @d.pop
end
@norm_data.each do |data_row|
@d = @d.stroke data_row[DATA_COLOR_INDEX]
@d = @d.fill data_row[DATA_COLOR_INDEX]
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
next if data_point.nil?
rad_pos = index * Math::PI * 2 / @column_count
point_distance = data_point * @radius
start_x = @center_x + Math::sin(rad_pos) * point_distance
start_y = @center_y - Math::cos(rad_pos) * point_distance
next_index = index + 1 < data_row[DATA_VALUES_INDEX].length ? index + 1 : 0
next_rad_pos = next_index * Math::PI * 2 / @column_count
next_point_distance = data_row[DATA_VALUES_INDEX][next_index] * @radius
end_x = @center_x + Math::sin(next_rad_pos) * next_point_distance
end_y = @center_y - Math::cos(next_rad_pos) * next_point_distance
@d = @d.line(start_x, start_y, end_x, end_y)
@d = @d.circle(start_x, start_y, start_x - circle_radius, start_y) unless @hide_dots
end
end
@d.draw(@base_image)
end
# the lines connecting in the center, with the first line vertical
def draw_line_markers
return if @hide_line_markers
# have to do this here (AGAIN)... see draw() in this class
# because this funtion is called before the @radius, @center_x and @center_y are set
@radius = @graph_height / 2.0
@center_x = @graph_left + (@graph_width / 2.0)
@center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
# Draw horizontal line markers and annotate with numbers
@d = @d.stroke(@marker_color)
@d = @d.stroke_width 1
(0..@column_count-1).each do |index|
rad_pos = index * Math::PI * 2 / @column_count
@d = @d.line(@center_x, @center_y, @center_x + Math::sin(rad_pos) * @radius, @center_y - Math::cos(rad_pos) * @radius)
marker_label = labels[index] ? labels[index].to_s : '000'
draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius, marker_label)
end
end
private
def draw_label(center_x, center_y, angle, radius, amount)
r_offset = 1.1
x_offset = center_x # + 15 # The label points need to be tweaked slightly
y_offset = center_y # + 0 # This one doesn't though
x = x_offset + (radius * r_offset * Math.sin(angle.deg2rad))
y = y_offset - (radius * r_offset * Math.cos(angle.deg2rad))
# Draw label
@d.fill = @marker_color
@d.font = @font if @font
@d.pointsize = scale_fontsize(20)
@d.stroke = 'transparent'
@d.font_weight = BoldWeight
@d.gravity = CenterGravity
@d.annotate_scaled(@base_image, 0, 0, x, y, amount, @scale)
end
end
# # This method is already in Float
# class Float
# # Used for degree => radian conversions
# def deg2rad
# self * (Math::PI/180.0)
# end
# end
|