gruff 0.7.0-java → 0.12.0-java

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