gruff 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,109 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ class Gruff::Bullet < Gruff::Base
4
+
5
+ def initialize(target_width="400x40")
6
+ if not Numeric === target_width
7
+ geometric_width, geometric_height = target_width.split('x')
8
+ @columns = geometric_width.to_f
9
+ @rows = geometric_height.to_f
10
+ else
11
+ @columns = target_width.to_f
12
+ @rows = target_width.to_f / 5.0
13
+ end
14
+
15
+ initialize_ivars
16
+
17
+ reset_themes
18
+ theme_greyscale
19
+ @title_font_size = 20
20
+ end
21
+
22
+ def data(value, maximum_value, options={})
23
+ @value = value.to_f
24
+ @maximum_value = maximum_value.to_f
25
+ @options = options
26
+ @options.map { |k, v| @options[k] = v.to_f if v === Numeric }
27
+ end
28
+
29
+ # def setup_drawing
30
+ # # Maybe should be done in one of the following functions for more granularity.
31
+ # unless @has_data
32
+ # draw_no_data()
33
+ # return
34
+ # end
35
+ #
36
+ # normalize()
37
+ # setup_graph_measurements()
38
+ # sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display)
39
+ #
40
+ # draw_legend()
41
+ # draw_line_markers()
42
+ # draw_axis_labels()
43
+ # draw_title
44
+ # end
45
+
46
+ def draw
47
+ # TODO Left label
48
+ # TODO Bottom labels and markers
49
+ # @graph_bottom
50
+ # Calculations are off 800x???
51
+
52
+ @colors.reverse!
53
+
54
+ draw_title
55
+
56
+ @margin = 30.0
57
+ @thickness = @raw_rows / 6.0
58
+ @right_margin = @margin
59
+ @graph_left = @title_width * 1.3 rescue @margin # HACK Need to calculate real width
60
+ @graph_width = @raw_columns - @graph_left - @right_margin
61
+ @graph_height = @thickness * 3.0
62
+
63
+ # Background
64
+ @d = @d.fill @colors[0]
65
+ @d = @d.rectangle(@graph_left, 0, @graph_left + @graph_width, @graph_height)
66
+
67
+ [:high, :low].each_with_index do |indicator, index|
68
+ next unless @options.has_key?(indicator)
69
+ @d = @d.fill @colors[index + 1]
70
+ indicator_width_x = @graph_left + @graph_width * (@options[indicator] / @maximum_value)
71
+ @d = @d.rectangle(@graph_left, 0, indicator_width_x, @graph_height)
72
+ end
73
+
74
+ if @options.has_key?(:target)
75
+ @d = @d.fill @font_color
76
+ target_x = @graph_left + @graph_width * (@options[:target] / @maximum_value)
77
+ half_thickness = @thickness / 2.0
78
+ @d = @d.rectangle(target_x, half_thickness, target_x + half_thickness, @thickness * 2 + half_thickness)
79
+ end
80
+
81
+ # Value
82
+ @d = @d.fill @font_color
83
+ @d = @d.rectangle(@graph_left, @thickness, @graph_left + @graph_width * (@value / @maximum_value), @thickness * 2)
84
+
85
+ @d.draw(@base_image)
86
+ end
87
+
88
+ def draw_title
89
+ return unless @title
90
+
91
+ @font_height = calculate_caps_height(scale_fontsize(@title_font_size))
92
+ @title_width = calculate_width(@title_font_size, @title)
93
+
94
+ @d.fill = @font_color
95
+ @d.font = @font if @font
96
+ @d.stroke('transparent')
97
+ @d.font_weight = NormalWeight
98
+ @d.pointsize = scale_fontsize(@title_font_size)
99
+ @d.gravity = NorthWestGravity
100
+ @d = @d.annotate_scaled(*[
101
+ @base_image,
102
+ 1.0, 1.0,
103
+ @font_height/2, @font_height/2,
104
+ @title,
105
+ @scale
106
+ ])
107
+ end
108
+
109
+ end
data/lib/gruff/line.rb CHANGED
@@ -67,7 +67,7 @@ class Gruff::Line < Gruff::Base
67
67
  @norm_data.each do |data_row|
