gruff 0.14.0-java → 0.17.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +28 -12
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +20 -24
  5. data/CHANGELOG.md +52 -0
  6. data/README.md +10 -3
  7. data/gruff.gemspec +9 -10
  8. data/lib/gruff/accumulator_bar.rb +1 -1
  9. data/lib/gruff/area.rb +6 -4
  10. data/lib/gruff/bar.rb +53 -31
  11. data/lib/gruff/base.rb +292 -184
  12. data/lib/gruff/bezier.rb +4 -2
  13. data/lib/gruff/box_plot.rb +180 -0
  14. data/lib/gruff/bullet.rb +6 -6
  15. data/lib/gruff/candlestick.rb +120 -0
  16. data/lib/gruff/dot.rb +11 -12
  17. data/lib/gruff/font.rb +3 -0
  18. data/lib/gruff/helper/bar_conversion.rb +6 -10
  19. data/lib/gruff/helper/bar_mixin.rb +25 -0
  20. data/lib/gruff/helper/bar_value_label.rb +24 -40
  21. data/lib/gruff/helper/stacked_mixin.rb +19 -1
  22. data/lib/gruff/histogram.rb +9 -5
  23. data/lib/gruff/line.rb +49 -48
  24. data/lib/gruff/mini/legend.rb +11 -11
  25. data/lib/gruff/net.rb +23 -18
  26. data/lib/gruff/patch/rmagick.rb +0 -1
  27. data/lib/gruff/patch/string.rb +1 -0
  28. data/lib/gruff/pie.rb +26 -12
  29. data/lib/gruff/renderer/dash_line.rb +3 -2
  30. data/lib/gruff/renderer/dot.rb +28 -15
  31. data/lib/gruff/renderer/line.rb +1 -3
  32. data/lib/gruff/renderer/rectangle.rb +6 -2
  33. data/lib/gruff/renderer/renderer.rb +4 -8
  34. data/lib/gruff/renderer/text.rb +7 -1
  35. data/lib/gruff/scatter.rb +64 -56
  36. data/lib/gruff/side_bar.rb +64 -30
  37. data/lib/gruff/side_stacked_bar.rb +43 -54
  38. data/lib/gruff/spider.rb +52 -18
  39. data/lib/gruff/stacked_area.rb +18 -8
  40. data/lib/gruff/stacked_bar.rb +59 -29
  41. data/lib/gruff/store/xy_data.rb +2 -0
  42. data/lib/gruff/version.rb +1 -1
  43. data/lib/gruff.rb +67 -58
  44. metadata +17 -16
  45. data/.rubocop_todo.yml +0 -116
  46. data/lib/gruff/scene.rb +0 -200
  47. data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/line.rb CHANGED
@@ -25,7 +25,7 @@ class Gruff::Line < Gruff::Base
25
25
  attr_writer :line_width
26
26
  attr_writer :dot_radius
27
27
 
28
- # default is +'circle'+, other options include square.
28
+ # default is +'circle'+, other options include +square+ and +diamond+.
29
29
  attr_writer :dot_style
30
30
 
31
31
  # Hide parts of the graph to fit more data points, or for a different appearance.
@@ -40,6 +40,23 @@ class Gruff::Line < Gruff::Base
40
40
  # The number of vertical lines shown.
41
41
  attr_writer :marker_x_count
42
42
 
43
+ # Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
44
+ #
45
+ # g = Gruff::Line.new(400) # 400px wide with lines
46
+ # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
47
+ # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
48
+ #
49
+ # The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
50
+ def initialize(*args)
51
+ raise ArgumentError, 'Wrong number of arguments' if args.length > 2
52
+
53
+ if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
54
+ super()
55
+ else
56
+ super args.shift
57
+ end
58
+ end
59
+
43
60
  # Get the value if somebody has defined it.
44
61
  def baseline_value
45
62
  if @reference_lines.key?(:baseline)
@@ -64,23 +81,6 @@ class Gruff::Line < Gruff::Base
64
81
  @reference_lines[:baseline][:color] = new_value
65
82
  end
66
83
 
67
- # Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
68
- #
69
- # g = Gruff::Line.new(400) # 400px wide with lines
70
- # g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
71
- # g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
72
- #
73
- # The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
74
- def initialize(*args)
75
- raise ArgumentError, 'Wrong number of arguments' if args.length > 2
76
-
77
- if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
78
- super()
79
- else
80
- super args.shift
81
- end
82
- end
83
-
84
84
  # This method allows one to plot a dataset with both X and Y data.
