gruff 0.7.0-java → 0.12.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 (113) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → CHANGELOG.md} +81 -25
  3. data/Gemfile +3 -1
  4. data/README.md +51 -23
  5. data/assets/plastik/blue.png +0 -0
  6. data/assets/plastik/green.png +0 -0
  7. data/assets/plastik/red.png +0 -0
  8. data/gruff.gemspec +23 -13
  9. data/init.rb +2 -0
  10. data/lib/gruff.rb +33 -4
  11. data/lib/gruff/accumulator_bar.rb +17 -9
  12. data/lib/gruff/area.rb +31 -21
  13. data/lib/gruff/bar.rb +90 -46
  14. data/lib/gruff/base.rb +476 -710
  15. data/lib/gruff/bezier.rb +29 -18
  16. data/lib/gruff/bullet.rb +58 -71
  17. data/lib/gruff/dot.rb +35 -83
  18. data/lib/gruff/helper/bar_conversion.rb +47 -0
  19. data/lib/gruff/helper/bar_value_label_mixin.rb +33 -0
  20. data/lib/gruff/helper/stacked_mixin.rb +23 -0
  21. data/lib/gruff/histogram.rb +59 -0
  22. data/lib/gruff/line.rb +121 -199
  23. data/lib/gruff/mini/bar.rb +17 -10
  24. data/lib/gruff/mini/legend.rb +26 -38
  25. data/lib/gruff/mini/pie.rb +18 -13
  26. data/lib/gruff/mini/side_bar.rb +25 -12
  27. data/lib/gruff/net.rb +69 -83
  28. data/lib/gruff/patch/rmagick.rb +31 -0
  29. data/lib/gruff/patch/string.rb +13 -0
  30. data/lib/gruff/photo_bar.rb +36 -43
  31. data/lib/gruff/pie.rb +42 -103
  32. data/lib/gruff/renderer/bezier.rb +22 -0
  33. data/lib/gruff/renderer/circle.rb +22 -0
  34. data/lib/gruff/renderer/dash_line.rb +23 -0
  35. data/lib/gruff/renderer/dot.rb +40 -0
  36. data/lib/gruff/renderer/ellipse.rb +22 -0
  37. data/lib/gruff/renderer/line.rb +43 -0
  38. data/lib/gruff/renderer/polygon.rb +24 -0
  39. data/lib/gruff/renderer/polyline.rb +22 -0
  40. data/lib/gruff/renderer/rectangle.rb +20 -0
  41. data/lib/gruff/renderer/renderer.rb +120 -0
  42. data/lib/gruff/renderer/text.rb +57 -0
  43. data/lib/gruff/scatter.rb +128 -201
  44. data/lib/gruff/scene.rb +30 -41
  45. data/lib/gruff/side_bar.rb +100 -68
  46. data/lib/gruff/side_stacked_bar.rb +92 -63
  47. data/lib/gruff/spider.rb +47 -53
  48. data/lib/gruff/stacked_area.rb +37 -34
  49. data/lib/gruff/stacked_bar.rb +99 -54
  50. data/lib/gruff/store/basic_data.rb +36 -0
  51. data/lib/gruff/store/custom_data.rb +36 -0
  52. data/lib/gruff/store/store.rb +81 -0
  53. data/lib/gruff/store/xy_data.rb +58 -0
  54. data/lib/gruff/themes.rb +32 -33
  55. data/lib/gruff/version.rb +3 -1
  56. metadata +74 -102
  57. data/.gitignore +0 -7
  58. data/.travis.yml +0 -19
  59. data/Manifest.txt +0 -81
  60. data/RELEASE.md +0 -30
  61. data/Rakefile +0 -218
  62. data/assets/bubble.png +0 -0
  63. data/assets/city_scene/background/0000.png +0 -0
  64. data/assets/city_scene/background/0600.png +0 -0
  65. data/assets/city_scene/background/2000.png +0 -0
  66. data/assets/city_scene/clouds/cloudy.png +0 -0
  67. data/assets/city_scene/clouds/partly_cloudy.png +0 -0
  68. data/assets/city_scene/clouds/stormy.png +0 -0
  69. data/assets/city_scene/grass/default.png +0 -0
  70. data/assets/city_scene/haze/true.png +0 -0
  71. data/assets/city_scene/number_sample/1.png +0 -0
  72. data/assets/city_scene/number_sample/2.png +0 -0
  73. data/assets/city_scene/number_sample/default.png +0 -0
  74. data/assets/city_scene/sky/0000.png +0 -0
  75. data/assets/city_scene/sky/0200.png +0 -0
  76. data/assets/city_scene/sky/0400.png +0 -0
  77. data/assets/city_scene/sky/0600.png +0 -0
  78. data/assets/city_scene/sky/0800.png +0 -0
  79. data/assets/city_scene/sky/1000.png +0 -0
  80. data/assets/city_scene/sky/1200.png +0 -0
  81. data/assets/city_scene/sky/1400.png +0 -0
  82. data/assets/city_scene/sky/1500.png +0 -0
  83. data/assets/city_scene/sky/1700.png +0 -0
  84. data/assets/city_scene/sky/2000.png +0 -0
  85. data/assets/pc306715.jpg +0 -0
  86. data/lib/gruff/bar_conversion.rb +0 -46
  87. data/lib/gruff/deprecated.rb +0 -39
  88. data/lib/gruff/stacked_mixin.rb +0 -23
  89. data/test/gruff_test_case.rb +0 -152
  90. data/test/image_compare.rb +0 -58
  91. data/test/test_accumulator_bar.rb +0 -51
  92. data/test/test_area.rb +0 -134
  93. data/test/test_bar.rb +0 -505
  94. data/test/test_base.rb +0 -33
  95. data/test/test_bezier.rb +0 -33
  96. data/test/test_bullet.rb +0 -26
  97. data/test/test_dot.rb +0 -263
  98. data/test/test_labels_for_null_data.rb +0 -27
  99. data/test/test_legend.rb +0 -68
  100. data/test/test_line.rb +0 -674
  101. data/test/test_mini_bar.rb +0 -33
  102. data/test/test_mini_pie.rb +0 -25
  103. data/test/test_mini_side_bar.rb +0 -36
  104. data/test/test_net.rb +0 -231
  105. data/test/test_photo.rb +0 -41
  106. data/test/test_pie.rb +0 -194
  107. data/test/test_scatter.rb +0 -270
  108. data/test/test_scene.rb +0 -100
  109. data/test/test_side_bar.rb +0 -56
  110. data/test/test_sidestacked_bar.rb +0 -105
  111. data/test/test_spider.rb +0 -226
  112. data/test/test_stacked_area.rb +0 -52
  113. data/test/test_stacked_bar.rb +0 -68
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @private
4
+ module Magick
5
+ # @private
6
+ module GruffAnnotate
7
+ refine Draw do
8
+ # Additional method to scale annotation text since Draw.scale doesn't.
9
+ def annotate_scaled(img, width, height, x, y, text, scale)
10
+ scaled_width = (width * scale) >= 1 ? (width * scale) : 1
11
+ scaled_height = (height * scale) >= 1 ? (height * scale) : 1
12
+
13
+ annotate(img,
14
+ scaled_width, scaled_height,
15
+ x * scale, y * scale,
16
+ text.gsub('%', '%%'))
17
+ end
18
+
19
+ if defined? JRUBY_VERSION
20
+ # FIXME(uwe): We should NOT need to implement this method.
21
+ # Remove this method as soon as RMagick4J Issue #16 is fixed.
22
+ # https://github.com/Serabe/RMagick4J/issues/16
23
+ def fill=(fill)
24
+ fill = { white: '#FFFFFF' }[fill.to_sym] || fill
25
+ @draw.fill = Magick4J.ColorDatabase.query_default(fill)
26
+ self
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @private
4
+ module String::GruffCommify
5
+ THOUSAND_SEPARATOR = ','
6
+
7
+ refine String do
8
+ #Taken from http://codesnippets.joyent.com/posts/show/330
9
+ def commify(delimiter = THOUSAND_SEPARATOR)
10
+ gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
11
+ end
12
+ end
13
+ end
@@ -1,36 +1,35 @@
1
- require File.dirname(__FILE__) + '/base'
1
+ # frozen_string_literal: true
2
2
 