68
68
  prev_x = prev_y = nil
69
69
 
70
- data_row[1].each_with_index do |data_point, index|
70
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
71
71
  new_x = @graph_left + (@x_increment * index)
72
72
  next if data_point.nil?
73
73
 
@@ -79,12 +79,12 @@ class Gruff::Line < Gruff::Base
79
79
  @d = @d.stroke data_row[DATA_COLOR_INDEX]
80
80
  @d = @d.fill data_row[DATA_COLOR_INDEX]
81
81
  @d = @d.stroke_opacity 1.0
82
- @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 4), 5.0)
82
+ @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
83
83
 
84
84
  if !@hide_lines and !prev_x.nil? and !prev_y.nil? then
85
85
  @d = @d.line(prev_x, prev_y, new_x, new_y)
86
86
  end
87
- circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 2.5), 5.0)
87
+ circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
88
88
  @d = @d.circle(new_x, new_y, new_x - circle_radius, new_y) unless @hide_dots
89
89
 
90
90
  prev_x = new_x
data/lib/gruff/net.rb CHANGED
@@ -24,10 +24,10 @@ class Gruff::Net < Gruff::Base
24
24
  @center_y = @graph_top + (@graph_height / 2.0) - 10 # Move graph up a bit
25
25
 
26
26
  @x_increment = @graph_width / (@column_count - 1).to_f
27
- circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 2.5), 5.0)
27
+ circle_radius = clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 2.5), 5.0)
28
28
 
29
29
  @d = @d.stroke_opacity 1.0
30
- @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[1].size * 4), 5.0)
30
+ @d = @d.stroke_width clip_value_if_greater_than(@columns / (@norm_data.first[DATA_VALUES_INDEX].size * 4), 5.0)
31
31
 
32
32
  if (defined?(@norm_baseline)) then
33
33
  level = @graph_top + (@graph_height - @norm_baseline * @graph_height)
@@ -45,7 +45,7 @@ class Gruff::Net < Gruff::Base
45
45
  @d = @d.stroke data_row[DATA_COLOR_INDEX]
46
46
  @d = @d.fill data_row[DATA_COLOR_INDEX]
47
47
 
48
- data_row[1].each_with_index do |data_point, index|
48
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
49
49
  next if data_point.nil?
50
50
 
51
51
  rad_pos = index * Math::PI * 2 / @column_count
@@ -53,10 +53,10 @@ class Gruff::Net < Gruff::Base
53
53
  start_x = @center_x + Math::sin(rad_pos) * point_distance
54
54
  start_y = @center_y - Math::cos(rad_pos) * point_distance
55
55
 
56
- next_index = index + 1 < data_row[1].length ? index + 1 : 0
56
+ next_index = index + 1 < data_row[DATA_VALUES_INDEX].length ? index + 1 : 0
57
57
 
58
58
  next_rad_pos = next_index * Math::PI * 2 / @column_count
59
- next_point_distance = data_row[1][next_index] * @radius
59
+ next_point_distance = data_row[DATA_VALUES_INDEX][next_index] * @radius
60
60
  end_x = @center_x + Math::sin(next_rad_pos) * next_point_distance
61
61
  end_y = @center_y - Math::cos(next_rad_pos) * next_point_distance
62
62
 
@@ -48,7 +48,7 @@ class Gruff::PhotoBar < Gruff::Base
48
48
 
49
49
  @norm_data.each_with_index do |data_row, row_index|
50
50
 
51
- data_row[1].each_with_index do |data_point, point_index|
51
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
52
52
  data_point = 0 if data_point.nil?
53
53
  # Use incremented x and scaled y
54
54
  left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
data/lib/gruff/pie.rb CHANGED
@@ -40,14 +40,14 @@ class Gruff::Pie < Gruff::Base
40
40
  prev_degrees = @zero_degree
41
41
 
42
42
  # Use full data since we can easily calculate percentages