85
85
  #
86
86
  # @overload dataxy(name, x_data_points = [], y_data_points = [], color = nil)
@@ -118,12 +118,14 @@ class Gruff::Line < Gruff::Base
118
118
  def dataxy(name, x_data_points = [], y_data_points = [], color = nil)
119
119
  # make sure it's an array
120
120
  x_data_points = Array(x_data_points)
121
- y_data_points = Array(y_data_points)
122
121
 
123
122
  raise ArgumentError, 'x_data_points is nil!' if x_data_points.empty?
124
123
 
125
124
  if x_data_points.all? { |p| p.is_a?(Array) && p.size == 2 }
125
+ color = y_data_points if y_data_points.is_a?(String)
126
126
  x_data_points, y_data_points = x_data_points.transpose
127
+ else
128
+ y_data_points = Array(y_data_points)
127
129
  end
128
130
 
129
131
  raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
@@ -163,7 +165,7 @@ private
163
165
  end
164
166
 
165
167
  def draw_horizontal_reference_line(reference_line)
166
- level = @graph_top + (@graph_height - reference_line[:norm_value] * @graph_height)
168
+ level = @graph_top + (@graph_height - (reference_line[:norm_value] * @graph_height))
167
169
  draw_reference_line(reference_line, @graph_left, @graph_left + @graph_width, level, level)
168
170
  end
169
171
 
@@ -174,7 +176,7 @@ private
174
176
 
175
177
  def draw_graph
176
178
  # Check to see if more than one datapoint was given. NaN can result otherwise.
177
- @x_increment = (column_count > 1) ? (@graph_width / (column_count - 1).to_f) : @graph_width
179
+ @x_increment = column_count > 1 ? @graph_width / (column_count - 1) : @graph_width
178
180
 
179
181
  @reference_lines.each_value do |curr_reference_line|
180
182
  draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
@@ -187,22 +189,22 @@ private
187
189
  one_point = contains_one_point_only?(data_row)
188
190
 
189
191
  data_row.coordinates.each_with_index do |(x_data, y_data), index|
190
- if x_data.nil?
191
- # use the old method: equally spaced points along the x-axis
192
- new_x = @graph_left + (@x_increment * index)
193
- draw_label(new_x, index)
194
- else
195
- new_x = get_x_coord(x_data, @graph_width, @graph_left)
196
- @labels.each do |label_pos, _|
197
- draw_label(@graph_left + ((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value), label_pos)
192
+ new_x = begin
193
+ if x_data.nil?
194
+ # use the old method: equally spaced points along the x-axis
195
+ @graph_left + (@x_increment * index)
196
+ else
197
+ get_x_coord(x_data, @graph_width, @graph_left)
198
198
  end
199
199
  end
200
+ draw_label_for_x_data(x_data, new_x, index)
201
+
200
202
  unless y_data # we can't draw a line for a null data point, we can still label the axis though
201
203
  prev_x = prev_y = nil
202
204
  next
203
205
  end
204
206
 
205
- new_y = @graph_top + (@graph_height - y_data * @graph_height)
207
+ new_y = @graph_top + (@graph_height - (y_data * @graph_height))
206
208
 
207
209
  # Reset each time to avoid thin-line errors
208
210
  stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
@@ -225,12 +227,12 @@ private
225
227
 
226
228
  def setup_data
227
229
  # Update the global min/max values for the x data
228
- @maximum_x_value ||= store.max_x
229
- @minimum_x_value ||= store.min_x
230
+ @maximum_x_value = (@maximum_x_value || store.max_x).to_f
231
+ @minimum_x_value = (@minimum_x_value || store.min_x).to_f
230
232
 
231
233
  # Deal with horizontal reference line values that exceed the existing minimum & maximum values.
232
- possible_maximums = [maximum_value.to_f]
233
- possible_minimums = [minimum_value.to_f]
234
+ possible_maximums = [maximum_value]
235
+ possible_minimums = [minimum_value]
234
236
 
235
237
  @reference_lines.each_value do |curr_reference_line|
236
238
  if curr_reference_line.key?(:value)
@@ -253,41 +255,40 @@ private
253
255
  def normalize
254
256
  return unless data_given?
255
257
 
256
- spread_x = @maximum_x_value.to_f - @minimum_x_value.to_f
258
+ spread_x = @maximum_x_value - @minimum_x_value
257
259
  store.normalize(minimum_x: @minimum_x_value, spread_x: spread_x, minimum_y: minimum_value, spread_y: @spread)
258
260
 
259
261
  @reference_lines.each_value do |curr_reference_line|
260
262
  # We only care about horizontal markers ... for normalization.
261
263
  # Vertical markers won't have a :value, they will have an :index
262
264
 
263
- curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread.to_f) if curr_reference_line.key?(:value)
265
+ curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread) if curr_reference_line.key?(:value)
264
266
  end
