gruff 0.13.0-java → 0.14.0-java

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +66 -0
  3. data/.rubocop.yml +6 -10
  4. data/.rubocop_todo.yml +19 -85
  5. data/CHANGELOG.md +10 -0
  6. data/README.md +6 -7
  7. data/gruff.gemspec +2 -4
  8. data/lib/gruff.rb +1 -0
  9. data/lib/gruff/accumulator_bar.rb +3 -1
  10. data/lib/gruff/area.rb +5 -8
  11. data/lib/gruff/bar.rb +19 -23
  12. data/lib/gruff/base.rb +134 -96
  13. data/lib/gruff/bezier.rb +4 -6
  14. data/lib/gruff/bullet.rb +11 -10
  15. data/lib/gruff/dot.rb +10 -10
  16. data/lib/gruff/font.rb +39 -0
  17. data/lib/gruff/helper/stacked_mixin.rb +1 -2
  18. data/lib/gruff/histogram.rb +9 -7
  19. data/lib/gruff/line.rb +55 -46
  20. data/lib/gruff/mini/bar.rb +9 -6
  21. data/lib/gruff/mini/legend.rb +12 -8
  22. data/lib/gruff/mini/pie.rb +9 -6
  23. data/lib/gruff/mini/side_bar.rb +9 -6
  24. data/lib/gruff/net.rb +9 -15
  25. data/lib/gruff/patch/string.rb +1 -1
  26. data/lib/gruff/pie.rb +23 -65
  27. data/lib/gruff/renderer/bezier.rb +8 -9
  28. data/lib/gruff/renderer/circle.rb +8 -9
  29. data/lib/gruff/renderer/dash_line.rb +9 -10
  30. data/lib/gruff/renderer/dot.rb +13 -14
  31. data/lib/gruff/renderer/ellipse.rb +8 -9
  32. data/lib/gruff/renderer/line.rb +8 -9
  33. data/lib/gruff/renderer/polygon.rb +9 -10
  34. data/lib/gruff/renderer/polyline.rb +8 -9
  35. data/lib/gruff/renderer/rectangle.rb +7 -8
  36. data/lib/gruff/renderer/renderer.rb +21 -36
  37. data/lib/gruff/renderer/text.rb +21 -37
  38. data/lib/gruff/scatter.rb +41 -46
  39. data/lib/gruff/scene.rb +15 -13
  40. data/lib/gruff/side_bar.rb +14 -30
  41. data/lib/gruff/side_stacked_bar.rb +8 -11
  42. data/lib/gruff/spider.rb +11 -16
  43. data/lib/gruff/stacked_area.rb +10 -11
  44. data/lib/gruff/stacked_bar.rb +9 -9
  45. data/lib/gruff/store/store.rb +6 -10
  46. data/lib/gruff/themes.rb +6 -6
  47. data/lib/gruff/version.rb +1 -1
  48. data/rails_generators/gruff/templates/controller.rb +1 -1
  49. metadata +4 -21
  50. data/.travis.yml +0 -23
  51. data/assets/plastik/blue.png +0 -0
  52. data/assets/plastik/green.png +0 -0
  53. data/assets/plastik/red.png +0 -0
  54. data/lib/gruff/photo_bar.rb +0 -93
@@ -3,20 +3,19 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Ellipse
6
- def initialize(color:, width: 1.0)
6
+ def initialize(renderer, color:, width: 1.0)
7
+ @renderer = renderer
7
8
  @color = color
8
9
  @width = width
9
10
  end
10
11
 
11
12
  def render(origin_x, origin_y, width, height, arc_start, arc_end)
12
- draw = Renderer.instance.draw
13
-
14
- draw.push
15
- draw.stroke_width(@width)
16
- draw.stroke(@color)
17
- draw.fill('transparent')
18
- draw.ellipse(origin_x, origin_y, width, height, arc_start, arc_end)
19
- draw.pop
13
+ @renderer.draw.push
14
+ @renderer.draw.stroke_width(@width)
15
+ @renderer.draw.stroke(@color)
16
+ @renderer.draw.fill('transparent')
17
+ @renderer.draw.ellipse(origin_x, origin_y, width, height, arc_start, arc_end)
18
+ @renderer.draw.pop
20
19
  end
