gruff 0.12.2 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +66 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +34 -27
  5. data/CHANGELOG.md +29 -0
  6. data/README.md +15 -7
  7. data/assets/fonts/LICENSE.txt +202 -0
  8. data/assets/fonts/Roboto-Bold.ttf +0 -0
  9. data/assets/fonts/Roboto-Regular.ttf +0 -0
  10. data/gruff.gemspec +9 -10
  11. data/lib/gruff/accumulator_bar.rb +3 -1
  12. data/lib/gruff/area.rb +5 -8
  13. data/lib/gruff/bar.rb +32 -49
  14. data/lib/gruff/base.rb +199 -115
  15. data/lib/gruff/bezier.rb +4 -6
  16. data/lib/gruff/bullet.rb +12 -11
  17. data/lib/gruff/dot.rb +13 -14
  18. data/lib/gruff/font.rb +39 -0
  19. data/lib/gruff/helper/bar_conversion.rb +27 -12
  20. data/lib/gruff/helper/bar_value_label.rb +71 -0
  21. data/lib/gruff/helper/stacked_mixin.rb +1 -2
  22. data/lib/gruff/histogram.rb +9 -7
  23. data/lib/gruff/line.rb +57 -50
  24. data/lib/gruff/mini/bar.rb +9 -6
  25. data/lib/gruff/mini/legend.rb +12 -8
  26. data/lib/gruff/mini/pie.rb +9 -6
  27. data/lib/gruff/mini/side_bar.rb +9 -6
  28. data/lib/gruff/net.rb +9 -15
  29. data/lib/gruff/patch/rmagick.rb +0 -1
  30. data/lib/gruff/patch/string.rb +1 -1
  31. data/lib/gruff/pie.rb +23 -65
  32. data/lib/gruff/renderer/bezier.rb +8 -9
  33. data/lib/gruff/renderer/circle.rb +8 -9
  34. data/lib/gruff/renderer/dash_line.rb +9 -10
  35. data/lib/gruff/renderer/dot.rb +13 -14
  36. data/lib/gruff/renderer/ellipse.rb +8 -9
  37. data/lib/gruff/renderer/line.rb +8 -9
  38. data/lib/gruff/renderer/polygon.rb +9 -10
  39. data/lib/gruff/renderer/polyline.rb +8 -9
  40. data/lib/gruff/renderer/rectangle.rb +7 -8
  41. data/lib/gruff/renderer/renderer.rb +25 -40
  42. data/lib/gruff/renderer/text.rb +21 -29
  43. data/lib/gruff/scatter.rb +55 -75
  44. data/lib/gruff/scene.rb +28 -18
  45. data/lib/gruff/side_bar.rb +35 -54
  46. data/lib/gruff/side_stacked_bar.rb +14 -17
  47. data/lib/gruff/spider.rb +11 -20
  48. data/lib/gruff/stacked_area.rb +10 -11
  49. data/lib/gruff/stacked_bar.rb +14 -15
  50. data/lib/gruff/store/store.rb +6 -10
  51. data/lib/gruff/store/xy_data.rb +2 -0
  52. data/lib/gruff/themes.rb +6 -6
  53. data/lib/gruff/version.rb +1 -1
  54. data/lib/gruff.rb +68 -55
  55. data/rails_generators/gruff/templates/controller.rb +1 -1
  56. metadata +34 -20
  57. data/.rubocop_todo.yml +0 -190
  58. data/.travis.yml +0 -23
  59. data/assets/plastik/blue.png +0 -0
  60. data/assets/plastik/green.png +0 -0
  61. data/assets/plastik/red.png +0 -0
  62. data/lib/gruff/helper/bar_value_label_mixin.rb +0 -33
  63. data/lib/gruff/photo_bar.rb +0 -93
@@ -5,12 +5,10 @@ module Gruff
5
5
  class Renderer::Text
6
6
  using Magick::GruffAnnotate
7
7
 
8
- def initialize(text, font:, size:, color:, weight: Magick::NormalWeight, rotation: nil)
8
+ def initialize(renderer, text, font:, rotation: nil)
9
+ @renderer = renderer
9
10
  @text = text.to_s