265
267
  end
266
268
 
267
- def sort_norm_data
268
- super unless store.data.any?(&:x_points)
269
- end
270
-
271
269
  def draw_line_markers
272
270
  # do all of the stuff for the horizontal lines on the y-axis
273
271
  super
274
272
  return if @hide_line_markers
273
+ return unless @show_vertical_markers
275
274
 
276
275
  (0..@marker_x_count).each do |index|
277
- if @show_vertical_markers
278
- x = @graph_left + @graph_width - index * @graph_width / @marker_x_count
276
+ draw_marker_vertical_line(@graph_left + @graph_width - (index * @graph_width / @marker_x_count))
277
+ end
278
+ end
279
279
 
280
- Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
281
- # If the user specified a marker shadow color, draw a shadow just below it
282
- if @marker_shadow_color
283
- Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x + 1, @graph_bottom, x + 1, @graph_top)
284
- end
280
+ def draw_label_for_x_data(x_data, new_x, index)
281
+ if x_data.nil?
282
+ draw_label(new_x, index)
283
+ else
284
+ @labels.each do |label_pos, _|
285
+ draw_label(@graph_left + (((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value)), label_pos)
285
286
  end
286
287
  end
287
288
  end
288
289
 
289
290
  def get_x_coord(x_data_point, width, offset)
290
- x_data_point * width + offset
291
+ (x_data_point * width) + offset
291
292
  end
292
293
 
293
294
  def contains_one_point_only?(data_row)
@@ -21,7 +21,7 @@ module Gruff
21
21
 
22
22
  @legend_labels = store.data.map(&:label)
23
23
 
24
- legend_height = scale_fontsize(store.length * calculate_line_height + @top_margin + @bottom_margin)
24
+ legend_height = scale((store.length * calculate_line_height) + @top_margin + @bottom_margin)
25
25
 
26
26
  @original_rows = @raw_rows
27
27
  @original_columns = @raw_columns
@@ -32,7 +32,7 @@ module Gruff
32
32
  @columns += calculate_legend_width + @left_margin
33
33
  else
34
34
  font = @legend_font.dup
35
- font.size = scale_fontsize(font.size)
35
+ font.size = scale(font.size)
36
36
  @rows += store.length * calculate_caps_height(font) * 1.7
37
37
  end
38
38
 
@@ -45,7 +45,7 @@ module Gruff
45
45
 
46
46
  def calculate_legend_width
47
47
  width = @legend_labels.map { |label| calculate_width(@legend_font, label) }.max
48
- scale_fontsize(width + 40 * 1.7)
48
+ scale(width + (40 * 1.7))
49
49
  end
50
50
 
51
51
  ##
@@ -69,17 +69,17 @@ module Gruff
69
69
 
70
70
  @legend_labels.each_with_index do |legend_label, index|
71
71
  # Draw label
72
- label = truncate_legend_label(legend_label)
73
- text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
74
72
  x_offset = current_x_offset + (legend_square_width * 1.7)
73
+ label = truncate_legend_label(legend_label, x_offset)
74
+ text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
75
75
  text_renderer.add_to_render_queue(@raw_columns, 1.0, x_offset, current_y_offset, Magick::WestGravity)
76
76
 
77
77
  # Now draw box with color of this dataset
78
78
  rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: store.data[index].color)
79
79
  rect_renderer.render(current_x_offset,
80
- current_y_offset - legend_square_width / 2.0,
80
+ current_y_offset - (legend_square_width / 2.0),
81
81
  current_x_offset + legend_square_width,
82
- current_y_offset + legend_square_width / 2.0)
82
+ current_y_offset + (legend_square_width / 2.0))
83
83
 