3
3
  # EXPERIMENTAL!
4
4
  #
5
5
  # Doesn't work yet.
6
6
  #
7
7
  class Gruff::PhotoBar < Gruff::Base
8
-
9
- # TODO
10
- #
11
- # define base and cap in yml
12
- # allow for image directory to be located elsewhere
13
- # more exact measurements for bar heights (go all the way to the bottom of the graph)
14
- # option to tile images instead of use a single image
15
- # drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
16
- #
8
+ # TODO
9
+ #
10
+ # define base and cap in yml
11
+ # allow for image directory to be located elsewhere
12
+ # more exact measurements for bar heights (go all the way to the bottom of the graph)
13
+ # option to tile images instead of use a single image
14
+ # drop base label a few px lower so photo bar graphs can have a base dropping over the lower marker line
15
+ #
17
16
 
18
17
  # The name of a pre-packaged photo-based theme.
19
18
  attr_reader :theme
20
19
 
21
- # def initialize(target_width=800)
22
- # super
23
- # init_photo_bar_graphics()
24
- # end
20
+ # def initialize(target_width=800)
21
+ # super
22
+ # init_photo_bar_graphics()
23
+ # end
25
24
 
26
25
  def draw
27
26
  super
28
- return unless @has_data
27
+ return unless data_given?
28
+
29
+ return # TODO: Remove for further development
29
30
 