10
11
  @font = font
11
- @font_size = size
12
- @font_color = color
13
- @font_weight = weight
14
12
  @rotation = rotation
15
13
  end
16
14
 
@@ -23,42 +21,36 @@ module Gruff
23
21
  @y = y
24
22
  @gravity = gravity
25
23
 
26
- Renderer.instance.text_renderers << self
24
+ @renderer.text_renderers << self
27
25
  end
28
26
 
29
27
  def render(width, height, x, y, gravity = Magick::NorthGravity)
30
- draw = Renderer.instance.draw
31
- image = Renderer.instance.image
32
- scale = Renderer.instance.scale
33
-
34
- draw.rotation = @rotation if @rotation
35
- draw.fill = @font_color
36
- draw.stroke = 'transparent'
37
- draw.font = @font if @font
38
- draw.font_weight = @font_weight
39
- draw.pointsize = @font_size * scale
40
- draw.gravity = gravity
41
- draw.annotate_scaled(image,
42
- width, height,
43
- x, y,
44
- @text, scale)
45
- draw.rotation = -@rotation if @rotation
28
+ @renderer.draw.rotation = @rotation if @rotation
29
+ @renderer.draw.fill = @font.color
30
+ @renderer.draw.stroke = 'transparent'
31
+ @renderer.draw.font = @font.file_path
32
+ @renderer.draw.font_weight = @font.weight
33
+ @renderer.draw.pointsize = @font.size * @renderer.scale
34
+ @renderer.draw.gravity = gravity
35
+ @renderer.draw.annotate_scaled(@renderer.image,
36
+ width, height,
37
+ x, y,
38
+ @text, @renderer.scale)
39
+ @renderer.draw.rotation = -@rotation if @rotation
46
40
  end
47
41
 
48
- def self.metrics(text, size, font_weight = Magick::NormalWeight)
49
- draw = Renderer.instance.draw
50
- image = Renderer.instance.image
51
-
52
- draw.font_weight = font_weight
53
- draw.pointsize = size
42
+ def metrics
43
+ @renderer.draw.font = @font.file_path
44
+ @renderer.draw.font_weight = @font.weight
45
+ @renderer.draw.pointsize = @font.size
54
46
 
55
47
  # The old ImageMagick causes SEGV with string which has '%' + alphabet (eg. '%S').
56
48
  # This format is used to embed value into a string using image properties.
57
49
  # However, gruff use plain image as canvas which does not have any property.
58
50
  # So, in here, it just escape % in order to avoid SEGV.
59
- text = text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
51
+ text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
60
52
 
61
- draw.get_type_metrics(image, text)
53
+ @renderer.draw.get_type_metrics(@renderer.image, text)
62
54
  end
63
55
  end
64
56
  end
data/lib/gruff/scatter.rb CHANGED
@@ -28,60 +28,18 @@ class Gruff::Scatter < Gruff::Base
28
28
  # This is useful when working with a small range of high values (for example, a date range of months, while seconds as units).
29
29
  attr_writer :disable_significant_rounding_x_axis
30
30
 
31
- # Allow enabling vertical lines. When you have a lot of data, they can work great.
32
- attr_writer :enable_vertical_line_markers
31
+ # Allow for vertical marker lines.
32
+ attr_writer :show_vertical_markers
33
33
 
34
34
  # Allow using vertical labels in the X axis (and setting the label margin).
35
35
  attr_writer :x_label_margin
36
36
  attr_writer :use_vertical_x_labels
37
37
 