84
84
  current_y_offset += calculate_line_height
85
85
  end
@@ -90,13 +90,13 @@ module Gruff
90
90
  #
91
91
  # Department of Hu...
92
92
 
93
- def truncate_legend_label(label)
93
+ def truncate_legend_label(label, x_offset)
94
94
  truncated_label = label.to_s
95
95
 
96
96
  font = @legend_font.dup
97
- font.size = scale_fontsize(font.size)
98
- max_width = @columns - @legend_left_margin - @right_margin
99
- while calculate_width(font, truncated_label) > max_width && truncated_label.length > 1
97
+ font.size = scale(font.size)
98
+ max_width = @columns - scale(x_offset) - @right_margin
99
+ while calculate_width(font, "#{truncated_label}...") > max_width && truncated_label.length > 1
100
100
  truncated_label = truncated_label[0..truncated_label.length - 2]
101
101
  end
102
102
  truncated_label + (truncated_label.length < label.to_s.length ? '...' : '')
data/lib/gruff/net.rb CHANGED
@@ -43,6 +43,21 @@ private
43
43
  @marker_font.bold = true
44
44
  end
45
45
 
46
+ def setup_drawing
47
+ @center_labels_over_point = false
48
+ super
49
+ end
50
+
51
+ def setup_graph_measurements
52
+ super
53
+
54
+ @radius = @graph_height / 2.0
55
+ @circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
56
+ @stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4.0), 5.0)
57
+ @center_x = @graph_left + (@graph_width / 2.0)
58
+ @center_y = @graph_top + (@graph_height / 2.0) + 10
59
+ end
60
+
46
61
  def draw_graph
47
62
  store.norm_data.each do |data_row|
48
63
  data_row.points.each_with_index do |data_point, index|
@@ -50,15 +65,15 @@ private
50
65
 
51
66
  rad_pos = index * Math::PI * 2 / column_count
52
67
  point_distance = data_point * @radius
53
- start_x = @center_x + Math.sin(rad_pos) * point_distance
54
- start_y = @center_y - Math.cos(rad_pos) * point_distance
68
+ start_x = @center_x + (Math.sin(rad_pos) * point_distance)
69
+ start_y = @center_y - (Math.cos(rad_pos) * point_distance)
55
70
 
56
71
  next_index = index + 1 < data_row.points.length ? index + 1 : 0
57
72
 
58
73
  next_rad_pos = next_index * Math::PI * 2 / column_count
59
74
  next_point_distance = data_row.points[next_index] * @radius
60
- end_x = @center_x + Math.sin(next_rad_pos) * next_point_distance
61
- end_y = @center_y - Math.cos(next_rad_pos) * next_point_distance
75
+ end_x = @center_x + (Math.sin(next_rad_pos) * next_point_distance)
76
+ end_y = @center_y - (Math.cos(next_rad_pos) * next_point_distance)
62
77
 
63
78
  Gruff::Renderer::Line.new(renderer, color: data_row.color, width: @stroke_width).render(start_x, start_y, end_x, end_y)
64
79
 
@@ -70,16 +85,6 @@ private
70
85
  end
71
86
  end
72
87
 
73
- def setup_drawing
74
- super
75
-
76
- @radius = @graph_height / 2.0
77
- @circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
78
- @stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4), 5.0)
79
- @center_x = @graph_left + (@graph_width / 2.0)
80
- @center_y = @graph_top + (@graph_height / 2.0) + 10
81
- end
82
-
83
88
  # the lines connecting in the center, with the first line vertical
84
89
  def draw_line_markers
85
90
  return if @hide_line_markers
@@ -89,7 +94,7 @@ private
89
94
  rad_pos = index * Math::PI * 2 / column_count
90
95
 
91
96
  Gruff::Renderer::Line.new(renderer, color: @marker_color)
92
- .render(@center_x, @center_y, @center_x + Math.sin(rad_pos) * @radius, @center_y - Math.cos(rad_pos) * @radius)
97
+ .render(@center_x, @center_y, @center_x + (Math.sin(rad_pos) * @radius), @center_y - (Math.cos(rad_pos) * @radius))
93
98
 
94
99
  marker_label = @labels[index] ? @labels[index].to_s : '000'
95
100
  draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius + @circle_radius, marker_label)
@@ -99,9 +104,9 @@ private
99
104
  def draw_label(center_x, center_y, angle, radius, amount)