43
- data = (@sort ? @data.sort{ |a, b| a[DATA_VALUES_INDEX][0] <=> b[DATA_VALUES_INDEX][0] } : @data)
43
+ data = (@sort ? @data.sort{ |a, b| a[DATA_VALUES_INDEX].first <=> b[DATA_VALUES_INDEX].first } : @data)
44
44
  data.each do |data_row|
45
- if data_row[DATA_VALUES_INDEX][0] > 0
45
+ if data_row[DATA_VALUES_INDEX].first > 0
46
46
  @d = @d.stroke data_row[DATA_COLOR_INDEX]
47
47
  @d = @d.fill 'transparent'
48
48
  @d.stroke_width(radius) # stroke width should be equal to radius. we'll draw centered on (radius / 2)
49
49
 
50
- current_degrees = (data_row[DATA_VALUES_INDEX][0] / total_sum) * 360.0
50
+ current_degrees = (data_row[DATA_VALUES_INDEX].first / total_sum) * 360.0
51
51
 
52
52
  # ellipse will draw the the stroke centered on the first two parameters offset by the second two.
53
53
  # therefore, in order to draw a circle of the proper diameter we must center the stroke at
@@ -63,7 +63,7 @@ class Gruff::Pie < Gruff::Base
63
63
  # unless @hide_line_markers then
64
64
  # End the string with %% to escape the single %.
65
65
  # RMagick must use sprintf with the string and % has special significance.
