File: spider.rb

package info (click to toggle)
ruby-gruff 0.6.0-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 852 kB
  • sloc: ruby: 4,929; makefile: 3
file content (131 lines) | stat: -rw-r--r-- 3,579 bytes parent folder | download | duplicates (3)
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

require File.dirname(__FILE__) + '/base'

# Experimental!!! See also the Net graph.
#
# Submitted by Kevin Clark http://glu.ttono.us/
class Gruff::Spider < Gruff::Base
  
  # Hide all text
  attr_reader :hide_text
  attr_accessor :hide_axes
  attr_reader :transparent_background
  attr_accessor :rotation
  
  def transparent_background=(value)
    @transparent_background = value
    @base_image = render_transparent_background if value
  end

  def hide_text=(value)
    @hide_title = @hide_text = value
  end

  def initialize(max_value, target_width = 800)
    super(target_width)
    @max_value = max_value
    @hide_legend = true;
    @rotation = 0
  end
  
  def draw
    @hide_line_markers = true
    
    super

    return unless @has_data

    # Setup basic positioning
    diameter = @graph_height
    radius = @graph_height / 2.0
    top_x = @graph_left + (@graph_width - diameter) / 2.0
    center_x = @graph_left + (@graph_width / 2.0)
    center_y = @graph_top + (@graph_height / 2.0) - 25 # Move graph up a bit

    @unit_length = radius / @max_value
        
    total_sum = sums_for_spider
    prev_degrees = 0.0
    additive_angle = (2 * Math::PI)/ @data.size
    
    current_angle = rotation * Math::PI / 180.0

    # Draw axes
    draw_axes(center_x, center_y, radius, additive_angle) unless hide_axes    

    # Draw polygon
    draw_polygon(center_x, center_y, additive_angle)

    @d.draw(@base_image)
  end

private

  def normalize_points(value)
    value * @unit_length
  end

  def draw_label(center_x, center_y, angle, radius, amount)
    r_offset = 50      # The distance out from the center of the pie to get point
    x_offset = center_x      # 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.cos(angle))
    y = y_offset + ((radius + r_offset) * Math.sin(angle))

    # Draw label
    @d.fill = @marker_color
    @d.font = @font if @font
    @d.pointsize = scale_fontsize(legend_font_size)
    @d.stroke = 'transparent'
    @d.font_weight = BoldWeight
    @d.gravity = CenterGravity
    @d.annotate_scaled( @base_image, 
                      0, 0,
                      x, y, 
                      amount, @scale)
  end

  def draw_axes(center_x, center_y, radius, additive_angle, line_color = nil)
    return if hide_axes

    current_angle = rotation * Math::PI / 180.0

    @data.each do |data_row|
      @d.stroke(line_color || data_row[DATA_COLOR_INDEX])
      @d.stroke_width 5.0

      x_offset = radius * Math.cos(current_angle)
      y_offset = radius * Math.sin(current_angle)

      @d.line(center_x, center_y,
              center_x + x_offset,
              center_y + y_offset)

      draw_label(center_x, center_y, current_angle, radius, data_row[DATA_LABEL_INDEX].to_s) unless hide_text

      current_angle += additive_angle
    end
  end

  def draw_polygon(center_x, center_y, additive_angle, color = nil)
    points = []
    current_angle = rotation * Math::PI / 180.0

    @data.each do |data_row|
      points << center_x + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.cos(current_angle)
      points << center_y + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.sin(current_angle)
      current_angle += additive_angle
    end

    @d.stroke_width 1.0
    @d.stroke(color || @marker_color)
    @d.fill(color || @marker_color)
    @d.fill_opacity 0.4
    @d.polygon(*points)
  end

  def sums_for_spider
    @data.inject(0.0) {|sum, data_row| sum += data_row[DATA_VALUES_INDEX].first}
  end

end