100
105
  x_offset = center_x # + 15 # The label points need to be tweaked slightly
101
106
  y_offset = center_y # + 0 # This one doesn't though
102
- x = x_offset + (radius + LABEL_MARGIN) * Math.sin(deg2rad(angle))
103
- y = y_offset - (radius + LABEL_MARGIN) * Math.cos(deg2rad(angle))
107
+ x = x_offset + ((radius + LABEL_MARGIN) * Math.sin(deg2rad(angle)))
108
+ y = y_offset - ((radius + LABEL_MARGIN) * Math.cos(deg2rad(angle)))
104
109
 
105
- draw_label_at(1.0, 1.0, x, y, amount, Magick::CenterGravity)
110
+ draw_label_at(1.0, 1.0, x, y, amount, gravity: Magick::CenterGravity)
106
111
  end
107
112
  end
@@ -23,7 +23,6 @@ module Magick
23
23
  def fill=(fill)
24
24
  fill = { white: '#FFFFFF' }[fill.to_sym] || fill
25
25
  @draw.fill = Magick4J.ColorDatabase.query_default(fill)
26
- self
27
26
  end
28
27
  end
29
28
  end
@@ -3,6 +3,7 @@
3
3
  # @private
4
4
  module String::GruffCommify
5
5
  THOUSAND_SEPARATOR = ','
6
+ private_constant :THOUSAND_SEPARATOR
6
7
 
7
8
  refine String do
8
9
  # Taken from http://codesnippets.joyent.com/posts/show/330
data/lib/gruff/pie.rb CHANGED
@@ -9,14 +9,14 @@
9
9
  # g.data 'Hamburgers', 50
10
10
  # g.write("pie_keynote.png")
11
11
  #
12
- # To control where the pie chart starts creating slices, use {#zero_degree=}.
12
+ # To control where the pie chart starts creating slices, use {#start_degree=}.
13
13
  #
14
14
  class Gruff::Pie < Gruff::Base
15
- DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.15
15
+ DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.1
16
16
 
17
17
  # Can be used to make the pie start cutting slices at the top (-90.0)
18
- # or at another angle. Default is +0.0+, which starts at 3 o'clock.
19
- attr_writer :zero_degree
18
+ # or at another angle. Default is +-90.0+, which starts at 3 o'clock.
19
+ attr_writer :start_degree
20
20
 
21
21
  # Set the number output format lambda.
22
22
  attr_writer :label_formatting
@@ -26,25 +26,34 @@ class Gruff::Pie < Gruff::Base
26
26
  attr_writer :hide_labels_less_than
27
27
 
28
28
  # Affect the distance between the percentages and the pie chart.
29
- # Defaults to +0.15+.
29
+ # Defaults to +0.1+.
30
30
  attr_writer :text_offset_percentage
31
31
 
32
32
  ## Use values instead of percentages.
33
33
  attr_writer :show_values_as_labels
34
34
 
35
- private
35
+ # Set to +true+ if you want the data sets sorted with largest avg values drawn
36
+ # first. Default is +true+.
37
+ attr_writer :sort
36
38
 
37
- def initialize_store
38
- @store = Gruff::Store.new(Gruff::Store::CustomData)
39
+ # Can be used to make the pie start cutting slices at the top (-90.0)
40
+ # or at another angle. Default is +-90.0+, which starts at 3 o'clock.
41
+ # @deprecated Please use +start_degree+ attribute instead.
42
+ def zero_degree=(value)
43
+ warn '#zero_degree= is deprecated. Please use `start_degree` attribute instead'
44
+ @start_degree = value
39
45
  end
40
46
 
47
+ private
48
+
41
49
  def initialize_attributes
42
50
  super
43
- @zero_degree = 0.0
51
+ @start_degree = -90.0
44
52
  @hide_labels_less_than = 0.0
45
53
  @text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
46
54
  @show_values_as_labels = false
47
55
  @marker_font.bold = true
56
+ @sort = true
48
57
 
49
58
  @hide_line_markers = true
50
59
  @hide_line_markers.freeze
@@ -52,6 +61,11 @@ private
52
61
  @label_formatting = ->(value, percentage) { @show_values_as_labels ? value.to_s : "#{percentage}%" }
53
62
  end
54
63
 