38
- # Allow passing lambdas to format labels.
39
- attr_writer :y_axis_label_format
40
- attr_writer :x_axis_label_format
41
-
42
- def initialize_store
43
- @store = Gruff::Store.new(Gruff::Store::XYData)
44
- end
45
- private :initialize_store
46
-
47
- def initialize_ivars
48
- super
49
-
50
- @baseline_x_color = @baseline_y_color = 'red'
51
- @baseline_x_value = @baseline_y_value = nil
52
- @circle_radius = nil
53
- @disable_significant_rounding_x_axis = false
54
- @enable_vertical_line_markers = false
55
- @marker_x_count = nil
56
- @maximum_x_value = @minimum_x_value = nil
57
- @stroke_width = nil
58
- @use_vertical_x_labels = false
59
- @x_axis_label_format = nil
60
- @x_label_margin = nil
61
- @y_axis_label_format = nil
62
- end
63
- private :initialize_ivars
64
-
65
- def draw
66
- super
67
- return unless data_given?
68
-
69
- # Check to see if more than one datapoint was given. NaN can result otherwise.
70
- @x_increment = (@x_spread > 1) ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
71
-
72
- store.norm_data.each do |data_row|
73
- data_row.coordinates.each do |x_value, y_value|
74
- next if y_value.nil? || x_value.nil?
75
-
76
- new_x = get_x_coord(x_value, @graph_width, @graph_left)
77
- new_y = @graph_top + (@graph_height - y_value * @graph_height)
78
-
79
- # Reset each time to avoid thin-line errors
80
- stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
81
- circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
82
- Gruff::Renderer::Circle.new(color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
83
- end
84
- end
38
+ # Allow enabling vertical lines. When you have a lot of data, they can work great.
39
+ # @deprecated Please use +show_vertical_markers+ attribute instead.
40
+ def enable_vertical_line_markers=(value)
41
+ warn '#enable_vertical_line_markers= is deprecated. Please use `show_vertical_markers` attribute instead'
42
+ @show_vertical_markers = value
85
43
  end
86
44
 
87
45
  # The first parameter is the name of the dataset. The next two are the
@@ -137,6 +95,44 @@ class Gruff::Scatter < Gruff::Base
137
95
 
138
96
  private
139
97
 
98
+ def initialize_store
99
+ @store = Gruff::Store.new(Gruff::Store::XYData)
100
+ end
101
+
102
+ def initialize_attributes
103
+ super
104
+
105
+ @baseline_x_color = @baseline_y_color = 'red'
106
+ @baseline_x_value = @baseline_y_value = nil
107
+ @circle_radius = nil
108
+ @disable_significant_rounding_x_axis = false
109
+ @show_vertical_markers = false
110
+ @marker_x_count = nil
111
+ @maximum_x_value = @minimum_x_value = nil
112
+ @stroke_width = nil
113
+ @use_vertical_x_labels = false
114
+ @x_label_margin = nil
115
+ end
116
+
117
+ def draw_graph
118
+ # Check to see if more than one datapoint was given. NaN can result otherwise.
119
+ @x_increment = @x_spread > 1 ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
120
+
121
+ store.norm_data.each do |data_row|
122
+ data_row.coordinates.each do |x_value, y_value|
123
+ next if y_value.nil? || x_value.nil?
124
+
125
+ new_x = get_x_coord(x_value, @graph_width, @graph_left)
126
+ new_y = @graph_top + (@graph_height - y_value * @graph_height)
127
+
128
+ # Reset each time to avoid thin-line errors
129
+ stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
130
+ circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
131
+ Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
132
+ end
133
+ end
134
+ end
135
+
140
136
  def setup_data
141
137
  # Update the global min/max values for the x data
142
138
  @maximum_x_value ||= store.max_x
@@ -152,7 +148,7 @@ private
152
148
  super
153
149
  end
154
150
 
155
- def calculate_spread #:nodoc:
151
+ def calculate_spread
156
152
  super
157
153
  @x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
158
154
  @x_spread = @x_spread > 0 ? @x_spread : 1
@@ -180,18 +176,18 @@ private
180
176
  end
181
177
  @marker_x_count ||= 4
182
178
  end
183
- @x_increment = (@x_spread > 0) ? (@x_spread / @marker_x_count) : 1
179
+ @x_increment = @x_spread > 0 ? (@x_spread / @marker_x_count) : 1
184
180
  unless @disable_significant_rounding_x_axis
185
181
  @x_increment = significant(@x_increment)
186
182
  end
187
183
  else
188
184
  # TODO: Make this work for negative values
189
- @maximum_x_value = [maximum_value.ceil, @x_axis_increment].max
185
+ @maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment].max
190
186
  @minimum_x_value = @minimum_x_value.floor
191
187
  calculate_spread
192
188
  normalize
193
189
 
