gruff 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +17 -4
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +26 -0
- data/README.md +10 -3
- data/gruff.gemspec +1 -1
- data/lib/gruff/accumulator_bar.rb +1 -1
- data/lib/gruff/area.rb +4 -4
- data/lib/gruff/bar.rb +28 -9
- data/lib/gruff/base.rb +109 -118
- data/lib/gruff/bezier.rb +2 -2
- data/lib/gruff/box_plot.rb +174 -0
- data/lib/gruff/bullet.rb +5 -5
- data/lib/gruff/candlestick.rb +112 -0
- data/lib/gruff/dot.rb +10 -10
- data/lib/gruff/font.rb +3 -0
- data/lib/gruff/helper/bar_conversion.rb +5 -5
- data/lib/gruff/helper/bar_value_label.rb +27 -24
- data/lib/gruff/helper/stacked_mixin.rb +3 -1
- data/lib/gruff/histogram.rb +1 -1
- data/lib/gruff/line.rb +48 -42
- data/lib/gruff/mini/legend.rb +4 -4
- data/lib/gruff/net.rb +7 -7
- data/lib/gruff/patch/string.rb +1 -0
- data/lib/gruff/pie.rb +20 -11
- data/lib/gruff/renderer/dash_line.rb +3 -2
- data/lib/gruff/renderer/dot.rb +3 -1
- data/lib/gruff/renderer/line.rb +1 -3
- data/lib/gruff/renderer/rectangle.rb +6 -2
- data/lib/gruff/scatter.rb +52 -46
- data/lib/gruff/side_bar.rb +43 -14
- data/lib/gruff/side_stacked_bar.rb +20 -27
- data/lib/gruff/spider.rb +46 -13
- data/lib/gruff/stacked_area.rb +11 -6
- data/lib/gruff/stacked_bar.rb +36 -14
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +9 -9
- metadata +4 -4
- data/lib/gruff/scene.rb +0 -208
- data/lib/gruff/store/custom_data.rb +0 -36
@@ -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(
|
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
|
data/lib/gruff/renderer/dot.rb
CHANGED
@@ -3,11 +3,12 @@
|
|
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
14
|
def render(new_x, new_y, circle_radius)
|
@@ -15,6 +16,7 @@ module Gruff
|
|
15
16
|
@renderer.draw.stroke_width(@width)
|
16
17
|
@renderer.draw.stroke(@color)
|
17
18
|
@renderer.draw.fill(@color)
|
19
|
+
@renderer.draw.fill_opacity(@opacity)
|
18
20
|
if @style.to_s == 'square'
|
19
21
|
square(new_x, new_y, circle_radius)
|
20
22
|
else
|
data/lib/gruff/renderer/line.rb
CHANGED
@@ -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
|
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.
|
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
|
data/lib/gruff/scatter.rb
CHANGED
@@ -115,15 +115,12 @@ private
|
|
115
115
|
end
|
116
116
|
|
117
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
118
|
store.norm_data.each do |data_row|
|
122
119
|
data_row.coordinates.each do |x_value, y_value|
|
123
120
|
next if y_value.nil? || x_value.nil?
|
124
121
|
|
125
122
|
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
126
|
-
new_y = @graph_top + (@graph_height - y_value * @graph_height)
|
123
|
+
new_y = @graph_top + (@graph_height - (y_value * @graph_height))
|
127
124
|
|
128
125
|
# Reset each time to avoid thin-line errors
|
129
126
|
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
@@ -134,17 +131,19 @@ private
|
|
134
131
|
end
|
135
132
|
|
136
133
|
def setup_data
|
137
|
-
# Update the global min/max values for the x data
|
138
|
-
@maximum_x_value ||= store.max_x
|
139
|
-
@minimum_x_value ||= store.min_x
|
140
|
-
|
141
|
-
super
|
142
|
-
end
|
143
|
-
|
144
|
-
def setup_drawing
|
145
134
|
# TODO: Need to get x-axis labels working. Current behavior will be to not allow.
|
146
135
|
@labels = {}
|
147
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
|
+
|
148
147
|
super
|
149
148
|
end
|
150
149
|
|
@@ -165,49 +164,24 @@ private
|
|
165
164
|
super
|
166
165
|
return if @hide_line_markers
|
167
166
|
|
168
|
-
|
169
|
-
# TODO: Do the same for larger numbers...100, 75, 50, 25
|
170
|
-
if @marker_x_count.nil?
|
171
|
-
(3..7).each do |lines|
|
172
|
-
if @x_spread % lines == 0.0
|
173
|
-
@marker_x_count = lines
|
174
|
-
break
|
175
|
-
end
|
176
|
-
end
|
177
|
-
@marker_x_count ||= 4
|
178
|
-
end
|
179
|
-
@x_increment = @x_spread > 0 ? (@x_spread / @marker_x_count) : 1
|
180
|
-
unless @disable_significant_rounding_x_axis
|
181
|
-
@x_increment = significant(@x_increment)
|
182
|
-
end
|
183
|
-
else
|
184
|
-
# TODO: Make this work for negative values
|
185
|
-
@maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment].max
|
186
|
-
@minimum_x_value = @minimum_x_value.floor
|
187
|
-
calculate_spread
|
188
|
-
normalize
|
189
|
-
|
190
|
-
@marker_x_count = (@x_spread / @x_axis_increment).to_i
|
191
|
-
@x_increment = @x_axis_increment
|
192
|
-
end
|
193
|
-
increment_x_scaled = @graph_width.to_f / (@x_spread / @x_increment)
|
167
|
+
increment_x_scaled = @graph_width / (@x_spread / x_increment)
|
194
168
|
|
195
169
|
# Draw vertical line markers and annotate with numbers
|
196
|
-
(0
|
170
|
+
(0..marker_x_count).each do |index|
|
197
171
|
# TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
|
198
172
|
if @show_vertical_markers
|
199
|
-
x = @graph_left + @graph_width - index
|
173
|
+
x = @graph_left + @graph_width - (index * increment_x_scaled)
|
200
174
|
|
201
|
-
|
202
|
-
|
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
|
203
177
|
end
|
204
178
|
|
205
179
|
unless @hide_line_numbers
|
206
|
-
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)
|
207
181
|
y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
|
208
|
-
x_offset = get_x_coord(index
|
182
|
+
x_offset = get_x_coord(index, increment_x_scaled, @graph_left)
|
209
183
|
|
210
|
-
label = x_axis_label(marker_label,
|
184
|
+
label = x_axis_label(marker_label, x_increment)
|
211
185
|
rotation = -90.0 if @use_vertical_x_labels
|
212
186
|
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
|
213
187
|
text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
|
@@ -216,6 +190,38 @@ private
|
|
216
190
|
end
|
217
191
|
|
218
192
|
def get_x_coord(x_data_point, width, offset)
|
219
|
-
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
|
220
226
|
end
|
221
227
|
end
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -36,6 +36,15 @@ 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
|
+
# Value to avoid completely overwriting the coordinate axis
|
40
|
+
AXIS_MARGIN = 0.5
|
41
|
+
private_constant :AXIS_MARGIN
|
42
|
+
|
43
|
+
def initialize(*)
|
44
|
+
super
|
45
|
+
@has_left_labels = true
|
46
|
+
end
|
47
|
+
|
39
48
|
# With Side Bars use the data label for the marker value to the left of the bar.
|
40
49
|
# @deprecated
|
41
50
|
def use_data_label=(_value)
|
@@ -51,7 +60,6 @@ private
|
|
51
60
|
@label_formatting = nil
|
52
61
|
@show_labels_for_bar_values = false
|
53
62
|
@hide_labels = false
|
54
|
-
@has_left_labels = true
|
55
63
|
end
|
56
64
|
|
57
65
|
def hide_labels?
|
@@ -59,20 +67,39 @@ private
|
|
59
67
|
end
|
60
68
|
|
61
69
|
def hide_left_label_area?
|
62
|
-
hide_labels?
|
70
|
+
hide_labels? && @y_axis_label.nil?
|
63
71
|
end
|
64
72
|
|
65
73
|
def hide_bottom_label_area?
|
66
|
-
@hide_line_markers
|
74
|
+
@hide_line_markers && @x_axis_label.nil? && @legend_at_bottom == false
|
67
75
|
end
|
68
76
|
|
69
|
-
|
70
|
-
|
77
|
+
def setup_graph_measurements
|
78
|
+
super
|
79
|
+
return if @hide_line_markers
|
80
|
+
|
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
|
71
98
|
|
72
99
|
def draw_graph
|
73
100
|
# Setup spacing.
|
74
101
|
#
|
75
|
-
bars_width = (@graph_height - calculate_spacing) / column_count
|
102
|
+
bars_width = (@graph_height - calculate_spacing) / column_count
|
76
103
|
bar_width = bars_width / store.length
|
77
104
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
78
105
|
|
@@ -82,12 +109,14 @@ private
|
|
82
109
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
83
110
|
)
|
84
111
|
|
112
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
113
|
+
|
85
114
|
store.norm_data.each_with_index do |data_row, row_index|
|
86
115
|
data_row.points.each_with_index do |data_point, point_index|
|
87
116
|
group_spacing = @group_spacing * @scale * point_index
|
88
117
|
|
89
118
|
left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
|
90
|
-
right_y = left_y + bar_width * @bar_spacing
|
119
|
+
right_y = left_y + (bar_width * @bar_spacing)
|
91
120
|
|
92
121
|
left_x, right_x = conversion.get_top_bottom_scaled(data_point).sort
|
93
122
|
|
@@ -95,14 +124,14 @@ private
|
|
95
124
|
rect_renderer.render(left_x + AXIS_MARGIN, left_y, right_x + AXIS_MARGIN, right_y)
|
96
125
|
|
97
126
|
# Calculate center based on bar_width and current row
|
98
|
-
label_center = left_y + bars_width / 2
|
127
|
+
label_center = left_y + (bars_width / 2.0)
|
99
128
|
|
100
129
|
# Subtract half a bar width to center left if requested
|
101
130
|
draw_label(label_center, point_index)
|
102
131
|
if @show_labels_for_bar_values
|
103
132
|
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
104
|
-
bar_value_label.prepare_rendering(@label_formatting,
|
105
|
-
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)
|
106
135
|
end
|
107
136
|
end
|
108
137
|
end
|
@@ -118,17 +147,17 @@ private
|
|
118
147
|
number_of_lines = 1 if number_of_lines == 0
|
119
148
|
|
120
149
|
# TODO: Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
|
121
|
-
increment = significant(@spread
|
150
|
+
increment = significant(@spread / number_of_lines)
|
122
151
|
(0..number_of_lines).each do |index|
|
123
152
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
124
153
|
x = @graph_right - (line_diff * index) - 1
|
125
154
|
|
126
|
-
|
127
|
-
|
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
|
128
157
|
|
129
158
|
unless @hide_line_numbers
|
130
159
|
diff = index - number_of_lines
|
131
|
-
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)
|
132
161
|
label = x_axis_label(marker_label, @increment)
|
133
162
|
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font)
|
134
163
|
text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + LABEL_MARGIN, Magick::CenterGravity)
|
@@ -39,6 +39,11 @@ 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 initialize(*)
|
43
|
+
super
|
44
|
+
@has_left_labels = true
|
45
|
+
end
|
46
|
+
|
42
47
|
private
|
43
48
|
|
44
49
|
def initialize_attributes
|
@@ -48,7 +53,7 @@ private
|
|
48
53
|
@label_formatting = nil
|
49
54
|
@show_labels_for_bar_values = false
|
50
55
|
@hide_labels = false
|
51
|
-
@
|
56
|
+
@minimum_value = 0.0
|
52
57
|
end
|
53
58
|
|
54
59
|
def setup_data
|
@@ -56,48 +61,35 @@ private
|
|
56
61
|
super
|
57
62
|
end
|
58
63
|
|
59
|
-
def hide_labels?
|
60
|
-
@hide_labels
|
61
|
-
end
|
62
|
-
|
63
|
-
def hide_left_label_area?
|
64
|
-
hide_labels?
|
65
|
-
end
|
66
|
-
|
67
|
-
def hide_bottom_label_area?
|
68
|
-
@hide_line_markers
|
69
|
-
end
|
70
|
-
|
71
64
|
def draw_graph
|
72
65
|
# Setup spacing.
|
73
66
|
#
|
74
67
|
# Columns sit stacked.
|
75
|
-
bar_width = @graph_height / column_count
|
68
|
+
bar_width = @graph_height / column_count
|
76
69
|
height = Array.new(column_count, 0)
|
77
70
|
length = Array.new(column_count, @graph_left)
|
78
71
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
79
|
-
|
72
|
+
stack_bar_value_labels = Gruff::BarValueLabel::StackedBar.new
|
80
73
|
|
81
74
|
store.norm_data.each_with_index do |data_row, row_index|
|
82
75
|
data_row.points.each_with_index do |data_point, point_index|
|
83
76
|
## using the original calculations from the stacked bar chart to get the difference between
|
84
77
|
## part of the bart chart we wish to stack.
|
85
|
-
temp1 = @graph_left + (@graph_width -
|
86
|
-
|
87
|
-
height[point_index]) + 1
|
88
|
-
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]
|
89
80
|
difference = temp2 - temp1
|
90
|
-
difference = 0 if
|
81
|
+
difference = 0 if difference < 0
|
91
82
|
|
92
83
|
left_x = length[point_index]
|
93
84
|
left_y = @graph_top + (bar_width * point_index) + padding
|
94
|
-
right_x = left_x + difference
|
95
|
-
|
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)
|
96
88
|
length[point_index] += difference
|
97
|
-
height[point_index] += (data_point * @graph_width
|
89
|
+
height[point_index] += (data_point * @graph_width)
|
98
90
|
|
99
91
|
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
100
|
-
|
92
|
+
stack_bar_value_labels.add(bar_value_label, point_index)
|
101
93
|
|
102
94
|
# if a data point is 0 it can result in weird really thing lines
|
103
95
|
# that shouldn't even be there being drawn on top of the existing
|
@@ -109,14 +101,15 @@ private
|
|
109
101
|
end
|
110
102
|
# we still need to draw the labels
|
111
103
|
# Calculate center based on bar_width and current row
|
112
|
-
label_center = left_y + bar_width / 2
|
104
|
+
label_center = left_y + (bar_width / 2.0)
|
113
105
|
draw_label(label_center, point_index)
|
114
106
|
end
|
115
107
|
end
|
116
108
|
|
117
109
|
if @show_labels_for_bar_values
|
118
|
-
|
119
|
-
|
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)
|
120
113
|
end
|
121
114
|
end
|
122
115
|
end
|
data/lib/gruff/spider.rb
CHANGED
@@ -19,6 +19,11 @@ class Gruff::Spider < Gruff::Base
|
|
19
19
|
attr_writer :hide_axes
|
20
20
|
attr_writer :rotation
|
21
21
|
|
22
|
+
def initialize(max_value, target_width = 800)
|
23
|
+
super(target_width)
|
24
|
+
@max_value = max_value
|
25
|
+
end
|
26
|
+
|
22
27
|
def transparent_background=(value)
|
23
28
|
renderer.transparent_background(@columns, @rows) if value
|
24
29
|
end
|
@@ -27,11 +32,6 @@ class Gruff::Spider < Gruff::Base
|
|
27
32
|
@hide_title = @hide_text = value
|
28
33
|
end
|
29
34
|
|
30
|
-
def initialize(max_value, target_width = 800)
|
31
|
-
super(target_width)
|
32
|
-
@max_value = max_value
|
33
|
-
end
|
34
|
-
|
35
35
|
private
|
36
36
|
|
37
37
|
def initialize_attributes
|
@@ -46,6 +46,24 @@ private
|
|
46
46
|
@hide_line_markers.freeze
|
47
47
|
end
|
48
48
|
|
49
|
+
def setup_graph_measurements
|
50
|
+
super
|
51
|
+
|
52
|
+
@graph_left += LABEL_MARGIN
|
53
|
+
@graph_top += LABEL_MARGIN
|
54
|
+
@graph_right -= LABEL_MARGIN
|
55
|
+
@graph_bottom -= LABEL_MARGIN
|
56
|
+
|
57
|
+
@graph_width = @graph_right - @graph_left
|
58
|
+
@graph_height = @graph_bottom - @graph_top
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup_data
|
62
|
+
raise(Gruff::IncorrectNumberOfDatasetsException, 'Requires 3 or more data sets') if store.length < 3
|
63
|
+
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
49
67
|
def draw_graph
|
50
68
|
# Setup basic positioning
|
51
69
|
radius = @graph_height / 2.0
|
@@ -68,19 +86,34 @@ private
|
|
68
86
|
end
|
69
87
|
|
70
88
|
def draw_label(center_x, center_y, angle, radius, amount)
|
71
|
-
|
72
|
-
|
73
|
-
|
89
|
+
degree = rad2deg(angle)
|
90
|
+
metrics = text_metrics(@marker_font, amount)
|
91
|
+
|
92
|
+
r_offset = LABEL_MARGIN # The distance out from the center of the pie to get point
|
93
|
+
x_offset = center_x # The label points need to be tweaked slightly
|
94
|
+
|
95
|
+
x_offset -= begin
|
96
|
+
case degree
|
97
|
+
when 0..45, 315..360
|
98
|
+
0
|
99
|
+
when 135..225
|
100
|
+
metrics.width
|
101
|
+
else
|
102
|
+
metrics.width / 2
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
y_offset = center_y - (metrics.height / 2.0) # This one doesn't though
|
74
107
|
x = x_offset + ((radius + r_offset) * Math.cos(angle))
|
75
108
|
y = y_offset + ((radius + r_offset) * Math.sin(angle))
|
76
109
|
|
77
|
-
draw_label_at(
|
110
|
+
draw_label_at(metrics.width, metrics.height, x, y, amount, Magick::CenterGravity)
|
78
111
|
end
|
79
112
|
|
80
113
|
def draw_axes(center_x, center_y, radius, additive_angle, line_color = nil)
|
81
114
|
return if @hide_axes
|
82
115
|
|
83
|
-
current_angle = @rotation
|
116
|
+
current_angle = deg2rad(@rotation)
|
84
117
|
|
85
118
|
store.data.each do |data_row|
|
86
119
|
x_offset = radius * Math.cos(current_angle)
|
@@ -97,11 +130,11 @@ private
|
|
97
130
|
|
98
131
|
def draw_polygon(center_x, center_y, additive_angle, color = nil)
|
99
132
|
points = []
|
100
|
-
current_angle = @rotation
|
133
|
+
current_angle = deg2rad(@rotation)
|
101
134
|
|
102
135
|
store.data.each do |data_row|
|
103
|
-
points << center_x + normalize_points(data_row.points.first) * Math.cos(current_angle)
|
104
|
-
points << center_y + normalize_points(data_row.points.first) * Math.sin(current_angle)
|
136
|
+
points << (center_x + (normalize_points(data_row.points.first) * Math.cos(current_angle)))
|
137
|
+
points << (center_y + (normalize_points(data_row.points.first) * Math.sin(current_angle)))
|
105
138
|
current_angle += additive_angle
|
106
139
|
end
|
107
140
|
|
data/lib/gruff/stacked_area.rb
CHANGED
@@ -20,13 +20,18 @@ class Gruff::StackedArea < Gruff::Base
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
+
def initialize_attributes
|
24
|
+
super
|
25
|
+
@minimum_value = 0.0
|
26
|
+
end
|
27
|
+
|
23
28
|
def setup_data
|
24
29
|
calculate_maximum_by_stack
|
25
30
|
super
|
26
31
|
end
|
27
32
|
|
28
33
|
def draw_graph
|
29
|
-
x_increment = @graph_width / (column_count - 1)
|
34
|
+
x_increment = @graph_width / (column_count - 1)
|
30
35
|
|
31
36
|
height = Array.new(column_count, 0)
|
32
37
|
|
@@ -38,7 +43,7 @@ private
|
|
38
43
|
data_row.points.each_with_index do |data_point, index|
|
39
44
|
# Use incremented x and scaled y
|
40
45
|
new_x = @graph_left + (x_increment * index)
|
41
|
-
new_y = @graph_top + (@graph_height - data_point * @graph_height - height[index])
|
46
|
+
new_y = @graph_top + (@graph_height - (data_point * @graph_height) - height[index])
|
42
47
|
|
43
48
|
height[index] += (data_point * @graph_height)
|
44
49
|
|
@@ -50,15 +55,15 @@ private
|
|
50
55
|
|
51
56
|
poly_points = data_points.dup
|
52
57
|
if prev_data_points
|
53
|
-
(prev_data_points.length / 2 - 1).downto(0) do |i|
|
58
|
+
((prev_data_points.length / 2) - 1).downto(0) do |i|
|
54
59
|
poly_points << prev_data_points[2 * i]
|
55
|
-
poly_points << prev_data_points[2 * i + 1]
|
60
|
+
poly_points << prev_data_points[(2 * i) + 1]
|
56
61
|
end
|
57
62
|
else
|
58
63
|
poly_points << @graph_right
|
59
|
-
poly_points << @graph_bottom - 1
|
64
|
+
poly_points << (@graph_bottom - 1)
|
60
65
|
poly_points << @graph_left
|
61
|
-
poly_points << @graph_bottom - 1
|
66
|
+
poly_points << (@graph_bottom - 1)
|
62
67
|
end
|
63
68
|
poly_points << data_points[0]
|
64
69
|
poly_points << data_points[1]
|