gruff 0.16.0-java → 0.19.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/.devcontainer/devcontainer.json +26 -0
- data/.github/workflows/ci.yml +9 -6
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/CHANGELOG.md +32 -0
- data/README.md +7 -3
- data/gruff.gemspec +2 -4
- data/lib/gruff/area.rb +3 -1
- data/lib/gruff/bar.rb +26 -24
- data/lib/gruff/base.rb +214 -93
- data/lib/gruff/bezier.rb +7 -8
- data/lib/gruff/{box_plot.rb → box.rb} +12 -6
- data/lib/gruff/bubble.rb +99 -0
- data/lib/gruff/candlestick.rb +22 -14
- data/lib/gruff/dot.rb +5 -6
- data/lib/gruff/helper/bar_conversion.rb +1 -5
- data/lib/gruff/helper/bar_mixin.rb +25 -0
- data/lib/gruff/helper/bar_value_label.rb +0 -22
- data/lib/gruff/helper/stacked_mixin.rb +16 -0
- data/lib/gruff/histogram.rb +8 -5
- data/lib/gruff/line.rb +47 -27
- data/lib/gruff/mini/bar.rb +1 -1
- data/lib/gruff/mini/legend.rb +13 -9
- data/lib/gruff/mini/pie.rb +2 -2
- data/lib/gruff/net.rb +26 -13
- data/lib/gruff/pie.rb +7 -2
- data/lib/gruff/renderer/bezier.rb +1 -1
- data/lib/gruff/renderer/circle.rb +5 -3
- data/lib/gruff/renderer/dash_line.rb +1 -1
- data/lib/gruff/renderer/dot.rb +26 -15
- data/lib/gruff/renderer/line.rb +1 -1
- data/lib/gruff/renderer/polygon.rb +1 -1
- data/lib/gruff/renderer/polyline.rb +4 -2
- data/lib/gruff/renderer/renderer.rb +0 -4
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +52 -55
- data/lib/gruff/side_bar.rb +28 -24
- data/lib/gruff/side_stacked_bar.rb +36 -41
- data/lib/gruff/spider.rb +7 -2
- data/lib/gruff/stacked_area.rb +8 -3
- data/lib/gruff/stacked_bar.rb +48 -40
- data/lib/gruff/store/xy_data.rb +8 -9
- data/lib/gruff/store/xy_pointsizes_data.rb +60 -0
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +3 -4
- metadata +9 -5
@@ -11,8 +11,8 @@ module Gruff
|
|
11
11
|
|
12
12
|
def render(points)
|
13
13
|
@renderer.draw.push
|
14
|
-
@renderer.draw.stroke(@color)
|
15
14
|
@renderer.draw.stroke_width(@width)
|
15
|
+
@renderer.draw.stroke(@color)
|
16
16
|
@renderer.draw.fill_opacity(0.0)
|
17
17
|
@renderer.draw.bezier(*points)
|
18
18
|
@renderer.draw.pop
|
@@ -3,17 +3,19 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Circle
|
6
|
-
def initialize(renderer, color:, width: 1.0)
|
6
|
+
def initialize(renderer, color:, width: 1.0, opacity: 1.0)
|
7
7
|
@renderer = renderer
|
8
8
|
@color = color
|
9
9
|
@width = width
|
10
|
+
@opacity = opacity
|
10
11
|
end
|
11
12
|
|
12
13
|
def render(origin_x, origin_y, perim_x, perim_y)
|
13
14
|
@renderer.draw.push
|
14
|
-
@renderer.draw.fill(@color)
|
15
|
-
@renderer.draw.stroke(@color)
|
16
15
|
@renderer.draw.stroke_width(@width)
|
16
|
+
@renderer.draw.stroke(@color)
|
17
|
+
@renderer.draw.fill_opacity(@opacity)
|
18
|
+
@renderer.draw.fill(@color)
|
17
19
|
@renderer.draw.circle(origin_x, origin_y, perim_x, perim_y)
|
18
20
|
@renderer.draw.pop
|
19
21
|
end
|
@@ -13,9 +13,9 @@ module Gruff
|
|
13
13
|
def render(start_x, start_y, end_x, end_y)
|
14
14
|
@renderer.draw.push
|
15
15
|
@renderer.draw.stroke_color(@color)
|
16
|
-
@renderer.draw.fill_opacity(0.0)
|
17
16
|
@renderer.draw.stroke_dasharray(*@dasharray)
|
18
17
|
@renderer.draw.stroke_width(@width)
|
18
|
+
@renderer.draw.fill_opacity(0.0)
|
19
19
|
@renderer.draw.line(start_x, start_y, end_x, end_y)
|
20
20
|
@renderer.draw.pop
|
21
21
|
end
|
data/lib/gruff/renderer/dot.rb
CHANGED
@@ -11,31 +11,42 @@ module Gruff
|
|
11
11
|
@opacity = opacity
|
12
12
|
end
|
13
13
|
|
14
|
-
def render(new_x, new_y,
|
15
|
-
|
14
|
+
def render(new_x, new_y, radius)
|
15
|
+
@renderer.draw.push
|
16
16
|
@renderer.draw.stroke_width(@width)
|
17
17
|
@renderer.draw.stroke(@color)
|
18
|
-
@renderer.draw.fill(@color)
|
19
18
|
@renderer.draw.fill_opacity(@opacity)
|
20
|
-
|
21
|
-
|
19
|
+
@renderer.draw.fill(@color)
|
20
|
+
case @style.to_sym
|
21
|
+
when :square
|
22
|
+
square(new_x, new_y, radius)
|
23
|
+
when :diamond
|
24
|
+
diamond(new_x, new_y, radius)
|
22
25
|
else
|
23
|
-
circle(new_x, new_y,
|
26
|
+
circle(new_x, new_y, radius)
|
24
27
|
end
|
25
|
-
|
28
|
+
@renderer.draw.pop
|
26
29
|
end
|
27
30
|
|
28
|
-
def circle(new_x, new_y,
|
29
|
-
@renderer.draw.circle(new_x, new_y, new_x -
|
31
|
+
def circle(new_x, new_y, radius)
|
32
|
+
@renderer.draw.circle(new_x, new_y, new_x - radius, new_y)
|
30
33
|
end
|
31
34
|
|
32
|
-
def square(new_x, new_y,
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
corner4 = new_y + offset
|
35
|
+
def square(new_x, new_y, radius)
|
36
|
+
corner1 = new_x - radius
|
37
|
+
corner2 = new_y - radius
|
38
|
+
corner3 = new_x + radius
|
39
|
+
corner4 = new_y + radius
|
38
40
|
@renderer.draw.rectangle(corner1, corner2, corner3, corner4)
|
39
41
|
end
|
42
|
+
|
43
|
+
def diamond(new_x, new_y, radius)
|
44
|
+
polygon = []
|
45
|
+
polygon += [new_x - radius, new_y]
|
46
|
+
polygon += [new_x, new_y + radius]
|
47
|
+
polygon += [new_x + radius, new_y]
|
48
|
+
polygon += [new_x, new_y - radius]
|
49
|
+
@renderer.draw.polygon(*polygon)
|
50
|
+
end
|
40
51
|
end
|
41
52
|
end
|
data/lib/gruff/renderer/line.rb
CHANGED
@@ -30,9 +30,9 @@ module Gruff
|
|
30
30
|
end
|
31
31
|
|
32
32
|
@renderer.draw.push
|
33
|
+
@renderer.draw.stroke_width(@width) if @width
|
33
34
|
@renderer.draw.stroke(color)
|
34
35
|
@renderer.draw.fill(color)
|
35
|
-
@renderer.draw.stroke_width(@width) if @width
|
36
36
|
@renderer.draw.line(start_x, start_y, end_x, end_y)
|
37
37
|
@renderer.draw.pop
|
38
38
|
end
|
@@ -14,8 +14,8 @@ module Gruff
|
|
14
14
|
@renderer.draw.push
|
15
15
|
@renderer.draw.stroke_width(@width)
|
16
16
|
@renderer.draw.stroke(@color)
|
17
|
-
@renderer.draw.fill(@color)
|
18
17
|
@renderer.draw.fill_opacity(@opacity)
|
18
|
+
@renderer.draw.fill(@color)
|
19
19
|
@renderer.draw.polygon(*points)
|
20
20
|
@renderer.draw.pop
|
21
21
|
end
|
@@ -3,17 +3,19 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Polyline
|
6
|
-
def initialize(renderer, color:, width:)
|
6
|
+
def initialize(renderer, color:, width: 1.0, linejoin: 'bevel')
|
7
7
|
@renderer = renderer
|
8
8
|
@color = color
|
9
9
|
@width = width
|
10
|
+
@linejoin = linejoin
|
10
11
|
end
|
11
12
|
|
12
13
|
def render(points)
|
13
14
|
@renderer.draw.push
|
15
|
+
@renderer.draw.stroke_linejoin(@linejoin)
|
16
|
+
@renderer.draw.stroke_width(@width)
|
14
17
|
@renderer.draw.stroke(@color)
|
15
18
|
@renderer.draw.fill('transparent')
|
16
|
-
@renderer.draw.stroke_width(@width)
|
17
19
|
@renderer.draw.polyline(*points)
|
18
20
|
@renderer.draw.pop
|
19
21
|
end
|
data/lib/gruff/renderer/text.rb
CHANGED
@@ -25,6 +25,7 @@ module Gruff
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def render(width, height, x, y, gravity = Magick::NorthGravity)
|
28
|
+
@renderer.draw.push
|
28
29
|
@renderer.draw.rotation = @rotation if @rotation
|
29
30
|
@renderer.draw.fill = @font.color
|
30
31
|
@renderer.draw.stroke = 'transparent'
|
@@ -37,9 +38,11 @@ module Gruff
|
|
37
38
|
x, y,
|
38
39
|
@text, @renderer.scale)
|
39
40
|
@renderer.draw.rotation = -@rotation if @rotation
|
41
|
+
@renderer.draw.pop
|
40
42
|
end
|
41
43
|
|
42
44
|
def metrics
|
45
|
+
@renderer.draw.push
|
43
46
|
@renderer.draw.font = @font.file_path
|
44
47
|
@renderer.draw.font_weight = @font.weight
|
45
48
|
@renderer.draw.pointsize = @font.size
|
@@ -50,7 +53,10 @@ module Gruff
|
|
50
53
|
# So, in here, it just escape % in order to avoid SEGV.
|
51
54
|
text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
52
55
|
|
53
|
-
@renderer.draw.get_type_metrics(@renderer.image, text)
|
56
|
+
metrics = @renderer.draw.get_type_metrics(@renderer.image, text)
|
57
|
+
@renderer.draw.pop
|
58
|
+
|
59
|
+
metrics
|
54
60
|
end
|
55
61
|
end
|
56
62
|
end
|
data/lib/gruff/scatter.rb
CHANGED
@@ -24,24 +24,35 @@ class Gruff::Scatter < Gruff::Base
|
|
24
24
|
attr_writer :circle_radius
|
25
25
|
attr_writer :stroke_width
|
26
26
|
|
27
|
-
# Allow disabling the significant rounding when labeling the X axis.
|
28
|
-
# This is useful when working with a small range of high values (for example, a date range of months, while seconds as units).
|
29
|
-
attr_writer :disable_significant_rounding_x_axis
|
30
|
-
|
31
27
|
# Allow for vertical marker lines.
|
32
28
|
attr_writer :show_vertical_markers
|
33
29
|
|
34
|
-
# Allow using vertical labels in the X axis (and setting the label margin).
|
35
|
-
attr_writer :x_label_margin
|
36
|
-
attr_writer :use_vertical_x_labels
|
37
|
-
|
38
30
|
# Allow enabling vertical lines. When you have a lot of data, they can work great.
|
39
|
-
# @deprecated Please use
|
31
|
+
# @deprecated Please use {#show_vertical_markers=} instead.
|
40
32
|
def enable_vertical_line_markers=(value)
|
41
33
|
warn '#enable_vertical_line_markers= is deprecated. Please use `show_vertical_markers` attribute instead'
|
42
34
|
@show_vertical_markers = value
|
43
35
|
end
|
44
36
|
|
37
|
+
# Allow using vertical labels in the X axis.
|
38
|
+
# @deprecated Please use {Gruff::Base#label_rotation=} instead.
|
39
|
+
def use_vertical_x_labels=(_value)
|
40
|
+
warn '#use_vertical_x_labels= is deprecated. It is no longer effective. Please use `#label_rotation=` instead'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Allow using vertical labels in the X axis (and setting the label margin).
|
44
|
+
# @deprecated
|
45
|
+
def x_label_margin=(_value)
|
46
|
+
warn '#x_label_margin= is deprecated. It is no longer effective.'
|
47
|
+
end
|
48
|
+
|
49
|
+
# Allow disabling the significant rounding when labeling the X axis.
|
50
|
+
# This is useful when working with a small range of high values (for example, a date range of months, while seconds as units).
|
51
|
+
# @deprecated
|
52
|
+
def disable_significant_rounding_x_axis=(_value)
|
53
|
+
warn '#disable_significant_rounding_x_axis= is deprecated. It is no longer effective.'
|
54
|
+
end
|
55
|
+
|
45
56
|
# The first parameter is the name of the dataset. The next two are the
|
46
57
|
# x and y axis data points contain in their own array in that respective
|
47
58
|
# order. The final parameter is the color.
|
@@ -55,11 +66,10 @@ class Gruff::Scatter < Gruff::Base
|
|
55
66
|
# @note If you want to use a preset theme, you must set it before calling {#data}.
|
56
67
|
#
|
57
68
|
# @param name [String, Symbol] containing the name of the dataset.
|
58
|
-
# @param x_data_points [Array] An Array of
|
59
|
-
# @param y_data_points [Array] An Array of
|
69
|
+
# @param x_data_points [Array] An Array of x-axis data points.
|
70
|
+
# @param y_data_points [Array] An Array of y-axis data points.
|
60
71
|
# @param color [String] The hex string for the color of the dataset. Defaults to nil.
|
61
72
|
#
|
62
|
-
#
|
63
73
|
# @raise [ArgumentError] Data points contain nil values.
|
64
74
|
# This error will get raised if either the x or y axis data points array
|
65
75
|
# contains a +nil+ value. The graph will not make an assumption
|
@@ -88,7 +98,7 @@ class Gruff::Scatter < Gruff::Base
|
|
88
98
|
raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
|
89
99
|
|
90
100
|
# Call the existing data routine for the x/y axis data
|
91
|
-
store.add(name, y_data_points, color
|
101
|
+
store.add(name, x_data_points, y_data_points, color)
|
92
102
|
end
|
93
103
|
|
94
104
|
alias dataxy data
|
@@ -102,32 +112,16 @@ private
|
|
102
112
|
def initialize_attributes
|
103
113
|
super
|
104
114
|
|
105
|
-
@baseline_x_color = @baseline_y_color = 'red'
|
106
|
-
@baseline_x_value = @baseline_y_value = nil
|
107
115
|
@circle_radius = nil
|
108
|
-
@disable_significant_rounding_x_axis = false
|
109
116
|
@show_vertical_markers = false
|
110
117
|
@marker_x_count = nil
|
111
118
|
@maximum_x_value = @minimum_x_value = nil
|
112
119
|
@stroke_width = nil
|
113
|
-
@use_vertical_x_labels = false
|
114
|
-
@x_label_margin = nil
|
115
120
|
end
|
116
121
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
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
|
122
|
+
def setup_drawing
|
123
|
+
@center_labels_over_point = false
|
124
|
+
super
|
131
125
|
end
|
132
126
|
|
133
127
|
def setup_data
|
@@ -147,10 +141,26 @@ private
|
|
147
141
|
super
|
148
142
|
end
|
149
143
|
|
144
|
+
def draw_graph
|
145
|
+
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4.0), 5.0)
|
146
|
+
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
147
|
+
|
148
|
+
store.norm_data.each do |data_row|
|
149
|
+
data_row.coordinates.each do |x_value, y_value|
|
150
|
+
next if y_value.nil? || x_value.nil?
|
151
|
+
|
152
|
+
new_x = @graph_left + (x_value * @graph_width)
|
153
|
+
new_y = @graph_bottom - (y_value * @graph_height)
|
154
|
+
|
155
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
150
160
|
def calculate_spread
|
151
161
|
super
|
152
162
|
@x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
|
153
|
-
@x_spread = @x_spread > 0 ? @x_spread : 1
|
163
|
+
@x_spread = @x_spread > 0 ? @x_spread : 1.0
|
154
164
|
end
|
155
165
|
|
156
166
|
def normalize
|
@@ -164,35 +174,27 @@ private
|
|
164
174
|
super
|
165
175
|
return if @hide_line_markers
|
166
176
|
|
167
|
-
increment_x_scaled = @graph_width / (@x_spread / x_increment)
|
177
|
+
increment_x_scaled = (@graph_width / (@x_spread / x_increment)).to_f
|
168
178
|
|
169
179
|
# Draw vertical line markers and annotate with numbers
|
170
180
|
(0..marker_x_count).each do |index|
|
171
181
|
# TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
|
172
182
|
if @show_vertical_markers
|
173
|
-
|
174
|
-
|
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
|
183
|
+
draw_marker_vertical_line(@graph_left + (index * increment_x_scaled))
|
177
184
|
end
|
178
185
|
|
179
186
|
unless @hide_line_numbers
|
180
187
|
marker_label = (BigDecimal(index.to_s) * BigDecimal(x_increment.to_s)) + BigDecimal(@minimum_x_value.to_s)
|
181
|
-
y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
|
182
|
-
x_offset = get_x_coord(index, increment_x_scaled, @graph_left)
|
183
|
-
|
184
188
|
label = x_axis_label(marker_label, x_increment)
|
185
|
-
|
186
|
-
|
187
|
-
|
189
|
+
x = @graph_left + (increment_x_scaled * index)
|
190
|
+
y = @graph_bottom
|
191
|
+
x_offset, y_offset = calculate_label_offset(@marker_font, label, LABEL_MARGIN, @label_rotation)
|
192
|
+
|
193
|
+
draw_label_at(1.0, 1.0, x + x_offset, y + y_offset, label, rotation: @label_rotation)
|
188
194
|
end
|
189
195
|
end
|
190
196
|
end
|
191
197
|
|
192
|
-
def get_x_coord(x_data_point, width, offset)
|
193
|
-
(x_data_point * width) + offset
|
194
|
-
end
|
195
|
-
|
196
198
|
def marker_x_count
|
197
199
|
# TODO: Do the same for larger numbers...100, 75, 50, 25
|
198
200
|
@marker_x_count ||= begin
|
@@ -213,15 +215,10 @@ private
|
|
213
215
|
def x_increment
|
214
216
|
@x_increment ||= begin
|
215
217
|
if @x_axis_increment.nil?
|
216
|
-
|
217
|
-
unless @disable_significant_rounding_x_axis
|
218
|
-
increment = significant(increment)
|
219
|
-
end
|
218
|
+
@x_spread > 0 ? significant(@x_spread / marker_x_count) : 1.0
|
220
219
|
else
|
221
|
-
|
220
|
+
@x_axis_increment.to_f
|
222
221
|
end
|
223
|
-
|
224
|
-
increment
|
225
222
|
end
|
226
223
|
end
|
227
224
|
end
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/bar_mixin'
|
4
|
+
|
3
5
|
# Graph with individual horizontal bars instead of vertical bars.
|
4
6
|
#
|
5
7
|
# Here's how to set up a Gruff::SideBar.
|
@@ -19,6 +21,8 @@
|
|
19
21
|
# g.write('sidebar.png')
|
20
22
|
#
|
21
23
|
class Gruff::SideBar < Gruff::Base
|
24
|
+
include BarMixin
|
25
|
+
|
22
26
|
# Spacing factor applied between bars.
|
23
27
|
attr_writer :bar_spacing
|
24
28
|
|
@@ -79,8 +83,6 @@ private
|
|
79
83
|
return if @hide_line_markers
|
80
84
|
|
81
85
|
if @show_labels_for_bar_values
|
82
|
-
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
83
|
-
|
84
86
|
if maximum_value >= 0
|
85
87
|
_, metrics = Gruff::BarValueLabel.metrics(maximum_value, @label_formatting, proc_text_metrics)
|
86
88
|
@graph_right -= metrics.width
|
@@ -109,32 +111,32 @@ private
|
|
109
111
|
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
110
112
|
)
|
111
113
|
|
112
|
-
|
114
|
+
group_left_y = @graph_top
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
|
116
|
+
normalized_group_bars.each_with_index do |group_bars, group_index|
|
117
|
+
right_y = 0
|
118
|
+
group_bars.each_with_index do |bar, index|
|
119
|
+
left_y = group_left_y + (bar_width * index) + padding
|
119
120
|
right_y = left_y + (bar_width * @bar_spacing)
|
120
121
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
# Calculate center based on bar_width and current row
|
127
|
-
label_center = left_y + (bars_width / 2.0)
|
122
|
+
bottom_x, top_x = conversion.get_top_bottom_scaled(bar.point).sort
|
123
|
+
if bar.point != 0
|
124
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: bar.color)
|
125
|
+
rect_renderer.render(bottom_x + AXIS_MARGIN, left_y, top_x, right_y)
|
126
|
+
end
|
128
127
|
|
129
|
-
|
130
|
-
|
131
|
-
if @show_labels_for_bar_values
|
132
|
-
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
128
|
+
if @show_labels_for_bar_values && bar.value
|
129
|
+
bar_value_label = Gruff::BarValueLabel::SideBar.new([bottom_x, left_y, top_x, right_y], bar.value)
|
133
130
|
bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
134
131
|
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
135
132
|
end
|
136
133
|
end
|
137
134
|
end
|
135
|
+
|
136
|
+
label_center = group_left_y + (bars_width / 2.0)
|
137
|
+
draw_label(label_center, group_index)
|
138
|
+
|
139
|
+
group_left_y = right_y + padding + @group_spacing
|
138
140
|
end
|
139
141
|
end
|
140
142
|
|
@@ -151,9 +153,7 @@ private
|
|
151
153
|
(0..number_of_lines).each do |index|
|
152
154
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
153
155
|
x = @graph_right - (line_diff * index) - 1
|
154
|
-
|
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
|
156
|
+
draw_marker_vertical_line(x)
|
157
157
|
|
158
158
|
unless @hide_line_numbers
|
159
159
|
diff = index - number_of_lines
|
@@ -170,11 +170,15 @@ private
|
|
170
170
|
|
171
171
|
def draw_label(y_offset, index)
|
172
172
|
draw_unique_label(index) do
|
173
|
-
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
|
173
|
+
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], gravity: Magick::EastGravity)
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
177
177
|
def calculate_spacing
|
178
|
-
@
|
178
|
+
@group_spacing * (column_count - 1)
|
179
|
+
end
|
180
|
+
|
181
|
+
def proc_text_metrics
|
182
|
+
->(text) { text_metrics(@marker_font, text) }
|
179
183
|
end
|
180
184
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/stacked_mixin'
|
4
|
+
|
3
5
|
#
|
4
6
|
# New gruff graph type added to enable sideways stacking bar charts
|
5
7
|
# (basically looks like a x/y flip of a standard stacking bar chart)
|
@@ -66,50 +68,43 @@ private
|
|
66
68
|
#
|
67
69
|
# Columns sit stacked.
|
68
70
|
bar_width = @graph_height / column_count
|
69
|
-
height = Array.new(column_count, 0)
|
70
|
-
length = Array.new(column_count, @graph_left)
|
71
71
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
99
|
-
rect_renderer.render(left_x, left_y, right_x, right_y)
|
100
|
-
# Calculate center based on bar_width and current row
|
101
|
-
end
|
102
|
-
# we still need to draw the labels
|
103
|
-
# Calculate center based on bar_width and current row
|
104
|
-
label_center = left_y + (bar_width / 2.0)
|
105
|
-
draw_label(label_center, point_index)
|
72
|
+
|
73
|
+
# Setup the BarConversion Object
|
74
|
+
conversion = Gruff::BarConversion.new(
|
75
|
+
top: @graph_right, bottom: @graph_left,
|
76
|
+
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
77
|
+
)
|
78
|
+
|
79
|
+
proc_text_metrics = ->(text) { text_metrics(@marker_font, text) }
|
80
|
+
|
81
|
+
normalized_stacked_bars.each_with_index do |stacked_bars, stacked_index|
|
82
|
+
total = 0
|
83
|
+
left_y = @graph_top + (bar_width * stacked_index) + padding
|
84
|
+
right_y = left_y + (bar_width * @bar_spacing)
|
85
|
+
|
86
|
+
top_x = 0
|
87
|
+
stacked_bars.each do |bar|
|
88
|
+
next if bar.point == 0
|
89
|
+
|
90
|
+
bottom_x, = conversion.get_top_bottom_scaled(total)
|
91
|
+
bottom_x += @segment_spacing
|
92
|
+
top_x, = conversion.get_top_bottom_scaled(total + bar.point)
|
93
|
+
|
94
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: bar.color)
|
95
|
+
rect_renderer.render(bottom_x, left_y, top_x, right_y)
|
96
|
+
|
97
|
+
total += bar.point
|
106
98
|
end
|
107
|
-
end
|
108
99
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
100
|
+
label_center = left_y + (bar_width / 2.0)
|
101
|
+
draw_label(label_center, stacked_index)
|
102
|
+
|
103
|
+
if @show_labels_for_bar_values
|
104
|
+
bar_value_label = Gruff::BarValueLabel::SideBar.new([@graph_left, left_y, top_x, right_y], stacked_bars.sum(&:value))
|
105
|
+
bar_value_label.prepare_rendering(@label_formatting, proc_text_metrics) do |x, y, text, text_width, _text_height|
|
106
|
+
draw_value_label(text_width, bar_width * @bar_spacing, x, y, text)
|
107
|
+
end
|
113
108
|
end
|
114
109
|
end
|
115
110
|
end
|
data/lib/gruff/spider.rb
CHANGED
@@ -46,6 +46,11 @@ private
|
|
46
46
|
@hide_line_markers.freeze
|
47
47
|
end
|
48
48
|
|
49
|
+
def setup_drawing
|
50
|
+
@center_labels_over_point = false
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
49
54
|
def setup_graph_measurements
|
50
55
|
super
|
51
56
|
|
@@ -82,7 +87,7 @@ private
|
|
82
87
|
end
|
83
88
|
|
84
89
|
def normalize_points(value)
|
85
|
-
value * @unit_length
|
90
|
+
value.to_f * @unit_length
|
86
91
|
end
|
87
92
|
|
88
93
|
def draw_label(center_x, center_y, angle, radius, amount)
|
@@ -107,7 +112,7 @@ private
|
|
107
112
|
x = x_offset + ((radius + r_offset) * Math.cos(angle))
|
108
113
|
y = y_offset + ((radius + r_offset) * Math.sin(angle))
|
109
114
|
|
110
|
-
draw_label_at(metrics.width, metrics.height, x, y, amount, Magick::CenterGravity)
|
115
|
+
draw_label_at(metrics.width, metrics.height, x, y, amount, gravity: Magick::CenterGravity)
|
111
116
|
end
|
112
117
|
|
113
118
|
def draw_axes(center_x, center_y, radius, additive_angle, line_color = nil)
|
data/lib/gruff/stacked_area.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'helper/stacked_mixin'
|
4
|
+
|
3
5
|
#
|
4
6
|
# Here's how to set up a Gruff::StackedArea.
|
5
7
|
#
|
@@ -31,13 +33,14 @@ private
|
|
31
33
|
end
|
32
34
|
|
33
35
|
def draw_graph
|
34
|
-
x_increment = @graph_width / (column_count - 1)
|
36
|
+
x_increment = (@graph_width / (column_count - 1)).to_f
|
35
37
|
|
36
38
|
height = Array.new(column_count, 0)
|
37
39
|
|
38
|
-
|
40
|
+
prev_data_points = nil
|
39
41
|
store.norm_data.each do |data_row|
|
40
|
-
|
42
|
+
next if data_row.points.empty?
|
43
|
+
|
41
44
|
data_points = []
|
42
45
|
|
43
46
|
data_row.points.each_with_index do |data_point, index|
|
@@ -69,6 +72,8 @@ private
|
|
69
72
|
poly_points << data_points[1]
|
70
73
|
|
71
74
|
Gruff::Renderer::Polygon.new(renderer, color: data_row.color).render(poly_points)
|
75
|
+
|
76
|
+
prev_data_points = data_points
|
72
77
|
end
|
73
78
|
end
|
74
79
|
end
|