30
- return # TODO Remove for further development
31
+ init_photo_bar_graphics
31
32
 
32
- init_photo_bar_graphics()
33
-
34
33
  #Draw#define_clip_path()
35
34
  #Draw#clip_path(pathname)
36
35
  #Draw#composite....with bar graph image OverCompositeOp
@@ -38,44 +37,39 @@ class Gruff::PhotoBar < Gruff::Base
38
37
  # See also
39
38
  #
40
39
  # Draw.pattern # define an image to tile as the filling of a draw object
41
- #
40
+ #
42
41
 
43
42
  # Setup spacing.
44
43
  #
45
44
  # Columns sit side-by-side.
46
45
  spacing_factor = 0.9
47
- @bar_width = @norm_data[0][DATA_COLOR_INDEX].columns
46
+ bar_width = store.norm_data[0].color.columns
48
47
 
49
- @norm_data.each_with_index do |data_row, row_index|
50
-
51
- data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
48
+ store.norm_data.each_with_index do |data_row, row_index|
49
+ data_row.points.each_with_index do |data_point, point_index|
52
50
  data_point = 0 if data_point.nil?
53
51
  # Use incremented x and scaled y
54
- left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
52
+ left_x = @graph_left + (bar_width * (row_index + point_index + ((store.length - 1) * point_index)))
55
53
  left_y = @graph_top + (@graph_height - data_point * @graph_height) + 1
56
- right_x = left_x + @bar_width * spacing_factor
54
+ right_x = left_x + bar_width * spacing_factor
57
55
  right_y = @graph_top + @graph_height - 1
58
-
59
- bar_image_width = data_row[DATA_COLOR_INDEX].columns
56
+
57
+ bar_image_width = data_row.color.columns
60
58
  bar_image_height = right_y.to_f - left_y.to_f
61
-
59
+
62
60
  # Crop to scale for data
63
- bar_image = data_row[DATA_COLOR_INDEX].crop(0, 0, bar_image_width, bar_image_height)
64
-
65
- @d.gravity = NorthWestGravity
66
- @d = @d.composite(left_x, left_y, bar_image_width, bar_image_height, bar_image)
67
-
61
+ bar_image = data_row.color.crop(0, 0, bar_image_width, bar_image_height)
62
+
63
+ @d.gravity = Magick::NorthWestGravity
64
+ @d.composite(left_x, left_y, bar_image_width, bar_image_height, bar_image)
65
+
68
66
  # Calculate center based on bar_width and current row
69
- label_center = @graph_left + (@data.length * @bar_width * point_index) + (@data.length * @bar_width / 2.0)
67
+ label_center = @graph_left + (store.length * bar_width * point_index) + (store.length * bar_width / 2.0)
70
68
  draw_label(label_center, point_index)
71
69
  end
72
-
73
70
  end
74
-
75
- @d.draw(@base_image)
76
71
  end
77
72
 
78
-
79
73
  # Return the chosen theme or the default
80
74
  def theme
81
75
  @theme || 'plastik'
@@ -85,16 +79,15 @@ protected
85
79
 
86
80
  # Sets up colors with a list of images that will be used.
87
81
  # Images should be 340px tall
88
- def init_photo_bar_graphics
89
- color_list = Array.new
82
+ def init_photo_bar_graphics
83
+ color_list = []
90
84
  theme_dir = File.dirname(__FILE__) + '/../../assets/' + theme
91
85
 
92
86
  Dir.open(theme_dir).each do |file|
93
87
  next unless /\.png$/.match(file)
94
- color_list << Image.read("#{theme_dir}/#{file}").first
88
+
89
+ color_list << Magick::Image.read("#{theme_dir}/#{file}").first
95
90
  end
96
91
  @colors = color_list
97
92
  end
98
-
99
93
  end
100
-
@@ -1,59 +1,54 @@
1
- require File.dirname(__FILE__) + '/base'
1
+ # frozen_string_literal: true
2
2
 