66
- label_string = ((data_row[DATA_VALUES_INDEX][0] / total_sum) *
66
+ label_string = ((data_row[DATA_VALUES_INDEX].first / total_sum) *
67
67
  100.0).round.to_s + '%%'
68
68
  @d = draw_label(center_x,center_y, half_angle,
69
69
  radius + (radius * TEXT_OFFSET_PERCENTAGE),
@@ -109,7 +109,7 @@ private
109
109
 
110
110
  def sums_for_pie
111
111
  total_sum = 0.0
112
- @data.collect {|data_row| total_sum += data_row[DATA_VALUES_INDEX][0] }
112
+ @data.collect {|data_row| total_sum += data_row[DATA_VALUES_INDEX].first }
113
113
  total_sum
114
114
  end
115
115
 
@@ -24,7 +24,7 @@ class Gruff::SideBar < Gruff::Base
24
24
  @norm_data.each_with_index do |data_row, row_index|
25
25
  @d = @d.fill data_row[DATA_COLOR_INDEX]
26
26
 
27
- data_row[1].each_with_index do |data_point, point_index|
27
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
28
28
 
29
29
  # Using the original calcs from the stacked bar chart
30
30
  # to get the difference between
@@ -31,7 +31,7 @@ class Gruff::SideStackedBar < Gruff::SideBar
31
31
  @norm_data.each_with_index do |data_row, row_index|
32
32
  @d = @d.fill data_row[DATA_COLOR_INDEX]
33
33
 
34
- data_row[1].each_with_index do |data_point, point_index|
34
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
35
35
 
36
36
  ## using the original calcs from the stacked bar chart to get the difference between
37
37
  ## part of the bart chart we wish to stack.
@@ -67,7 +67,7 @@ class Gruff::SideStackedBar < Gruff::SideBar
67
67
  end
68
68
 
69
69
  def max(data_point, index)
70
- @data.inject(0) {|sum, item| sum + item[1][index]}
70
+ @data.inject(0) {|sum, item| sum + item[DATA_VALUES_INDEX][index]}
71
71
  end
72
72
 
73
73
  end
data/lib/gruff/spider.rb CHANGED
@@ -101,7 +101,7 @@ private
101
101
  center_x + x_offset,
102
102
  center_y + y_offset)
103
103
 
104
- draw_label(center_x, center_y, current_angle, radius, data_row[0].to_s) unless hide_text
104
+ draw_label(center_x, center_y, current_angle, radius, data_row[DATA_LABEL_INDEX].to_s) unless hide_text
105
105
 
106
106
  current_angle += additive_angle
107
107
  end
@@ -111,8 +111,8 @@ private
111
111
  points = []
112
112
  current_angle = 0.0
113
113
  @data.each do |data_row|
114
- points << center_x + normalize_points(data_row[1][0]) * Math.cos(current_angle)
115
- points << center_y + normalize_points(data_row[1][0]) * Math.sin(current_angle)
114
+ points << center_x + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.cos(current_angle)
115
+ points << center_y + normalize_points(data_row[DATA_VALUES_INDEX].first) * Math.sin(current_angle)
116
116
  current_angle += additive_angle
117
117
  end
118
118
 
@@ -124,7 +124,7 @@ private
124
124
  end
125
125
 
126
126
  def sums_for_spider
127
- @data.inject(0.0) {|sum, data_row| sum += data_row[1][0]}
127
+ @data.inject(0.0) {|sum, data_row| sum += data_row[DATA_VALUES_INDEX].first}
128
128
  end
129
129
 
130
130
  end
@@ -7,6 +7,7 @@ class Gruff::StackedArea < Gruff::Base
7
7
  attr_accessor :last_series_goes_on_bottom
8
8
 
9
9
  def draw
10
+ get_maximum_by_stack
10
11
  super
11
12
 
12
13
  return unless @has_data
@@ -24,7 +25,7 @@ class Gruff::StackedArea < Gruff::Base
24
25
 
25
26
  @d = @d.fill data_row[DATA_COLOR_INDEX]
26
27
 
27
- data_row[1].each_with_index do |data_point, index|
28
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
28
29
  # Use incremented x and scaled y
29
30
  new_x = @graph_left + (@x_increment * index)
30
31
  new_y = @graph_top + (@graph_height - data_point * @graph_height - height[index])
@@ -21,10 +21,10 @@ class Gruff::StackedBar < Gruff::Base
21
21
 
22
22
  height = Array.new(@column_count, 0)
23
23
 
24
- @norm_data.each_with_index do |data_row, row_index|
25
- @d = @d.fill data_row[DATA_COLOR_INDEX]
26
-
27
- data_row[1].each_with_index do |data_point, point_index|
24
+ @norm_data.each_with_index do |data_row, row_index|
25
+ data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
26
+ @d = @d.fill data_row[DATA_COLOR_INDEX]
27
+
28
28
  # Calculate center based on bar_width and current row
29
29
  label_center = @graph_left + (@bar_width * point_index) + (@bar_width * spacing_factor / 2.0)
30
30
  draw_label(label_center, point_index)
@@ -0,0 +1,63 @@
1
+ class GruffGenerator < Rails::Generator::NamedBase
2
+
3
+ attr_reader :controller_name,
4
+ :controller_class_path,
5
+ :controller_file_path,
6
+ :controller_class_nesting,
7
+ :controller_class_nesting_depth,
8
+ :controller_class_name,
9
+ :controller_singular_name,
10
+ :controller_plural_name,
11
+ :parent_folder_for_require
12
+ alias_method :controller_file_name, :controller_singular_name
13
+ alias_method :controller_table_name, :controller_plural_name
14
+
15
+ def initialize(runtime_args, runtime_options = {})
16
+ super
17
+
18
+ # Take controller name from the next argument.
19
+ @controller_name = runtime_args.shift
20
+
21
+ base_name, @controller_class_path, @controller_file_path, @controller_class_nesting, @controller_class_nesting_depth = extract_modules(@controller_name)
22
+ @controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
23
+
24
+ if @controller_class_nesting.empty?
25
+ @controller_class_name = @controller_class_name_without_nesting
26
+ else
27
+ @controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
28
+ end
29
+ end
30
+
31
+ def manifest
32
+ record do |m|
33
+ # Check for class naming collisions.
34
+ m.class_collisions controller_class_path, "#{controller_class_name}Controller",
35
+ "#{controller_class_name}ControllerTest"
36
+
37
+ # Controller, helper, views, and test directories.
38
+ m.directory File.join('app/controllers', controller_class_path)
39
+ m.directory File.join('test/functional', controller_class_path)
40
+
41
+ m.template 'controller.rb',
42
+ File.join('app/controllers',
43
+ controller_class_path,
44
+ "#{controller_file_name}_controller.rb")
45
+
46
+ # For some reason this doesn't take effect if done in initialize()
47
+ @parent_folder_for_require = @controller_class_path.join('/').gsub(%r%app/controllers/?%, '')
48
+ @parent_folder_for_require += @parent_folder_for_require.blank? ? '' : '/'
49
+
50
+ m.template 'functional_test.rb',
51
+ File.join('test/functional',
52
+ controller_class_path,
53
+ "#{controller_file_name}_controller_test.rb")
54
+
55
+ end
56
+ end
57
+
58
+ protected
59
+ # Override with your own usage banner.
60
+ def banner
61
+ "Usage: #{$0} gruff ControllerName"
62
+ end
63
+ end
@@ -0,0 +1,32 @@
1
+ class <%= controller_class_name %>Controller < ApplicationController
2
+
3
+ # To make caching easier, add a line like this to config/routes.rb:
4
+ # map.graph "graph/:action/:id/image.png", :controller => "graph"
5
+ #
6
+ # Then reference it with the named route:
7
+ # image_tag graph_url(:action => 'show', :id => 42)
8
+
9
+ def show
10
+ g = Gruff::Line.new
11
+ # Uncomment to use your own theme or font
12
+ # See http://colourlovers.com or http://www.firewheeldesign.com/widgets/ for color ideas
13
+ # g.theme = {
14
+ # :colors => ['#663366', '#cccc99', '#cc6633', '#cc9966', '#99cc99'],
15
+ # :marker_color => 'white',
16
+ # :background_colors => ['black', '#333333']
17
+ # }
18
+ # g.font = File.expand_path('artwork/fonts/VeraBd.ttf', RAILS_ROOT)
19
+
20
+ g.title = "Gruff-o-Rama"
21
+
22
+ g.data("Apples", [1, 2, 3, 4, 4, 3])
23
+ g.data("Oranges", [4, 8, 7, 9, 8, 9])
24
+ g.data("Watermelon", [2, 3, 1, 5, 6, 8])
25
+ g.data("Peaches", [9, 9, 10, 8, 7, 9])
26
+
27
+ g.labels = {0 => '2004', 2 => '2005', 4 => '2006'}
28
+
29
+ send_data(g.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "gruff.png")
30
+ end
31
+
32
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '<%= '/..' * controller_class_name.split("::").length %>/test_helper'
2
+ require '<%= parent_folder_for_require %><%= controller_file_name %>_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class <%= controller_class_name %>Controller; def rescue_action(e) raise e end; end
6
+
7
+ class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
8
+
9
+ #fixtures :data
10
+
11
+ def setup
12
+ @controller = <%= controller_class_name %>Controller.new
13
+ @request = ActionController::TestRequest.new
14
+ @response = ActionController::TestResponse.new
15
+ end
16
+
17
+ # TODO Replace this with your actual tests
18
+ def test_show
19
+ get :show
20
+ assert_response :success
21
+ assert_equal 'image/png', @response.headers['Content-Type']
22
+ end
23
+
24
+ end
@@ -3,8 +3,12 @@ $:.unshift(File.dirname(__FILE__) + "/../lib/")
3
3
 
4
4
  require 'test/unit'
5
5
  require 'gruff'
6
+ require 'fileutils'
6
7
  # require 'test_timer'
7
8
 
9
+ TEST_OUTPUT_DIR = File.dirname(__FILE__) + "/output"
10
+ FileUtils.mkdir_p(TEST_OUTPUT_DIR)
11
+
8
12
  class GruffTestCase < Test::Unit::TestCase
9
13
 
10
14
  def setup
@@ -76,7 +80,7 @@ protected
76
80
  end
77
81
 
78
82
  def write_test_file(graph, filename)
79
- graph.write(File.dirname(__FILE__) + "/output/#{filename}")
83
+ graph.write([TEST_OUTPUT_DIR, filename].join("/"))
80
84
  end
81
85
 
82
86
  ##