194
- self.marker_count = (@x_spread / @x_axis_increment).to_i
190
+ @marker_x_count = (@x_spread / @x_axis_increment).to_i
195
191
  @x_increment = @x_axis_increment
196
192
  end
197
193
  increment_x_scaled = @graph_width.to_f / (@x_spread / @x_increment)
@@ -199,43 +195,27 @@ private
199
195
  # Draw vertical line markers and annotate with numbers
200
196
  (0..@marker_x_count).each do |index|
201
197
  # TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
202
- if @enable_vertical_line_markers
198
+ if @show_vertical_markers
203
199
  x = @graph_left + @graph_width - index.to_f * increment_x_scaled
204
200
 
205
- line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
201
+ line_renderer = Gruff::Renderer::Line.new(renderer, color: @marker_color, shadow_color: @marker_shadow_color)
206
202
  line_renderer.render(x, @graph_top, x, @graph_bottom)
207
203
  end
208
204
 
209
205
  unless @hide_line_numbers
210
- marker_label = index * @x_increment + @minimum_x_value.to_f
206
+ marker_label = BigDecimal(index.to_s) * BigDecimal(@x_increment.to_s) + BigDecimal(@minimum_x_value.to_s)
211
207
  y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
212
208
  x_offset = get_x_coord(index.to_f, increment_x_scaled, @graph_left)
213
209
 
214
- label = vertical_label(marker_label, @x_increment)
210
+ label = x_axis_label(marker_label, @x_increment)
215
211
  rotation = -90.0 if @use_vertical_x_labels
216
- text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color, rotation: rotation)
212
+ text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
217
213
  text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
218
214
  end
219
215
  end
220
216
  end
221
217
 
222
- def label(value, increment)
223
- if @y_axis_label_format
224
- @y_axis_label_format.call(value)
225
- else
226
- super
227
- end
228
- end
229
-
230
- def vertical_label(value, increment)
231
- if @x_axis_label_format
232
- @x_axis_label_format.call(value)
233
- else
234
- label(value, increment)
235
- end
236
- end
237
-
238
- def get_x_coord(x_data_point, width, offset) #:nodoc:
218
+ def get_x_coord(x_data_point, width, offset)
239
219
  x_data_point * width + offset
240
220
  end
241
221
  end
data/lib/gruff/scene.rb CHANGED
@@ -52,7 +52,7 @@ class Gruff::Scene < Gruff::Base
52
52
  # Join all the custom paths and filter out the empty ones
53
53
  image_paths = @layers.map(&:path).reject(&:empty?)
54
54
  images = Magick::ImageList.new(*image_paths)
55
- Gruff::Renderer.background_image = images.flatten_images
55
+ renderer.background_image = images.flatten_images
56
56
  end
57
57
 
58
58
  def layers=(ordered_list)
@@ -73,12 +73,20 @@ class Gruff::Scene < Gruff::Base
73
73
  case method_name.to_s
74
74
  when /^(\w+)_group=$/
75
75
  add_group Regexp.last_match(1), *args
76
- return
77
76
  when /^(\w+)=$/
78
77
  set_input Regexp.last_match(1), args.first
79
- return
78
+ else
79
+ super
80
+ end
81
+ end
82
+
83
+ def respond_to_missing?(method_sym, include_private)
84
+ case method_sym.to_s
85
+ when /^(\w+)_group=$/, /^(\w+)=$/
86
+ true
87
+ else
88
+ super
80
89
  end
81
- super
82
90
  end
83
91
 
84
92
  private
@@ -90,7 +98,7 @@ private
90
98
  def set_input(input_name, input_value)
91
99
  if !@groups[input_name].nil?
92
100
  @groups[input_name].send_updates(input_value)
93
- elsif chosen_layer = @layers.find { |layer| layer.name == input_name }
101
+ elsif (chosen_layer = @layers.find { |layer| layer.name == input_name })
94
102
  chosen_layer.update input_value
95
103
  end
96
104
  end
@@ -121,7 +129,7 @@ class Gruff::Layer
121
129
  def initialize(base_dir, folder_name)
122
130
  @base_dir = base_dir.to_s
123
131
  @name = folder_name.to_s