3
- ##
4
- # Here's how to make a Pie graph:
3
+ #
4
+ # Here's how to make a Gruff::Pie.
5
5
  #
6
6
  # g = Gruff::Pie.new
7
7
  # g.title = "Visual Pie Graph Test"
8
8
  # g.data 'Fries', 20
9
9
  # g.data 'Hamburgers', 50
10
- # g.write("test/output/pie_keynote.png")
10
+ # g.write("pie_keynote.png")
11
+ #
12
+ # To control where the pie chart starts creating slices, use {#zero_degree=}.
11
13
  #
12
- # To control where the pie chart starts creating slices, use #zero_degree.
13
-
14
14
  class Gruff::Pie < Gruff::Base
15
-
16
15
  DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.15
17
16
 
18
17
  # Can be used to make the pie start cutting slices at the top (-90.0)
19
- # or at another angle. Default is 0.0, which starts at 3 o'clock.
18
+ # or at another angle. Default is +0.0+, which starts at 3 o'clock.
20
19
  attr_writer :zero_degree
21
20
 
22
21
  # Do not show labels for slices that are less than this percent. Use 0 to always show all labels.
23
- # Defaults to 0
22
+ # Defaults to +0+.
24
23
  attr_writer :hide_labels_less_than
25
24
 
26
- # Affect the distance between the percentages and the pie chart
27
- # Defaults to 0.15
25
+ # Affect the distance between the percentages and the pie chart.
26
+ # Defaults to +0.15+.
28
27
  attr_writer :text_offset_percentage
29
28
 
30
- ## Use values instead of percentages
31
- attr_accessor :show_values_as_labels
29
+ ## Use values instead of percentages.
30
+ attr_writer :show_values_as_labels
31
+
32
+ def initialize_store
33
+ @store = Gruff::Store.new(Gruff::Store::CustomData)
34
+ end
35
+ private :initialize_store
32
36
 
33
37
  def initialize_ivars
34
38
  super
35
-
39
+ @zero_degree = 0.0
40
+ @hide_labels_less_than = 0.0
41
+ @text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
36
42
  @show_values_as_labels = false
37
43
  end
38
-
39
- def zero_degree
40
- @zero_degree ||= 0.0
41
- end
42
-
43
- def hide_labels_less_than
44
- @hide_labels_less_than ||= 0.0
45
- end
46
-
47
- def text_offset_percentage
48
- @text_offset_percentage ||= DEFAULT_TEXT_OFFSET_PERCENTAGE
49
- end
44
+ private :initialize_ivars
50
45
 
51
46
  def options
52
47
  {
53
- :zero_degree => zero_degree,
54
- :hide_labels_less_than => hide_labels_less_than,
55
- :text_offset_percentage => text_offset_percentage,
56
- :show_values_as_labels => show_values_as_labels
48
+ zero_degree: @zero_degree,
49
+ hide_labels_less_than: @hide_labels_less_than,
50
+ text_offset_percentage: @text_offset_percentage,
51
+ show_values_as_labels: @show_values_as_labels
57
52
  }
58
53
  end
59
54
 
@@ -66,27 +61,23 @@ class Gruff::Pie < Gruff::Base
66
61
 
67
62
  slices.each do |slice|
68
63
  if slice.value > 0
69
- set_stroke_color slice
70
- set_fill_color
71
- set_stroke_width
72
- set_drawing_points_for slice
64
+ Gruff::Renderer::Ellipse.new(color: slice.color, width: radius)
65
+ .render(center_x, center_y, radius / 2.0, radius / 2.0, chart_degrees, chart_degrees + slice.degrees + 0.5)
73
66
  process_label_for slice
74
67
  update_chart_degrees_with slice.degrees
75
68
  end
76
69
  end
77
-
78
- trigger_final_draw
79
70
  end
80
71
 
81
- private
72
+ private
82
73
 
83
74
  def slices
84
75
  @slices ||= begin
85
- slices = @data.map { |data| slice_class.new(data, options) }
76
+ slices = store.data.map { |data| slice_class.new(data, options) }
86
77
 
87
78
  slices.sort_by(&:value) if @sort
88
79
 
89
- total = slices.map(&:value).inject(:+).to_f
80
+ total = slices.map(&:value).sum.to_f
90
81
  slices.each { |slice| slice.total = total }
91
82
  end
92
83
  end
@@ -97,10 +88,6 @@ class Gruff::Pie < Gruff::Base
97
88
  @hide_line_markers = true
98
89
  end
99
90
 
100
- def data_given?
101
- @has_data
102
- end
103
-
104
91
  def update_chart_degrees_with(degrees)
105
92
  @chart_degrees = chart_degrees + degrees
