gruff 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  ##