124
- @filenames = Dir.open(File.join(base_dir, folder_name)).entries.select { |file| file =~ /^[^.]+\.png$/ }.sort
132
+ @filenames = Dir.open(File.join(base_dir, folder_name)).entries.grep(/^[^.]+\.png$/).sort
125
133
  @selected_filename = select_default
126
134
  end
127
135
 
@@ -132,18 +140,20 @@ class Gruff::Layer
132
140
 
133
141
  # Choose the appropriate filename for this layer, based on the input
134
142
  def update(value)
135
- @selected_filename = case value.to_s
136
- when /^(true|false)$/
137
- select_boolean value
138
- when /^(\w|\s)+$/
139
- select_string value
140
- when /^-?(\d+\.)?\d+$/
141
- select_numeric value
142
- when /(\d\d):(\d\d):\d\d/
143
- select_time "#{Regexp.last_match(1)}#{Regexp.last_match(2)}"
144
- else
145
- select_default
146
- end
143
+ @selected_filename = begin
144
+ case value.to_s
145
+ when /^(true|false)$/
146
+ select_boolean value
147
+ when /^(\w|\s)+$/
148
+ select_string value
149
+ when /^-?(\d+\.)?\d+$/
150
+ select_numeric value
151
+ when /(\d\d):(\d\d):\d\d/
152
+ select_time "#{Regexp.last_match(1)}#{Regexp.last_match(2)}"
153
+ else
154
+ select_default
155
+ end
156
+ end
147
157
  # Finally, try to use 'default' if we're still blank
148
158
  @selected_filename ||= select_default
149
159
  end
@@ -19,15 +19,13 @@
19
19
  # g.write('sidebar.png')
20
20
  #
21
21
  class Gruff::SideBar < Gruff::Base
22
- using String::GruffCommify
23
-
24
22
  # Spacing factor applied between bars.
25
23
  attr_writer :bar_spacing
26
24
 
27
25
  # Spacing factor applied between a group of bars belonging to the same label.
28
26
  attr_writer :group_spacing
29
27
 
30
- # Set the number output format for labels using sprintf.
28
+ # Set the number output format string or lambda.
31
29
  # Default is +"%.2f"+.
32
30
  attr_writer :label_formatting
33
31
 
@@ -38,27 +36,24 @@ class Gruff::SideBar < Gruff::Base
38
36
  # Prevent drawing of column labels left of a side bar graph. Default is +false+.
39
37
  attr_writer :hide_labels
40
38
 
41
- def initialize_ivars
39
+ # With Side Bars use the data label for the marker value to the left of the bar.
40
+ # @deprecated
41
+ def use_data_label=(_value)
42
+ warn '#use_data_label is deprecated. It is no longer effective.'
43
+ end
44
+
45
+ private
46
+
47
+ def initialize_attributes
42
48
  super
43
49
  @bar_spacing = 0.9
44
50
  @group_spacing = 10
45
51
  @label_formatting = nil
46
52
  @show_labels_for_bar_values = false
47
53
  @hide_labels = false
48
- end
49
- private :initialize_ivars
50
-
51
- def draw
52
54
  @has_left_labels = true
53
- super
54
-
55
- return unless data_given?
56
-
57
- draw_bars
58
55
  end
59
56
 
60
- protected
61
-
62
57
  def hide_labels?
63
58
  @hide_labels
64
59
  end
@@ -71,55 +66,44 @@ protected
71
66
  @hide_line_markers
72
67
  end
73
68
 
74
- private
69
+ # Value to avoid completely overwriting the coordinate axis
70
+ AXIS_MARGIN = 0.5
75
71
 
76
- def draw_bars
72
+ def draw_graph
77
73
  # Setup spacing.
78
74
  #
79
75
  bars_width = (@graph_height - calculate_spacing) / column_count.to_f
80
76
  bar_width = bars_width / store.length
81
- height = Array.new(column_count, 0)
82
- length = Array.new(column_count, @graph_left)
83
77
  padding = (bar_width * (1 - @bar_spacing)) / 2
84
78
 