106
93
  end
@@ -112,16 +99,12 @@ class Gruff::Pie < Gruff::Base
112
99
  # Spatial Value-Related Methods
113
100
 
114
101
  def chart_degrees
115
- @chart_degrees ||= zero_degree
102
+ @chart_degrees ||= @zero_degree
116
103
  end
117
104
 
118
- def graph_height
119
- @graph_height
120
- end
105
+ attr_reader :graph_height
121
106
 
122
- def graph_width
123
- @graph_width
124
- end
107
+ attr_reader :graph_width
125
108
 
126
109
  def diameter
127
110
  graph_height
@@ -152,20 +135,20 @@ class Gruff::Pie < Gruff::Base
152
135
  end
153
136
 
154
137
  def radius_offset
155
- radius + (radius * text_offset_percentage) + distance_from_center
138
+ radius + (radius * @text_offset_percentage) + distance_from_center
156
139
  end
157
140
 
158
141
  def ellipse_factor
159
- radius_offset * text_offset_percentage
142
+ radius_offset * @text_offset_percentage
160
143
  end
161
144
 
162
145
  # Label-Related Methods
163
146
 
164
147
  def process_label_for(slice)
165
- if slice.percentage >= hide_labels_less_than
166
- x, y = label_coordinates_for slice
148
+ if slice.percentage >= @hide_labels_less_than
149
+ x, y = label_coordinates_for slice
167
150
 
168
- @d = draw_label(x, y, slice.label)
151
+ draw_label(x, y, slice.label)
169
152
  end
170
153
  end
171
154
 
@@ -185,58 +168,14 @@ class Gruff::Pie < Gruff::Base
185
168
 
186
169
  # Drawing-Related Methods
187
170
 
188
- def set_stroke_width
189
- @d.stroke_width(radius)
190
- end
191
-
192
- def set_stroke_color(slice)
193
- @d = @d.stroke slice.color
194
- end
195
-
196
- def set_fill_color
197
- @d = @d.fill 'transparent'
198
- end
199
-
200
- def set_drawing_points_for(slice)
201
- @d = @d.ellipse(
202
- center_x,
203
- center_y,
204
- radius / 2.0,
205
- radius / 2.0,
206
- chart_degrees,
207
- chart_degrees + slice.degrees + 0.5
208
- )
209
- end
210
-
211
- def trigger_final_draw
212
- @d.draw(@base_image)
213
- end
214
-
215
- def configure_label_styling
216
- @d.fill = @font_color
217
- @d.font = @font if @font
218
- @d.pointsize = scale_fontsize(@marker_font_size)
219
- @d.stroke = 'transparent'
220
- @d.font_weight = BoldWeight
221
- @d.gravity = CenterGravity
222
- end
223
-
224
171
  def draw_label(x, y, value)
225
- configure_label_styling
226
-
227
- @d.annotate_scaled(
228
- @base_image,
229
- 0,
230
- 0,
231
- x,
232
- y,
233
- value,
234
- @scale
235
- )
172
+ text_renderer = Gruff::Renderer::Text.new(value, font: @font, size: @marker_font_size, color: @font_color, weight: Magick::BoldWeight)
173
+ text_renderer.add_to_render_queue(0, 0, x, y, Magick::CenterGravity)
236
174
  end
237
175
 
238
176
  # Helper Classes
239
-
177
+ #
178
+ # @private
240
179
  class PieSlice < Struct.new(:data_array, :options)
241
180
  attr_accessor :total
242
181
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gruff
4
+ # @private
5
+ class Renderer::Bezier
6
+ def initialize(color:, width: 1.0)
7
+ @color = color
8
+ @width = width
9
+ end
10
+
11
+ def render(points)
12
+ draw = Renderer.instance.draw
13
+
14
+ draw.push
15
+ draw.stroke(@color)
16
+ draw.stroke_width(@width)
17
+ draw.fill_opacity(0.0)
18
+ draw.bezier(*points)
19
+ draw.pop
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gruff
4
+ # @private
5
+ class Renderer::Circle
6
+ def initialize(color:, width: 1.0)
7
+ @color = color
8
+ @width = width
9
+ end
10
+
11
+ def render(origin_x, origin_y, perim_x, perim_y)
12
+ draw = Renderer.instance.draw
13
+
14
+ draw.push
15
+ draw.fill(@color)
16
+ draw.stroke(@color)
17
+ draw.stroke_width(@width)
18
+ draw.circle(origin_x, origin_y, perim_x, perim_y)
19
+ draw.pop
20
+ end
21
+ end
22
+ end