21
20
  end
22
21
  end
@@ -5,7 +5,8 @@ module Gruff
5
5
  class Renderer::Line
6
6
  EPSILON = 0.001
7
7
 
8
- def initialize(color:, width: nil, shadow_color: nil)
8
+ def initialize(renderer, color:, width: nil, shadow_color: nil)
9
+ @renderer = renderer
9
10
  @color = color
10
11
  @width = width
11
12
  @shadow_color = shadow_color
@@ -30,14 +31,12 @@ module Gruff
30
31
  end_y += EPSILON
31
32
  end
32
33
 
33
- draw = Renderer.instance.draw
34
-
35
- draw.push
36
- draw.stroke(color)
37
- draw.fill(color)
38
- draw.stroke_width(@width) if @width
39
- draw.line(start_x, start_y, end_x, end_y)
40
- draw.pop
34
+ @renderer.draw.push
35
+ @renderer.draw.stroke(color)
36
+ @renderer.draw.fill(color)
37
+ @renderer.draw.stroke_width(@width) if @width
38
+ @renderer.draw.line(start_x, start_y, end_x, end_y)
39
+ @renderer.draw.pop
41
40
  end
42
41
  end
43
42
  end
@@ -3,22 +3,21 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Polygon
6
- def initialize(color:, width: 1.0, opacity: 1.0)
6
+ def initialize(renderer, color:, width: 1.0, opacity: 1.0)
7
+ @renderer = renderer
7
8
  @color = color
8
9
  @width = width
9
10
  @opacity = opacity
10
11
  end
11
12
 
12
13
  def render(points)
13
- draw = Renderer.instance.draw
14
-
15
- draw.push
16
- draw.stroke_width(@width)
17
- draw.stroke(@color)
18
- draw.fill(@color)
19
- draw.fill_opacity(@opacity)
20
- draw.polygon(*points)
21
- draw.pop
14
+ @renderer.draw.push
15
+ @renderer.draw.stroke_width(@width)
16
+ @renderer.draw.stroke(@color)
17
+ @renderer.draw.fill(@color)
18
+ @renderer.draw.fill_opacity(@opacity)
19
+ @renderer.draw.polygon(*points)
20
+ @renderer.draw.pop
22
21
  end
23
22
  end
24
23
  end
@@ -3,20 +3,19 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Polyline
6
- def initialize(color:, width:)
6
+ def initialize(renderer, color:, width:)
7
+ @renderer = renderer
7
8
  @color = color
8
9
  @width = width
9
10
  end
10
11
 
11
12
  def render(points)
12
- draw = Renderer.instance.draw
13
-
14
- draw.push
15
- draw.stroke(@color)
16
- draw.fill('transparent')
17
- draw.stroke_width(@width)
18
- draw.polyline(*points)
19
- draw.pop
13
+ @renderer.draw.push
14
+ @renderer.draw.stroke(@color)
15
+ @renderer.draw.fill('transparent')
16
+ @renderer.draw.stroke_width(@width)
17
+ @renderer.draw.polyline(*points)
18
+ @renderer.draw.pop
20
19
  end
21
20
  end
22
21
  end
@@ -3,18 +3,17 @@
3
3
  module Gruff
4
4
  # @private
5
5
  class Renderer::Rectangle
6
- def initialize(color: nil)
6
+ def initialize(renderer, color: nil)
7
+ @renderer = renderer
7
8
  @color = color
8
9
  end
9
10
 