85
- # if we're a side stacked bar then we don't need to draw ourself at all
86
- # because sometimes (due to different heights/min/max) you can actually
87
- # see both graphs and it looks like crap
88
- return if is_a?(Gruff::SideStackedBar)
79
+ # Setup the BarConversion Object
80
+ conversion = Gruff::BarConversion.new(
81
+ top: @graph_right, bottom: @graph_left,
82
+ minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
83
+ )
89
84
 
90
85
  store.norm_data.each_with_index do |data_row, row_index|
91
86
  data_row.points.each_with_index do |data_point, point_index|
92
87
  group_spacing = @group_spacing * @scale * point_index
93
88
 
94
- # Using the original calculations from the stacked bar chart
95
- # to get the difference between
96
- # part of the bart chart we wish to stack.
97
- temp1 = @graph_left + (@graph_width - data_point * @graph_width - height[point_index])
98
- temp2 = @graph_left + @graph_width - height[point_index]
99
- difference = temp2 - temp1
100
-
101
- left_x = length[point_index] - 1
102
89
  left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
103
- right_x = left_x + difference
104
90
  right_y = left_y + bar_width * @bar_spacing
105
91
 
106
- height[point_index] += (data_point * @graph_width)
92
+ left_x, right_x = conversion.get_top_bottom_scaled(data_point).sort
107
93
 
108
- rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
109
- rect_renderer.render(left_x, left_y, right_x, right_y)
94
+ rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
95
+ rect_renderer.render(left_x + AXIS_MARGIN, left_y, right_x + AXIS_MARGIN, right_y)
110
96
 
111
97
  # Calculate center based on bar_width and current row
98
+ label_center = left_y + bars_width / 2
112
99
 
113
- if @use_data_label
114
- label_center = left_y + bar_width / 2
115
- draw_label(label_center, row_index, store.norm_data[row_index].label)
116
- else
117
- label_center = left_y + bars_width / 2
118
- draw_label(label_center, point_index)
119
- end
100
+ # Subtract half a bar width to center left if requested
101
+ draw_label(label_center, point_index)
120
102
  if @show_labels_for_bar_values
121
- val = (@label_formatting || '%.2f') % store.data[row_index].points[point_index]
122
- draw_value_label(right_x + 40, right_y - bar_width / 2, val.commify, true)
103
+ bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
104
+ bar_value_label.prepare_rendering(@label_formatting, bar_width) do |x, y, text|
105
+ draw_value_label(x, y, text)
106
+ end
123
107
  end
124
108
  end
125
109
  end
@@ -139,14 +123,14 @@ private
139
123
  line_diff = (@graph_right - @graph_left) / number_of_lines
140
124
  x = @graph_right - (line_diff * index) - 1
141
125
 
142
- line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
126
+ line_renderer = Gruff::Renderer::Line.new(renderer, color: @marker_color, shadow_color: @marker_shadow_color)
143
127
  line_renderer.render(x, @graph_bottom, x, @graph_top)
144
128
 
145
- diff = index - number_of_lines
146
- marker_label = diff.abs * increment + minimum_value
147
-
148
129
  unless @hide_line_numbers
149
- text_renderer = Gruff::Renderer::Text.new(marker_label, font: @font, size: @marker_font_size, color: @font_color)
130
+ diff = index - number_of_lines
131
+ marker_label = BigDecimal(diff.abs.to_s) * BigDecimal(increment.to_s) + BigDecimal(minimum_value.to_s)
132
+ label = x_axis_label(marker_label, @increment)
133
+ text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font)
150
134
  text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + LABEL_MARGIN, Magick::CenterGravity)
151
135
  end
152
136
  end
@@ -155,12 +139,9 @@ private
155
139
  ##
156
140
  # Draw on the Y axis instead of the X
157
141
 
158
- def draw_label(y_offset, index, label = nil)
142
+ def draw_label(y_offset, index)
159
143
  draw_unique_label(index) do
160
- lbl = @use_data_label ? label : @labels[index]
161
-
162
- text_renderer = Gruff::Renderer::Text.new(lbl, font: @font, size: @marker_font_size, color: @font_color)
163
- text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, Magick::EastGravity)
144
+ draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
164
145
  end
165
146
  end
166
147
 
@@ -21,7 +21,6 @@
21
21
  #
