gruff 0.13.0-java → 0.16.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +79 -0
- data/.rubocop.yml +29 -31
- data/CHANGELOG.md +43 -0
- data/README.md +11 -5
- data/gruff.gemspec +8 -10
- data/lib/gruff/accumulator_bar.rb +4 -2
- data/lib/gruff/area.rb +9 -12
- data/lib/gruff/bar.rb +46 -31
- data/lib/gruff/base.rb +236 -207
- data/lib/gruff/bezier.rb +6 -8
- data/lib/gruff/box_plot.rb +174 -0
- data/lib/gruff/bullet.rb +17 -16
- data/lib/gruff/candlestick.rb +112 -0
- data/lib/gruff/dot.rb +14 -14
- data/lib/gruff/font.rb +42 -0
- data/lib/gruff/helper/bar_conversion.rb +5 -5
- data/lib/gruff/helper/bar_value_label.rb +26 -20
- data/lib/gruff/helper/stacked_mixin.rb +4 -3
- data/lib/gruff/histogram.rb +9 -7
- data/lib/gruff/line.rb +96 -83
- data/lib/gruff/mini/bar.rb +9 -6
- data/lib/gruff/mini/legend.rb +16 -12
- data/lib/gruff/mini/pie.rb +9 -6
- data/lib/gruff/mini/side_bar.rb +9 -6
- data/lib/gruff/net.rb +16 -22
- data/lib/gruff/patch/rmagick.rb +0 -1
- data/lib/gruff/patch/string.rb +2 -1
- data/lib/gruff/pie.rb +42 -75
- data/lib/gruff/renderer/bezier.rb +8 -9
- data/lib/gruff/renderer/circle.rb +8 -9
- data/lib/gruff/renderer/dash_line.rb +10 -10
- data/lib/gruff/renderer/dot.rb +15 -14
- data/lib/gruff/renderer/ellipse.rb +8 -9
- data/lib/gruff/renderer/line.rb +8 -11
- data/lib/gruff/renderer/polygon.rb +9 -10
- data/lib/gruff/renderer/polyline.rb +8 -9
- data/lib/gruff/renderer/rectangle.rb +11 -8
- data/lib/gruff/renderer/renderer.rb +25 -40
- data/lib/gruff/renderer/text.rb +21 -37
- data/lib/gruff/scatter.rb +86 -85
- data/lib/gruff/side_bar.rb +50 -37
- data/lib/gruff/side_stacked_bar.rb +26 -35
- data/lib/gruff/spider.rb +52 -28
- data/lib/gruff/stacked_area.rb +20 -16
- data/lib/gruff/stacked_bar.rb +44 -22
- data/lib/gruff/store/store.rb +6 -10
- data/lib/gruff/store/xy_data.rb +2 -0
- data/lib/gruff/themes.rb +6 -6
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +70 -57
- data/rails_generators/gruff/templates/controller.rb +1 -1
- metadata +15 -32
- data/.rubocop_todo.yml +0 -182
- data/.travis.yml +0 -23
- data/assets/plastik/blue.png +0 -0
- data/assets/plastik/green.png +0 -0
- data/assets/plastik/red.png +0 -0
- data/lib/gruff/photo_bar.rb +0 -93
- data/lib/gruff/scene.rb +0 -198
- data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/renderer/text.rb
CHANGED
@@ -5,12 +5,10 @@ module Gruff
|
|
5
5
|
class Renderer::Text
|
6
6
|
using Magick::GruffAnnotate
|
7
7
|
|
8
|
-
def initialize(text, font:,
|
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
|
-
|
24
|
+
@renderer.text_renderers << self
|
27
25
|
end
|
28
26
|
|
29
27
|
def render(width, height, x, y, gravity = Magick::NorthGravity)
|
30
|
-
draw
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
draw.
|
35
|
-
draw.
|
36
|
-
draw.
|
37
|
-
draw.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
draw.
|
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
|
49
|
-
draw
|
50
|
-
|
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
|
-
|
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,22 +95,59 @@ class Gruff::Scatter < Gruff::Base
|
|
138
95
|
|
139
96
|
private
|
140
97
|
|
141
|
-
def
|
142
|
-
|
143
|
-
|
144
|
-
@minimum_x_value ||= store.min_x
|
98
|
+
def initialize_store
|
99
|
+
@store = Gruff::Store.new(Gruff::Store::XYData)
|
100
|
+
end
|
145
101
|
|
102
|
+
def initialize_attributes
|
146
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
|
+
store.norm_data.each do |data_row|
|
119
|
+
data_row.coordinates.each do |x_value, y_value|
|
120
|
+
next if y_value.nil? || x_value.nil?
|
121
|
+
|
122
|
+
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
123
|
+
new_y = @graph_top + (@graph_height - (y_value * @graph_height))
|
124
|
+
|
125
|
+
# Reset each time to avoid thin-line errors
|
126
|
+
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
127
|
+
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
128
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
129
|
+
end
|
130
|
+
end
|
147
131
|
end
|
148
132
|
|
149
|
-
def
|
133
|
+
def setup_data
|
150
134
|
# TODO: Need to get x-axis labels working. Current behavior will be to not allow.
|
151
135
|
@labels = {}
|
152
136
|
|
137
|
+
# Update the global min/max values for the x data
|
138
|
+
@maximum_x_value = (@maximum_x_value || store.max_x).to_f
|
139
|
+
@minimum_x_value = (@minimum_x_value || store.min_x).to_f
|
140
|
+
|
141
|
+
if @x_axis_increment
|
142
|
+
# TODO: Make this work for negative values
|
143
|
+
@maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment.to_f].max
|
144
|
+
@minimum_x_value = @minimum_x_value.floor
|
145
|
+
end
|
146
|
+
|
153
147
|
super
|
154
148
|
end
|
155
149
|
|
156
|
-
def calculate_spread
|
150
|
+
def calculate_spread
|
157
151
|
super
|
158
152
|
@x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
|
159
153
|
@x_spread = @x_spread > 0 ? @x_spread : 1
|
@@ -170,57 +164,64 @@ private
|
|
170
164
|
super
|
171
165
|
return if @hide_line_markers
|
172
166
|
|
173
|
-
|
174
|
-
# TODO: Do the same for larger numbers...100, 75, 50, 25
|
175
|
-
if @marker_x_count.nil?
|
176
|
-
(3..7).each do |lines|
|
177
|
-
if @x_spread % lines == 0.0
|
178
|
-
@marker_x_count = lines
|
179
|
-
break
|
180
|
-
end
|
181
|
-
end
|
182
|
-
@marker_x_count ||= 4
|
183
|
-
end
|
184
|
-
@x_increment = (@x_spread > 0) ? (@x_spread / @marker_x_count) : 1
|
185
|
-
unless @disable_significant_rounding_x_axis
|
186
|
-
@x_increment = significant(@x_increment)
|
187
|
-
end
|
188
|
-
else
|
189
|
-
# TODO: Make this work for negative values
|
190
|
-
@maximum_x_value = [maximum_value.ceil, @x_axis_increment].max
|
191
|
-
@minimum_x_value = @minimum_x_value.floor
|
192
|
-
calculate_spread
|
193
|
-
normalize
|
194
|
-
|
195
|
-
@marker_x_count = (@x_spread / @x_axis_increment).to_i
|
196
|
-
@x_increment = @x_axis_increment
|
197
|
-
end
|
198
|
-
increment_x_scaled = @graph_width.to_f / (@x_spread / @x_increment)
|
167
|
+
increment_x_scaled = @graph_width / (@x_spread / x_increment)
|
199
168
|
|
200
169
|
# Draw vertical line markers and annotate with numbers
|
201
|
-
(0
|
170
|
+
(0..marker_x_count).each do |index|
|
202
171
|
# TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
|
203
172
|
if @show_vertical_markers
|
204
|
-
x = @graph_left + @graph_width - index
|
173
|
+
x = @graph_left + @graph_width - (index * increment_x_scaled)
|
205
174
|
|
206
|
-
|
207
|
-
|
175
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_top, x, @graph_bottom)
|
176
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_top + 1, x, @graph_bottom + 1) if @marker_shadow_color
|
208
177
|
end
|
209
178
|
|
210
179
|
unless @hide_line_numbers
|
211
|
-
marker_label = BigDecimal(index.to_s) * BigDecimal(
|
180
|
+
marker_label = (BigDecimal(index.to_s) * BigDecimal(x_increment.to_s)) + BigDecimal(@minimum_x_value.to_s)
|
212
181
|
y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
|
213
|
-
x_offset = get_x_coord(index
|
182
|
+
x_offset = get_x_coord(index, increment_x_scaled, @graph_left)
|
214
183
|
|
215
|
-
label = x_axis_label(marker_label,
|
184
|
+
label = x_axis_label(marker_label, x_increment)
|
216
185
|
rotation = -90.0 if @use_vertical_x_labels
|
217
|
-
text_renderer = Gruff::Renderer::Text.new(label, font: @
|
186
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
|
218
187
|
text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
|
219
188
|
end
|
220
189
|
end
|
221
190
|
end
|
222
191
|
|
223
|
-
def get_x_coord(x_data_point, width, offset)
|
224
|
-
x_data_point * width + offset
|
192
|
+
def get_x_coord(x_data_point, width, offset)
|
193
|
+
(x_data_point * width) + offset
|
194
|
+
end
|
195
|
+
|
196
|
+
def marker_x_count
|
197
|
+
# TODO: Do the same for larger numbers...100, 75, 50, 25
|
198
|
+
@marker_x_count ||= begin
|
199
|
+
if @x_axis_increment.nil?
|
200
|
+
count = nil
|
201
|
+
(3..7).each do |lines|
|
202
|
+
if @x_spread % lines == 0.0
|
203
|
+
count = lines and break
|
204
|
+
end
|
205
|
+
end
|
206
|
+
count || 4
|
207
|
+
else
|
208
|
+
(@x_spread / @x_axis_increment).to_i
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def x_increment
|
214
|
+
@x_increment ||= begin
|
215
|
+
if @x_axis_increment.nil?
|
216
|
+
increment = @x_spread > 0 ? (@x_spread / marker_x_count) : 1
|
217
|
+
unless @disable_significant_rounding_x_axis
|
218
|
+
increment = significant(increment)
|
219
|
+
end
|
220
|
+
else
|
221
|
+
increment = @x_axis_increment
|
222
|
+
end
|
223
|
+
|
224
|
+
increment
|
225
|
+
end
|
225
226
|
end
|
226
227
|
end
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -36,23 +36,13 @@ class Gruff::SideBar < Gruff::Base
|
|
36
36
|
# Prevent drawing of column labels left of a side bar graph. Default is +false+.
|
37
37
|
attr_writer :hide_labels
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@group_spacing = 10
|
43
|
-
@label_formatting = nil
|
44
|
-
@show_labels_for_bar_values = false
|
45
|
-
@hide_labels = false
|
46
|
-
end
|
47
|
-
private :initialize_ivars
|
39
|
+
# Value to avoid completely overwriting the coordinate axis
|
40
|
+
AXIS_MARGIN = 0.5
|
41
|
+
private_constant :AXIS_MARGIN
|
48
42
|
|
49
|
-
def
|
50
|
-
@has_left_labels = true
|
43
|
+
def initialize(*)
|
51
44
|
super
|
52
|
-
|
53
|
-
return unless data_given?
|
54
|
-
|
55
|
-
draw_bars
|
45
|
+
@has_left_labels = true
|
56
46
|
end
|
57
47
|
|
58
48
|
# With Side Bars use the data label for the marker value to the left of the bar.
|
@@ -61,29 +51,55 @@ class Gruff::SideBar < Gruff::Base
|
|
61
51
|
warn '#use_data_label is deprecated. It is no longer effective.'
|
62
52
|
end
|
63
53
|
|
64
|
-
|
54
|
+
private
|
55
|
+
|
56
|
+
def initialize_attributes
|
57
|
+
super
|
58
|
+
@bar_spacing = 0.9
|
59
|
+
@group_spacing = 10
|
60
|
+
@label_formatting = nil
|
61
|
+
@show_labels_for_bar_values = false
|
62
|
+
@hide_labels = false
|
63
|
+
end
|
65
64
|
|
66
65
|
def hide_labels?
|
67
66
|
@hide_labels
|
68
67
|
end
|
69
68
|
|
70
69
|
def hide_left_label_area?
|
71
|
-
hide_labels?
|
70
|
+
hide_labels? && @y_axis_label.nil?
|
72
71
|
end
|
73
72
|
|
74
73
|
def hide_bottom_label_area?
|
75
|
-
@hide_line_markers
|
74
|
+
@hide_line_markers && @x_axis_label.nil? && @legend_at_bottom == false
|
76
75
|
end
|
77
76
|
|
78
|
-
|
77
|
+
def setup_graph_measurements
|
78
|
+
super
|
79
|
+
return if @hide_line_markers
|
79
80
|
|
80
|
-
|
81
|
-
|
81
|
+
if @show_labels_for_bar_values
|
82
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
83
|
+
|
84
|
+
if maximum_value >= 0
|
85
|
+
_, metrics = Gruff::BarValueLabel.metrics(maximum_value, @label_formatting, proc_text_metrics)
|
86
|
+
@graph_right -= metrics.width
|
87
|
+
end
|
88
|
+
|
89
|
+
if minimum_value < 0
|
90
|
+
_, metrics = Gruff::BarValueLabel.metrics(minimum_value, @label_formatting, proc_text_metrics)
|
91
|
+
width = metrics.width + LABEL_MARGIN
|
92
|
+
@graph_left += width - @graph_left if width > @graph_left
|
93
|
+
end
|
94
|
+
|
95
|
+
@graph_width = @graph_right - @graph_left
|
96
|
+
end
|
97
|
+
end
|
82
98
|
|
83
|
-
def
|
99
|
+
def draw_graph
|
84
100
|
# Setup spacing.
|
85
101
|
#
|
86
|
-
bars_width = (@graph_height - calculate_spacing) / column_count
|
102
|
+
bars_width = (@graph_height - calculate_spacing) / column_count
|
87
103
|
bar_width = bars_width / store.length
|
88
104
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
89
105
|
|
@@ -93,32 +109,29 @@ private
|
|
93
109
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
94
110
|
)
|
95
111
|
|
96
|
-
|
97
|
-
# because sometimes (due to different heights/min/max) you can actually
|
98
|
-
# see both graphs and it looks like crap
|
99
|
-
return if is_a?(Gruff::SideStackedBar)
|
112
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
100
113
|
|
101
114
|
store.norm_data.each_with_index do |data_row, row_index|
|
102
115
|
data_row.points.each_with_index do |data_point, point_index|
|
103
116
|
group_spacing = @group_spacing * @scale * point_index
|
104
117
|
|
105
118
|
left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
|
106
|
-
right_y = left_y + bar_width * @bar_spacing
|
119
|
+
right_y = left_y + (bar_width * @bar_spacing)
|
107
120
|
|
108
121
|
left_x, right_x = conversion.get_top_bottom_scaled(data_point).sort
|
109
122
|
|
110
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
|
123
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
111
124
|
rect_renderer.render(left_x + AXIS_MARGIN, left_y, right_x + AXIS_MARGIN, right_y)
|
112
125
|
|
113
126
|
# Calculate center based on bar_width and current row
|
114
|
-
label_center = left_y + bars_width / 2
|
127
|
+
label_center = left_y + (bars_width / 2.0)
|
115
128
|
|
116
129
|
# Subtract half a bar width to center left if requested
|
117
130
|
draw_label(label_center, point_index)
|
118
131
|
if @show_labels_for_bar_values
|
119
132
|
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
120
|
-
bar_value_label.prepare_rendering(@label_formatting,
|
121
|
-
draw_value_label(x, y, text
|
133
|
+
bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
134
|
+
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
122
135
|
end
|
123
136
|
end
|
124
137
|
end
|
@@ -134,19 +147,19 @@ private
|
|
134
147
|
number_of_lines = 1 if number_of_lines == 0
|
135
148
|
|
136
149
|
# TODO: Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
|
137
|
-
increment = significant(@spread
|
150
|
+
increment = significant(@spread / number_of_lines)
|
138
151
|
(0..number_of_lines).each do |index|
|
139
152
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
140
153
|
x = @graph_right - (line_diff * index) - 1
|
141
154
|
|
142
|
-
|
143
|
-
|
155
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(x, @graph_bottom, x, @graph_top)
|
156
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(x, @graph_bottom + 1, x, @graph_top + 1) if @marker_shadow_color
|
144
157
|
|
145
158
|
unless @hide_line_numbers
|
146
159
|
diff = index - number_of_lines
|
147
|
-
marker_label = BigDecimal(diff.abs.to_s) * BigDecimal(increment.to_s) + BigDecimal(minimum_value.to_s)
|
160
|
+
marker_label = (BigDecimal(diff.abs.to_s) * BigDecimal(increment.to_s)) + BigDecimal(minimum_value.to_s)
|
148
161
|
label = x_axis_label(marker_label, @increment)
|
149
|
-
text_renderer = Gruff::Renderer::Text.new(label, font: @
|
162
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font)
|
150
163
|
text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + LABEL_MARGIN, Magick::CenterGravity)
|
151
164
|
end
|
152
165
|
end
|
@@ -39,86 +39,77 @@ class Gruff::SideStackedBar < Gruff::SideBar
|
|
39
39
|
# Prevent drawing of column labels left of a side stacked bar graph. Default is +false+.
|
40
40
|
attr_writer :hide_labels
|
41
41
|
|
42
|
-
def
|
42
|
+
def initialize(*)
|
43
|
+
super
|
44
|
+
@has_left_labels = true
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def initialize_attributes
|
43
50
|
super
|
44
51
|
@bar_spacing = 0.9
|
45
52
|
@segment_spacing = 2.0
|
46
53
|
@label_formatting = nil
|
47
54
|
@show_labels_for_bar_values = false
|
48
55
|
@hide_labels = false
|
56
|
+
@minimum_value = 0.0
|
49
57
|
end
|
50
|
-
private :initialize_ivars
|
51
58
|
|
52
|
-
def
|
53
|
-
@has_left_labels = true
|
59
|
+
def setup_data
|
54
60
|
calculate_maximum_by_stack
|
55
61
|
super
|
56
62
|
end
|
57
63
|
|
58
|
-
|
59
|
-
|
60
|
-
def hide_labels?
|
61
|
-
@hide_labels
|
62
|
-
end
|
63
|
-
|
64
|
-
def hide_left_label_area?
|
65
|
-
hide_labels?
|
66
|
-
end
|
67
|
-
|
68
|
-
def hide_bottom_label_area?
|
69
|
-
@hide_line_markers
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def draw_bars
|
64
|
+
def draw_graph
|
75
65
|
# Setup spacing.
|
76
66
|
#
|
77
67
|
# Columns sit stacked.
|
78
|
-
bar_width = @graph_height / column_count
|
68
|
+
bar_width = @graph_height / column_count
|
79
69
|
height = Array.new(column_count, 0)
|
80
70
|
length = Array.new(column_count, @graph_left)
|
81
71
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
82
|
-
|
72
|
+
stack_bar_value_labels = Gruff::BarValueLabel::StackedBar.new
|
83
73
|
|
84
74
|
store.norm_data.each_with_index do |data_row, row_index|
|
85
75
|
data_row.points.each_with_index do |data_point, point_index|
|
86
76
|
## using the original calculations from the stacked bar chart to get the difference between
|
87
77
|
## part of the bart chart we wish to stack.
|
88
|
-
temp1 = @graph_left + (@graph_width -
|
89
|
-
|
90
|
-
height[point_index]) + 1
|
91
|
-
temp2 = @graph_left + @graph_width - height[point_index] - 1
|
78
|
+
temp1 = @graph_left + (@graph_width - (data_point * @graph_width) - height[point_index])
|
79
|
+
temp2 = @graph_left + @graph_width - height[point_index]
|
92
80
|
difference = temp2 - temp1
|
81
|
+
difference = 0 if difference < 0
|
93
82
|
|
94
83
|
left_x = length[point_index]
|
95
84
|
left_y = @graph_top + (bar_width * point_index) + padding
|
96
|
-
right_x = left_x + difference
|
97
|
-
|
85
|
+
right_x = left_x + difference
|
86
|
+
right_x -= @segment_spacing if row_index != store.columns - 1
|
87
|
+
right_y = left_y + (bar_width * @bar_spacing)
|
98
88
|
length[point_index] += difference
|
99
|
-
height[point_index] += (data_point * @graph_width
|
89
|
+
height[point_index] += (data_point * @graph_width)
|
100
90
|
|
101
91
|
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
102
|
-
|
92
|
+
stack_bar_value_labels.add(bar_value_label, point_index)
|
103
93
|
|
104
94
|
# if a data point is 0 it can result in weird really thing lines
|
105
95
|
# that shouldn't even be there being drawn on top of the existing
|
106
96
|
# bar - this is bad
|
107
97
|
if data_point != 0
|
108
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
|
98
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
109
99
|
rect_renderer.render(left_x, left_y, right_x, right_y)
|
110
100
|
# Calculate center based on bar_width and current row
|
111
101
|
end
|
112
102
|
# we still need to draw the labels
|
113
103
|
# Calculate center based on bar_width and current row
|
114
|
-
label_center = left_y + bar_width / 2
|
104
|
+
label_center = left_y + (bar_width / 2.0)
|
115
105
|
draw_label(label_center, point_index)
|
116
106
|
end
|
117
107
|
end
|
118
108
|
|
119
109
|
if @show_labels_for_bar_values
|
120
|
-
|
121
|
-
|
110
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
111
|
+
stack_bar_value_labels.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
112
|
+
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
122
113
|
end
|
123
114
|
end
|
124
115
|
end
|