64
+ def setup_drawing
65
+ @center_labels_over_point = false
66
+ super
67
+ end
68
+
55
69
  def draw_graph
56
70
  slices.each do |slice|
57
71
  if slice.value > 0
@@ -83,7 +97,7 @@ private
83
97
  # Spatial Value-Related Methods
84
98
 
85
99
  def chart_degrees
86
- @chart_degrees ||= @zero_degree
100
+ @chart_degrees ||= @start_degree
87
101
  end
88
102
 
89
103
  attr_reader :graph_height
@@ -127,12 +141,12 @@ private
127
141
  if slice.percentage >= @hide_labels_less_than
128
142
  x, y = label_coordinates_for slice
129
143
  label = @label_formatting.call(slice.value, slice.percentage)
130
- draw_label_at(1.0, 1.0, x, y, label, Magick::CenterGravity)
144
+ draw_label_at(1.0, 1.0, x, y, label, gravity: Magick::CenterGravity)
131
145
  end
132
146
  end
133
147
 
134
148
  def label_coordinates_for(slice)
135
- angle = chart_degrees + slice.degrees / 2
149
+ angle = chart_degrees + (slice.degrees / 2.0)
136
150
 
137
151
  [x_label_coordinate(angle), y_label_coordinate(angle)]
138
152
  end
@@ -3,17 +3,18 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::DashLine
6
- def initialize(renderer, color:, width:)
6
+ def initialize(renderer, color:, width:, dasharray: [10, 20])
7
7
  @renderer = renderer
8
8
  @color = color
9
9
  @width = width
10
+ @dasharray = dasharray
10
11
  end
11
12
 
12
13
  def render(start_x, start_y, end_x, end_y)
13
14
  @renderer.draw.push
14
15
  @renderer.draw.stroke_color(@color)
15
16
  @renderer.draw.fill_opacity(0.0)
16
- @renderer.draw.stroke_dasharray(10, 20)
17
+ @renderer.draw.stroke_dasharray(*@dasharray)
17
18
  @renderer.draw.stroke_width(@width)
18
19
  @renderer.draw.line(start_x, start_y, end_x, end_y)
19
20
  @renderer.draw.pop
@@ -3,37 +3,50 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Dot
6
- def initialize(renderer, style, color:, width: 1.0)
6
+ def initialize(renderer, style, color:, width: 1.0, opacity: 1.0)
7
7
  @renderer = renderer
8
8
  @style = style
9
9
  @color = color
10
10
  @width = width
11
+ @opacity = opacity
11
12
  end
12
13
 
13
- def render(new_x, new_y, circle_radius)
14
- # @renderer.draw.push # TODO
14
+ def render(new_x, new_y, radius)
15
+ @renderer.draw.push
15
16
  @renderer.draw.stroke_width(@width)
16
17
  @renderer.draw.stroke(@color)
17
18
  @renderer.draw.fill(@color)
18
- if @style.to_s == 'square'
19
- square(new_x, new_y, circle_radius)
19
+ @renderer.draw.fill_opacity(@opacity)
20
+ case @style.to_sym
21
+ when :square
22
+ square(new_x, new_y, radius)
23
+ when :diamond
24
+ diamond(new_x, new_y, radius)
20
25
  else
21
- circle(new_x, new_y, circle_radius)
26
+ circle(new_x, new_y, radius)
22
27
  end
23
- # @renderer.draw.pop # TODO
28
+ @renderer.draw.pop
24
29
  end
25
30
 
26
- def circle(new_x, new_y, circle_radius)
27
- @renderer.draw.circle(new_x, new_y, new_x - circle_radius, new_y)
31
+ def circle(new_x, new_y, radius)
32
+ @renderer.draw.circle(new_x, new_y, new_x - radius, new_y)
28
33
  end
29
34
 
30
- def square(new_x, new_y, circle_radius)
31
- offset = (circle_radius * 0.8).to_i
32
- corner1 = new_x - offset
33
- corner2 = new_y - offset
34
- corner3 = new_x + offset
35
- corner4 = new_y + offset
35
+ def square(new_x, new_y, radius)
36
+ corner1 = new_x - radius
37
+ corner2 = new_y - radius
38
+ corner3 = new_x + radius
39
+ corner4 = new_y + radius
36
40
  @renderer.draw.rectangle(corner1, corner2, corner3, corner4)
37
41
  end