22
22
  class Gruff::SideStackedBar < Gruff::SideBar
23
23
  include StackedMixin
24
- include BarValueLabelMixin
25
24
 
26
25
  # Spacing factor applied between bars.
27
26
  attr_writer :bar_spacing
@@ -29,7 +28,7 @@ class Gruff::SideStackedBar < Gruff::SideBar
29
28
  # Number of pixels between bar segments.
30
29
  attr_writer :segment_spacing
31
30
 
32
- # Set the number output format for labels using sprintf.
31
+ # Set the number output format string or lambda.
33
32
  # Default is +"%.2f"+.
34
33
  attr_writer :label_formatting
35
34
 
@@ -40,24 +39,23 @@ class Gruff::SideStackedBar < Gruff::SideBar
40
39
  # Prevent drawing of column labels left of a side stacked bar graph. Default is +false+.
41
40
  attr_writer :hide_labels
42
41
 
43
- def initialize_ivars
42
+ private
43
+
44
+ def initialize_attributes
44
45
  super
45
46
  @bar_spacing = 0.9
46
47
  @segment_spacing = 2.0
47
48
  @label_formatting = nil
48
49
  @show_labels_for_bar_values = false
49
50
  @hide_labels = false
51
+ @has_left_labels = true
50
52
  end
51
- private :initialize_ivars
52
53
 
53
- def draw
54
- @has_left_labels = true
54
+ def setup_data
55
55
  calculate_maximum_by_stack
56
56
  super
57
57
  end
58
58
 
59
- protected
60
-
61
59
  def hide_labels?
62
60
  @hide_labels
63
61
  end
@@ -70,9 +68,7 @@ protected
70
68
  @hide_line_markers
71
69
  end
72
70
 
73
- private
74
-
75
- def draw_bars
71
+ def draw_graph
76
72
  # Setup spacing.
77
73
  #
78
74
  # Columns sit stacked.
@@ -80,7 +76,7 @@ private
80
76
  height = Array.new(column_count, 0)
81
77
  length = Array.new(column_count, @graph_left)
82
78
  padding = (bar_width * (1 - @bar_spacing)) / 2
83
- bar_value_label = BarValueLabel.new(column_count, bar_width)
79
+ stack_bar_value_label = Gruff::BarValueLabel::StackedBar.new
84
80
 
85
81
  store.norm_data.each_with_index do |data_row, row_index|
86
82
  data_row.points.each_with_index do |data_point, point_index|
@@ -91,6 +87,7 @@ private
91
87
  height[point_index]) + 1
92
88
  temp2 = @graph_left + @graph_width - height[point_index] - 1
93
89
  difference = temp2 - temp1
90
+ difference = 0 if row_index == 0 && difference < 0
94
91
 
95
92
  left_x = length[point_index]
96
93
  left_y = @graph_top + (bar_width * point_index) + padding
@@ -99,14 +96,14 @@ private
99
96
  length[point_index] += difference
100
97
  height[point_index] += (data_point * @graph_width - 2)
101
98
 
102
- bar_value_label.coordinates[point_index] = [left_x, left_y, right_x, right_y]
103
- bar_value_label.values[point_index] += store.data[row_index].points[point_index]
99
+ bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
100
+ stack_bar_value_label.add(bar_value_label, point_index)
104
101
 
105
102
  # if a data point is 0 it can result in weird really thing lines
106
103
  # that shouldn't even be there being drawn on top of the existing
107
104
  # bar - this is bad
108
105
  if data_point != 0
109
- rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
106
+ rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
110
107
  rect_renderer.render(left_x, left_y, right_x, right_y)
111
108
  # Calculate center based on bar_width and current row
112
109
  end
@@ -118,8 +115,8 @@ private
118
115
  end
119
116
 
120
117
  if @show_labels_for_bar_values
121
- bar_value_label.prepare_sidebar_rendering(@label_formatting) do |x, y, text|
122
- draw_value_label(x, y, text, true)
118
+ stack_bar_value_label.prepare_rendering(@label_formatting, bar_width) do |x, y, text|
119
+ draw_value_label(x, y, text)
123
120
  end
124
121
  end
125
122
  end