10
11
  def render(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
11
- draw = Renderer.instance.draw
12
-
13
- draw.push
14
- draw.stroke('transparent')
15
- draw.fill(@color) if @color
16
- draw.rectangle(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
17
- draw.pop
12
+ @renderer.draw.push
13
+ @renderer.draw.stroke('transparent')
14
+ @renderer.draw.fill(@color) if @color
15
+ @renderer.draw.rectangle(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
16
+ @renderer.draw.pop
18
17
  end
19
18
  end
20
19
  end
@@ -1,53 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'singleton'
4
-
5
3
  module Gruff
6
4
  # @private
7
5
  class Renderer
8
- include Singleton
9
-
10
- attr_accessor :draw, :image, :scale, :text_renderers
11
-
12
- def self.setup(columns, rows, font, scale, theme_options)
13
- draw = Magick::Draw.new
14
- draw.font = font if font
15
- # Scale down from 800x600 used to calculate drawing.
16
- draw.scale(scale, scale)
17
-
18
- image = Renderer.instance.background(columns, rows, scale, theme_options)
6
+ attr_accessor :text_renderers
7
+ attr_reader :draw, :image, :scale
19
8
 
20
- Renderer.instance.draw = draw
21
- Renderer.instance.scale = scale
22
- Renderer.instance.image = image
23
- Renderer.instance.text_renderers = []
24
- end
25
-
26
- def self.setup_transparent_background(columns, rows)
27
- image = Renderer.instance.render_transparent_background(columns, rows)
28
- Renderer.instance.image = image
29
- end
9
+ def initialize(columns, rows, scale, theme_options)
10
+ @draw = Magick::Draw.new
11
+ @text_renderers = []
30
12
 
31
- def self.background_image=(image)
32
- Renderer.instance.image = image
13
+ @scale = scale
14
+ @draw.scale(scale, scale)
15
+ @image = background(columns, rows, scale, theme_options)
33
16
  end
34
17
 
35
- def self.font=(font)
36
- draw = Renderer.instance.draw
37
- draw.font = font if font
38
- end
18
+ def finish
19
+ @draw.draw(@image)
39
20
 
40
- def self.finish
41
- draw = Renderer.instance.draw
42
- image = Renderer.instance.image
43
-
44
- draw.draw(image)
45
-
46
- Renderer.instance.text_renderers.each do |renderer|
21
+ @text_renderers.each do |renderer|
47
22
  renderer.render(renderer.width, renderer.height, renderer.x, renderer.y, renderer.gravity)
48
23
  end
49
24
  end
50
25
 
26
+ def background_image=(image)
27
+ @image = image
28
+ end
29
+
51
30
  def background(columns, rows, scale, theme_options)
52
31
  case theme_options[:background_colors]
53
32
  when Array
@@ -59,6 +38,10 @@ module Gruff
59
38
  end
60
39
  end
61
40
 
41
+ def transparent_background(columns, rows)
42
+ @image = render_transparent_background(columns, rows)
43
+ end
44
+
62
45
  # Make a new image at the current size with a solid +color+.
63
46
  def solid_background(columns, rows, color)
64
47
  Magick::Image.new(columns, rows) do
@@ -101,6 +84,8 @@ module Gruff
101
84
  end
102
85
  end
103
86
 
87
+ private
88
+
104
89
  # Use with a theme to use an image (800x600 original) background.
105
90
  def image_background(scale, image_path)
106
91
  image = Magick::Image.read(image_path)
@@ -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,50 +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 || Renderer::Text.default_font(@font_weight)
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, font, size, font_weight = Magick::NormalWeight)
49
- draw = Renderer.instance.draw
50
- image = Renderer.instance.image
51
-
52
- draw.font = font || Renderer::Text.default_font(font_weight)
53
- draw.font_weight = font_weight
54
- 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
55
46
 
56
47
  # The old ImageMagick causes SEGV with string which has '%' + alphabet (eg. '%S').
57
48
  # This format is used to embed value into a string using image properties.
58
49
  # However, gruff use plain image as canvas which does not have any property.
59
50
  # So, in here, it just escape % in order to avoid SEGV.
60
- text = text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
61
-
62
- draw.get_type_metrics(image, text)
63
- end
64
-
65
- FONT_BOLD = File.expand_path(File.join(__FILE__, '../../../../assets/fonts/Roboto-Bold.ttf'))
66
- FONT_REGULAR = File.expand_path(File.join(__FILE__, '../../../../assets/fonts/Roboto-Regular.ttf'))
51
+ text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
67
52
 
68
- def self.default_font(font_weight)
69
- (font_weight == Magick::BoldWeight) ? FONT_BOLD : FONT_REGULAR
53
+ @renderer.draw.get_type_metrics(@renderer.image, text)
70
54
  end
71
55
  end
72
56
  end
data/lib/gruff/scatter.rb CHANGED
@@ -35,27 +35,6 @@ class Gruff::Scatter < Gruff::Base
35
35
  attr_writer :x_label_margin
36
36
  attr_writer :use_vertical_x_labels
37
37
 
38
- def initialize_store
39
- @store = Gruff::Store.new(Gruff::Store::XYData)
40
- end
41
- private :initialize_store
42
-
43
- def initialize_ivars
44
- super
45
-
46
- @baseline_x_color = @baseline_y_color = 'red'
47
- @baseline_x_value = @baseline_y_value = nil
48
- @circle_radius = nil
49
- @disable_significant_rounding_x_axis = false
50
- @show_vertical_markers = false
51
- @marker_x_count = nil
52
- @maximum_x_value = @minimum_x_value = nil
53
- @stroke_width = nil
54
- @use_vertical_x_labels = false
55
- @x_label_margin = nil
56
- end
57
- private :initialize_ivars
58
-
59
38
  # Allow enabling vertical lines. When you have a lot of data, they can work great.
60
39
  # @deprecated Please use +show_vertical_markers+ attribute instead.
61
40
  def enable_vertical_line_markers=(value)
@@ -63,28 +42,6 @@ class Gruff::Scatter < Gruff::Base
63
42
  @show_vertical_markers = value
64
43
  end
65
44
 
66
- def draw
67
- super
68
- return unless data_given?
69
-
70
- # Check to see if more than one datapoint was given. NaN can result otherwise.
71
- @x_increment = (@x_spread > 1) ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
72
-
73
- store.norm_data.each do |data_row|
74
- data_row.coordinates.each do |x_value, y_value|
75
- next if y_value.nil? || x_value.nil?
76
-
77
- new_x = get_x_coord(x_value, @graph_width, @graph_left)
78
- new_y = @graph_top + (@graph_height - y_value * @graph_height)
79
-
80
- # Reset each time to avoid thin-line errors
81
- stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
82
- circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
83
- Gruff::Renderer::Circle.new(color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
84
- end
85
- end
86
- end
87
-
88
45
  # The first parameter is the name of the dataset. The next two are the
89
46
  # x and y axis data points contain in their own array in that respective
90
47
  # order. The final parameter is the color.
@@ -138,6 +95,44 @@ class Gruff::Scatter < Gruff::Base
138
95
 
139
96
  private
140
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
+
141
136
  def setup_data
142
137
  # Update the global min/max values for the x data
143
138
  @maximum_x_value ||= store.max_x
@@ -187,7 +182,7 @@ private
187
182
  end
188
183
  else
189
184
  # TODO: Make this work for negative values
190
- @maximum_x_value = [maximum_value.ceil, @x_axis_increment].max
185
+ @maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment].max
191
186
  @minimum_x_value = @minimum_x_value.floor
192
187
  calculate_spread
193
188
  normalize
@@ -203,7 +198,7 @@ private
203
198
  if @show_vertical_markers
204
199
  x = @graph_left + @graph_width - index.to_f * increment_x_scaled
205
200
 
206
- 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)
207
202
  line_renderer.render(x, @graph_top, x, @graph_bottom)
208
203
  end
209
204
 
@@ -214,7 +209,7 @@ private
214
209
 
215
210
  label = x_axis_label(marker_label, @x_increment)
216
211
  rotation = -90.0 if @use_vertical_x_labels
217
- 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)
218
213
  text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
219
214
  end
220
215
  end