42
+
43
+ def diamond(new_x, new_y, radius)
44
+ polygon = []
45
+ polygon += [new_x - radius, new_y]
46
+ polygon += [new_x, new_y + radius]
47
+ polygon += [new_x + radius, new_y]
48
+ polygon += [new_x, new_y - radius]
49
+ @renderer.draw.polygon(*polygon)
50
+ end
38
51
  end
39
52
  end
@@ -5,16 +5,14 @@ module Gruff
5
5
  class Renderer::Line
6
6
  EPSILON = 0.001
7
7
 
8
- def initialize(renderer, color:, width: nil, shadow_color: nil)
8
+ def initialize(renderer, color:, width: nil)
9
9
  @renderer = renderer
10
10
  @color = color
11
11
  @width = width
12
- @shadow_color = shadow_color
13
12
  end
14
13
 
15
14
  def render(start_x, start_y, end_x, end_y)
16
15
  render_line(start_x, start_y, end_x, end_y, @color)
17
- render_line(start_x, start_y + 1, end_x, end_y + 1, @shadow_color) if @shadow_color
18
16
  end
19
17
 
20
18
  private
@@ -3,14 +3,18 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Rectangle
6
- def initialize(renderer, color: nil)
6
+ def initialize(renderer, color: nil, width: 1.0, opacity: 1.0)
7
7
  @renderer = renderer
8
8
  @color = color
9
+ @width = width
10
+ @opacity = opacity
9
11
  end
10
12
 
11
13
  def render(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
12
14
  @renderer.draw.push
13
- @renderer.draw.stroke('transparent')
15
+ @renderer.draw.stroke_width(@width)
16
+ @renderer.draw.stroke(@color) if @width > 1.0
17
+ @renderer.draw.fill_opacity(@opacity)
14
18
  @renderer.draw.fill(@color) if @color
15
19
  @renderer.draw.rectangle(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
16
20
  @renderer.draw.pop
@@ -23,10 +23,6 @@ module Gruff
23
23
  end
24
24
  end
25
25
 
26
- def background_image=(image)
27
- @image = image
28
- end
29
-
30
26
  def background(columns, rows, scale, theme_options)
31
27
  case theme_options[:background_colors]
32
28
  when Array
@@ -44,8 +40,8 @@ module Gruff
44
40
 
45
41
  # Make a new image at the current size with a solid +color+.
46
42
  def solid_background(columns, rows, color)
47
- Magick::Image.new(columns, rows) do
48
- self.background_color = color
43
+ Magick::Image.new(columns, rows) do |img|
44
+ img.background_color = color
49
45
  end
50
46
  end
51
47
 
@@ -97,8 +93,8 @@ module Gruff
97
93
 
98
94
  # Use with a theme to make a transparent background
99
95
  def render_transparent_background(columns, rows)
100
- Magick::Image.new(columns, rows) do
101
- self.background_color = 'transparent'
96
+ Magick::Image.new(columns, rows) do |img|
97
+ img.background_color = 'transparent'
102
98
  end
103
99
  end
104
100
  end
@@ -25,6 +25,7 @@ module Gruff
25
25
  end
26
26
 
27
27
  def render(width, height, x, y, gravity = Magick::NorthGravity)
28
+ @renderer.draw.push
28
29
  @renderer.draw.rotation = @rotation if @rotation
29
30
  @renderer.draw.fill = @font.color
30
31
  @renderer.draw.stroke = 'transparent'
@@ -37,9 +38,11 @@ module Gruff
37
38
  x, y,
38
39
  @text, @renderer.scale)
39
40
  @renderer.draw.rotation = -@rotation if @rotation
41
+ @renderer.draw.pop
40
42
  end
41
43
 
42
44
  def metrics
45
+ @renderer.draw.push
43
46
  @renderer.draw.font = @font.file_path
44
47
  @renderer.draw.font_weight = @font.weight
45
48
  @renderer.draw.pointsize = @font.size
@@ -50,7 +53,10 @@ module Gruff
50
53
  # So, in here, it just escape % in order to avoid SEGV.
51
54
  text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
52
55
 
53
- @renderer.draw.get_type_metrics(@renderer.image, text)
56
+ metrics = @renderer.draw.get_type_metrics(@renderer.image, text)
57
+ @renderer.draw.pop
58
+
59
+ metrics
54
60
  end
55
61
  end
56
62
  end