gruff 0.14.0-java → 0.17.0-java
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 +28 -12
- data/.gitignore +1 -0
- data/.rubocop.yml +20 -24
- data/CHANGELOG.md +52 -0
- data/README.md +10 -3
- data/gruff.gemspec +9 -10
- data/lib/gruff/accumulator_bar.rb +1 -1
- data/lib/gruff/area.rb +6 -4
- data/lib/gruff/bar.rb +53 -31
- data/lib/gruff/base.rb +292 -184
- data/lib/gruff/bezier.rb +4 -2
- data/lib/gruff/box_plot.rb +180 -0
- data/lib/gruff/bullet.rb +6 -6
- data/lib/gruff/candlestick.rb +120 -0
- data/lib/gruff/dot.rb +11 -12
- data/lib/gruff/font.rb +3 -0
- data/lib/gruff/helper/bar_conversion.rb +6 -10
- data/lib/gruff/helper/bar_mixin.rb +25 -0
- data/lib/gruff/helper/bar_value_label.rb +24 -40
- data/lib/gruff/helper/stacked_mixin.rb +19 -1
- data/lib/gruff/histogram.rb +9 -5
- data/lib/gruff/line.rb +49 -48
- data/lib/gruff/mini/legend.rb +11 -11
- data/lib/gruff/net.rb +23 -18
- data/lib/gruff/patch/rmagick.rb +0 -1
- data/lib/gruff/patch/string.rb +1 -0
- data/lib/gruff/pie.rb +26 -12
- data/lib/gruff/renderer/dash_line.rb +3 -2
- data/lib/gruff/renderer/dot.rb +28 -15
- data/lib/gruff/renderer/line.rb +1 -3
- data/lib/gruff/renderer/rectangle.rb +6 -2
- data/lib/gruff/renderer/renderer.rb +4 -8
- data/lib/gruff/renderer/text.rb +7 -1
- data/lib/gruff/scatter.rb +64 -56
- data/lib/gruff/side_bar.rb +64 -30
- data/lib/gruff/side_stacked_bar.rb +43 -54
- data/lib/gruff/spider.rb +52 -18
- data/lib/gruff/stacked_area.rb +18 -8
- data/lib/gruff/stacked_bar.rb +59 -29
- data/lib/gruff/store/xy_data.rb +2 -0
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +67 -58
- metadata +17 -16
- data/.rubocop_todo.yml +0 -116
- data/lib/gruff/scene.rb +0 -200
- data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/line.rb
CHANGED
@@ -25,7 +25,7 @@ class Gruff::Line < Gruff::Base
|
|
25
25
|
attr_writer :line_width
|
26
26
|
attr_writer :dot_radius
|
27
27
|
|
28
|
-
# default is +'circle'+, other options include square
|
28
|
+
# default is +'circle'+, other options include +square+ and +diamond+.
|
29
29
|
attr_writer :dot_style
|
30
30
|
|
31
31
|
# Hide parts of the graph to fit more data points, or for a different appearance.
|
@@ -40,6 +40,23 @@ class Gruff::Line < Gruff::Base
|
|
40
40
|
# The number of vertical lines shown.
|
41
41
|
attr_writer :marker_x_count
|
42
42
|
|
43
|
+
# Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
|
44
|
+
#
|
45
|
+
# g = Gruff::Line.new(400) # 400px wide with lines
|
46
|
+
# g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
|
47
|
+
# g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
|
48
|
+
#
|
49
|
+
# The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
|
50
|
+
def initialize(*args)
|
51
|
+
raise ArgumentError, 'Wrong number of arguments' if args.length > 2
|
52
|
+
|
53
|
+
if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
|
54
|
+
super()
|
55
|
+
else
|
56
|
+
super args.shift
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
43
60
|
# Get the value if somebody has defined it.
|
44
61
|
def baseline_value
|
45
62
|
if @reference_lines.key?(:baseline)
|
@@ -64,23 +81,6 @@ class Gruff::Line < Gruff::Base
|
|
64
81
|
@reference_lines[:baseline][:color] = new_value
|
65
82
|
end
|
66
83
|
|
67
|
-
# Call with target pixel width of graph (+800+, +400+, +300+), and/or +false+ to omit lines (points only).
|
68
|
-
#
|
69
|
-
# g = Gruff::Line.new(400) # 400px wide with lines
|
70
|
-
# g = Gruff::Line.new(400, false) # 400px wide, no lines (for backwards compatibility)
|
71
|
-
# g = Gruff::Line.new(false) # Defaults to 800px wide, no lines (for backwards compatibility)
|
72
|
-
#
|
73
|
-
# The preferred way is to call {#hide_dots=} or {#hide_lines=} instead.
|
74
|
-
def initialize(*args)
|
75
|
-
raise ArgumentError, 'Wrong number of arguments' if args.length > 2
|
76
|
-
|
77
|
-
if args.empty? || (!args.first.is_a?(Numeric) && !args.first.is_a?(String))
|
78
|
-
super()
|
79
|
-
else
|
80
|
-
super args.shift
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
84
|
# This method allows one to plot a dataset with both X and Y data.
|
85
85
|
#
|
86
86
|
# @overload dataxy(name, x_data_points = [], y_data_points = [], color = nil)
|
@@ -118,12 +118,14 @@ class Gruff::Line < Gruff::Base
|
|
118
118
|
def dataxy(name, x_data_points = [], y_data_points = [], color = nil)
|
119
119
|
# make sure it's an array
|
120
120
|
x_data_points = Array(x_data_points)
|
121
|
-
y_data_points = Array(y_data_points)
|
122
121
|
|
123
122
|
raise ArgumentError, 'x_data_points is nil!' if x_data_points.empty?
|
124
123
|
|
125
124
|
if x_data_points.all? { |p| p.is_a?(Array) && p.size == 2 }
|
125
|
+
color = y_data_points if y_data_points.is_a?(String)
|
126
126
|
x_data_points, y_data_points = x_data_points.transpose
|
127
|
+
else
|
128
|
+
y_data_points = Array(y_data_points)
|
127
129
|
end
|
128
130
|
|
129
131
|
raise ArgumentError, 'x_data_points.length != y_data_points.length!' if x_data_points.length != y_data_points.length
|
@@ -163,7 +165,7 @@ private
|
|
163
165
|
end
|
164
166
|
|
165
167
|
def draw_horizontal_reference_line(reference_line)
|
166
|
-
level = @graph_top + (@graph_height - reference_line[:norm_value] * @graph_height)
|
168
|
+
level = @graph_top + (@graph_height - (reference_line[:norm_value] * @graph_height))
|
167
169
|
draw_reference_line(reference_line, @graph_left, @graph_left + @graph_width, level, level)
|
168
170
|
end
|
169
171
|
|
@@ -174,7 +176,7 @@ private
|
|
174
176
|
|
175
177
|
def draw_graph
|
176
178
|
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
177
|
-
@x_increment =
|
179
|
+
@x_increment = column_count > 1 ? @graph_width / (column_count - 1) : @graph_width
|
178
180
|
|
179
181
|
@reference_lines.each_value do |curr_reference_line|
|
180
182
|
draw_horizontal_reference_line(curr_reference_line) if curr_reference_line.key?(:norm_value)
|
@@ -187,22 +189,22 @@ private
|
|
187
189
|
one_point = contains_one_point_only?(data_row)
|
188
190
|
|
189
191
|
data_row.coordinates.each_with_index do |(x_data, y_data), index|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
@labels.each do |label_pos, _|
|
197
|
-
draw_label(@graph_left + ((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value), label_pos)
|
192
|
+
new_x = begin
|
193
|
+
if x_data.nil?
|
194
|
+
# use the old method: equally spaced points along the x-axis
|
195
|
+
@graph_left + (@x_increment * index)
|
196
|
+
else
|
197
|
+
get_x_coord(x_data, @graph_width, @graph_left)
|
198
198
|
end
|
199
199
|
end
|
200
|
+
draw_label_for_x_data(x_data, new_x, index)
|
201
|
+
|
200
202
|
unless y_data # we can't draw a line for a null data point, we can still label the axis though
|
201
203
|
prev_x = prev_y = nil
|
202
204
|
next
|
203
205
|
end
|
204
206
|
|
205
|
-
new_y = @graph_top + (@graph_height - y_data * @graph_height)
|
207
|
+
new_y = @graph_top + (@graph_height - (y_data * @graph_height))
|
206
208
|
|
207
209
|
# Reset each time to avoid thin-line errors
|
208
210
|
stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.y_points.size * 4), 5.0)
|
@@ -225,12 +227,12 @@ private
|
|
225
227
|
|
226
228
|
def setup_data
|
227
229
|
# Update the global min/max values for the x data
|
228
|
-
@maximum_x_value
|
229
|
-
@minimum_x_value
|
230
|
+
@maximum_x_value = (@maximum_x_value || store.max_x).to_f
|
231
|
+
@minimum_x_value = (@minimum_x_value || store.min_x).to_f
|
230
232
|
|
231
233
|
# Deal with horizontal reference line values that exceed the existing minimum & maximum values.
|
232
|
-
possible_maximums = [maximum_value
|
233
|
-
possible_minimums = [minimum_value
|
234
|
+
possible_maximums = [maximum_value]
|
235
|
+
possible_minimums = [minimum_value]
|
234
236
|
|
235
237
|
@reference_lines.each_value do |curr_reference_line|
|
236
238
|
if curr_reference_line.key?(:value)
|
@@ -253,41 +255,40 @@ private
|
|
253
255
|
def normalize
|
254
256
|
return unless data_given?
|
255
257
|
|
256
|
-
spread_x = @maximum_x_value
|
258
|
+
spread_x = @maximum_x_value - @minimum_x_value
|
257
259
|
store.normalize(minimum_x: @minimum_x_value, spread_x: spread_x, minimum_y: minimum_value, spread_y: @spread)
|
258
260
|
|
259
261
|
@reference_lines.each_value do |curr_reference_line|
|
260
262
|
# We only care about horizontal markers ... for normalization.
|
261
263
|
# Vertical markers won't have a :value, they will have an :index
|
262
264
|
|
263
|
-
curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread
|
265
|
+
curr_reference_line[:norm_value] = ((curr_reference_line[:value].to_f - minimum_value) / @spread) if curr_reference_line.key?(:value)
|
264
266
|
end
|
265
267
|
end
|
266
268
|
|
267
|
-
def sort_norm_data
|
268
|
-
super unless store.data.any?(&:x_points)
|
269
|
-
end
|
270
|
-
|
271
269
|
def draw_line_markers
|
272
270
|
# do all of the stuff for the horizontal lines on the y-axis
|
273
271
|
super
|
274
272
|
return if @hide_line_markers
|
273
|
+
return unless @show_vertical_markers
|
275
274
|
|
276
275
|
(0..@marker_x_count).each do |index|
|
277
|
-
|
278
|
-
|
276
|
+
draw_marker_vertical_line(@graph_left + @graph_width - (index * @graph_width / @marker_x_count))
|
277
|
+
end
|
278
|
+
end
|
279
279
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
280
|
+
def draw_label_for_x_data(x_data, new_x, index)
|
281
|
+
if x_data.nil?
|
282
|
+
draw_label(new_x, index)
|
283
|
+
else
|
284
|
+
@labels.each do |label_pos, _|
|
285
|
+
draw_label(@graph_left + (((label_pos - @minimum_x_value) * @graph_width) / (@maximum_x_value - @minimum_x_value)), label_pos)
|
285
286
|
end
|
286
287
|
end
|
287
288
|
end
|
288
289
|
|
289
290
|
def get_x_coord(x_data_point, width, offset)
|
290
|
-
x_data_point * width + offset
|
291
|
+
(x_data_point * width) + offset
|
291
292
|
end
|
292
293
|
|
293
294
|
def contains_one_point_only?(data_row)
|
data/lib/gruff/mini/legend.rb
CHANGED
@@ -21,7 +21,7 @@ module Gruff
|
|
21
21
|
|
22
22
|
@legend_labels = store.data.map(&:label)
|
23
23
|
|
24
|
-
legend_height =
|
24
|
+
legend_height = scale((store.length * calculate_line_height) + @top_margin + @bottom_margin)
|
25
25
|
|
26
26
|
@original_rows = @raw_rows
|
27
27
|
@original_columns = @raw_columns
|
@@ -32,7 +32,7 @@ module Gruff
|
|
32
32
|
@columns += calculate_legend_width + @left_margin
|
33
33
|
else
|
34
34
|
font = @legend_font.dup
|
35
|
-
font.size =
|
35
|
+
font.size = scale(font.size)
|
36
36
|
@rows += store.length * calculate_caps_height(font) * 1.7
|
37
37
|
end
|
38
38
|
|
@@ -45,7 +45,7 @@ module Gruff
|
|
45
45
|
|
46
46
|
def calculate_legend_width
|
47
47
|
width = @legend_labels.map { |label| calculate_width(@legend_font, label) }.max
|
48
|
-
|
48
|
+
scale(width + (40 * 1.7))
|
49
49
|
end
|
50
50
|
|
51
51
|
##
|
@@ -69,17 +69,17 @@ module Gruff
|
|
69
69
|
|
70
70
|
@legend_labels.each_with_index do |legend_label, index|
|
71
71
|
# Draw label
|
72
|
-
label = truncate_legend_label(legend_label)
|
73
|
-
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
|
74
72
|
x_offset = current_x_offset + (legend_square_width * 1.7)
|
73
|
+
label = truncate_legend_label(legend_label, x_offset)
|
74
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @legend_font)
|
75
75
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, x_offset, current_y_offset, Magick::WestGravity)
|
76
76
|
|
77
77
|
# Now draw box with color of this dataset
|
78
78
|
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: store.data[index].color)
|
79
79
|
rect_renderer.render(current_x_offset,
|
80
|
-
current_y_offset - legend_square_width / 2.0,
|
80
|
+
current_y_offset - (legend_square_width / 2.0),
|
81
81
|
current_x_offset + legend_square_width,
|
82
|
-
current_y_offset + legend_square_width / 2.0)
|
82
|
+
current_y_offset + (legend_square_width / 2.0))
|
83
83
|
|
84
84
|
current_y_offset += calculate_line_height
|
85
85
|
end
|
@@ -90,13 +90,13 @@ module Gruff
|
|
90
90
|
#
|
91
91
|
# Department of Hu...
|
92
92
|
|
93
|
-
def truncate_legend_label(label)
|
93
|
+
def truncate_legend_label(label, x_offset)
|
94
94
|
truncated_label = label.to_s
|
95
95
|
|
96
96
|
font = @legend_font.dup
|
97
|
-
font.size =
|
98
|
-
max_width = @columns -
|
99
|
-
while calculate_width(font, truncated_label) > max_width && truncated_label.length > 1
|
97
|
+
font.size = scale(font.size)
|
98
|
+
max_width = @columns - scale(x_offset) - @right_margin
|
99
|
+
while calculate_width(font, "#{truncated_label}...") > max_width && truncated_label.length > 1
|
100
100
|
truncated_label = truncated_label[0..truncated_label.length - 2]
|
101
101
|
end
|
102
102
|
truncated_label + (truncated_label.length < label.to_s.length ? '...' : '')
|
data/lib/gruff/net.rb
CHANGED
@@ -43,6 +43,21 @@ private
|
|
43
43
|
@marker_font.bold = true
|
44
44
|
end
|
45
45
|
|
46
|
+
def setup_drawing
|
47
|
+
@center_labels_over_point = false
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
def setup_graph_measurements
|
52
|
+
super
|
53
|
+
|
54
|
+
@radius = @graph_height / 2.0
|
55
|
+
@circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
|
56
|
+
@stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4.0), 5.0)
|
57
|
+
@center_x = @graph_left + (@graph_width / 2.0)
|
58
|
+
@center_y = @graph_top + (@graph_height / 2.0) + 10
|
59
|
+
end
|
60
|
+
|
46
61
|
def draw_graph
|
47
62
|
store.norm_data.each do |data_row|
|
48
63
|
data_row.points.each_with_index do |data_point, index|
|
@@ -50,15 +65,15 @@ private
|
|
50
65
|
|
51
66
|
rad_pos = index * Math::PI * 2 / column_count
|
52
67
|
point_distance = data_point * @radius
|
53
|
-
start_x = @center_x + Math.sin(rad_pos) * point_distance
|
54
|
-
start_y = @center_y - Math.cos(rad_pos) * point_distance
|
68
|
+
start_x = @center_x + (Math.sin(rad_pos) * point_distance)
|
69
|
+
start_y = @center_y - (Math.cos(rad_pos) * point_distance)
|
55
70
|
|
56
71
|
next_index = index + 1 < data_row.points.length ? index + 1 : 0
|
57
72
|
|
58
73
|
next_rad_pos = next_index * Math::PI * 2 / column_count
|
59
74
|
next_point_distance = data_row.points[next_index] * @radius
|
60
|
-
end_x = @center_x + Math.sin(next_rad_pos) * next_point_distance
|
61
|
-
end_y = @center_y - Math.cos(next_rad_pos) * next_point_distance
|
75
|
+
end_x = @center_x + (Math.sin(next_rad_pos) * next_point_distance)
|
76
|
+
end_y = @center_y - (Math.cos(next_rad_pos) * next_point_distance)
|
62
77
|
|
63
78
|
Gruff::Renderer::Line.new(renderer, color: data_row.color, width: @stroke_width).render(start_x, start_y, end_x, end_y)
|
64
79
|
|
@@ -70,16 +85,6 @@ private
|
|
70
85
|
end
|
71
86
|
end
|
72
87
|
|
73
|
-
def setup_drawing
|
74
|
-
super
|
75
|
-
|
76
|
-
@radius = @graph_height / 2.0
|
77
|
-
@circle_radius = @dot_radius || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 2.5), 5.0)
|
78
|
-
@stroke_width = @line_width || clip_value_if_greater_than(@columns / (store.norm_data.first.points.size * 4), 5.0)
|
79
|
-
@center_x = @graph_left + (@graph_width / 2.0)
|
80
|
-
@center_y = @graph_top + (@graph_height / 2.0) + 10
|
81
|
-
end
|
82
|
-
|
83
88
|
# the lines connecting in the center, with the first line vertical
|
84
89
|
def draw_line_markers
|
85
90
|
return if @hide_line_markers
|
@@ -89,7 +94,7 @@ private
|
|
89
94
|
rad_pos = index * Math::PI * 2 / column_count
|
90
95
|
|
91
96
|
Gruff::Renderer::Line.new(renderer, color: @marker_color)
|
92
|
-
.render(@center_x, @center_y, @center_x + Math.sin(rad_pos) * @radius, @center_y - Math.cos(rad_pos) * @radius)
|
97
|
+
.render(@center_x, @center_y, @center_x + (Math.sin(rad_pos) * @radius), @center_y - (Math.cos(rad_pos) * @radius))
|
93
98
|
|
94
99
|
marker_label = @labels[index] ? @labels[index].to_s : '000'
|
95
100
|
draw_label(@center_x, @center_y, rad_pos * 360 / (2 * Math::PI), @radius + @circle_radius, marker_label)
|
@@ -99,9 +104,9 @@ private
|
|
99
104
|
def draw_label(center_x, center_y, angle, radius, amount)
|
100
105
|
x_offset = center_x # + 15 # The label points need to be tweaked slightly
|
101
106
|
y_offset = center_y # + 0 # This one doesn't though
|
102
|
-
x = x_offset + (radius + LABEL_MARGIN) * Math.sin(deg2rad(angle))
|
103
|
-
y = y_offset - (radius + LABEL_MARGIN) * Math.cos(deg2rad(angle))
|
107
|
+
x = x_offset + ((radius + LABEL_MARGIN) * Math.sin(deg2rad(angle)))
|
108
|
+
y = y_offset - ((radius + LABEL_MARGIN) * Math.cos(deg2rad(angle)))
|
104
109
|
|
105
|
-
draw_label_at(1.0, 1.0, x, y, amount, Magick::CenterGravity)
|
110
|
+
draw_label_at(1.0, 1.0, x, y, amount, gravity: Magick::CenterGravity)
|
106
111
|
end
|
107
112
|
end
|
data/lib/gruff/patch/rmagick.rb
CHANGED
data/lib/gruff/patch/string.rb
CHANGED
data/lib/gruff/pie.rb
CHANGED
@@ -9,14 +9,14 @@
|
|
9
9
|
# g.data 'Hamburgers', 50
|
10
10
|
# g.write("pie_keynote.png")
|
11
11
|
#
|
12
|
-
# To control where the pie chart starts creating slices, use {#
|
12
|
+
# To control where the pie chart starts creating slices, use {#start_degree=}.
|
13
13
|
#
|
14
14
|
class Gruff::Pie < Gruff::Base
|
15
|
-
DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.
|
15
|
+
DEFAULT_TEXT_OFFSET_PERCENTAGE = 0.1
|
16
16
|
|
17
17
|
# Can be used to make the pie start cutting slices at the top (-90.0)
|
18
|
-
# or at another angle. Default is
|
19
|
-
attr_writer :
|
18
|
+
# or at another angle. Default is +-90.0+, which starts at 3 o'clock.
|
19
|
+
attr_writer :start_degree
|
20
20
|
|
21
21
|
# Set the number output format lambda.
|
22
22
|
attr_writer :label_formatting
|
@@ -26,25 +26,34 @@ class Gruff::Pie < Gruff::Base
|
|
26
26
|
attr_writer :hide_labels_less_than
|
27
27
|
|
28
28
|
# Affect the distance between the percentages and the pie chart.
|
29
|
-
# Defaults to +0.
|
29
|
+
# Defaults to +0.1+.
|
30
30
|
attr_writer :text_offset_percentage
|
31
31
|
|
32
32
|
## Use values instead of percentages.
|
33
33
|
attr_writer :show_values_as_labels
|
34
34
|
|
35
|
-
|
35
|
+
# Set to +true+ if you want the data sets sorted with largest avg values drawn
|
36
|
+
# first. Default is +true+.
|
37
|
+
attr_writer :sort
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
# Can be used to make the pie start cutting slices at the top (-90.0)
|
40
|
+
# or at another angle. Default is +-90.0+, which starts at 3 o'clock.
|
41
|
+
# @deprecated Please use +start_degree+ attribute instead.
|
42
|
+
def zero_degree=(value)
|
43
|
+
warn '#zero_degree= is deprecated. Please use `start_degree` attribute instead'
|
44
|
+
@start_degree = value
|
39
45
|
end
|
40
46
|
|
47
|
+
private
|
48
|
+
|
41
49
|
def initialize_attributes
|
42
50
|
super
|
43
|
-
@
|
51
|
+
@start_degree = -90.0
|
44
52
|
@hide_labels_less_than = 0.0
|
45
53
|
@text_offset_percentage = DEFAULT_TEXT_OFFSET_PERCENTAGE
|
46
54
|
@show_values_as_labels = false
|
47
55
|
@marker_font.bold = true
|
56
|
+
@sort = true
|
48
57
|
|
49
58
|
@hide_line_markers = true
|
50
59
|
@hide_line_markers.freeze
|
@@ -52,6 +61,11 @@ private
|
|
52
61
|
@label_formatting = ->(value, percentage) { @show_values_as_labels ? value.to_s : "#{percentage}%" }
|
53
62
|
end
|
54
63
|
|
64
|
+
def setup_drawing
|
65
|
+
@center_labels_over_point = false
|
66
|
+
super
|
67
|
+
end
|
68
|
+
|
55
69
|
def draw_graph
|
56
70
|
slices.each do |slice|
|
57
71
|
if slice.value > 0
|
@@ -83,7 +97,7 @@ private
|
|
83
97
|
# Spatial Value-Related Methods
|
84
98
|
|
85
99
|
def chart_degrees
|
86
|
-
@chart_degrees ||= @
|
100
|
+
@chart_degrees ||= @start_degree
|
87
101
|
end
|
88
102
|
|
89
103
|
attr_reader :graph_height
|
@@ -127,12 +141,12 @@ private
|
|
127
141
|
if slice.percentage >= @hide_labels_less_than
|
128
142
|
x, y = label_coordinates_for slice
|
129
143
|
label = @label_formatting.call(slice.value, slice.percentage)
|
130
|
-
draw_label_at(1.0, 1.0, x, y, label, Magick::CenterGravity)
|
144
|
+
draw_label_at(1.0, 1.0, x, y, label, gravity: Magick::CenterGravity)
|
131
145
|
end
|
132
146
|
end
|
133
147
|
|
134
148
|
def label_coordinates_for(slice)
|
135
|
-
angle = chart_degrees + slice.degrees / 2
|
149
|
+
angle = chart_degrees + (slice.degrees / 2.0)
|
136
150
|
|
137
151
|
[x_label_coordinate(angle), y_label_coordinate(angle)]
|
138
152
|
end
|
@@ -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,37 +3,50 @@
|
|
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
|
-
def render(new_x, new_y,
|
14
|
-
|
14
|
+
def render(new_x, new_y, radius)
|
15
|
+
@renderer.draw.push
|
15
16
|
@renderer.draw.stroke_width(@width)
|
16
17
|
@renderer.draw.stroke(@color)
|
17
18
|
@renderer.draw.fill(@color)
|
18
|
-
|
19
|
-
|
19
|
+
@renderer.draw.fill_opacity(@opacity)
|
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)
|
20
25
|
else
|
21
|
-
circle(new_x, new_y,
|
26
|
+
circle(new_x, new_y, radius)
|
22
27
|
end
|
23
|
-
|
28
|
+
@renderer.draw.pop
|
24
29
|
end
|
25
30
|
|
26
|
-
def circle(new_x, new_y,
|
27
|
-
@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)
|
28
33
|
end
|
29
34
|
|
30
|
-
def square(new_x, new_y,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
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
|
36
40
|
@renderer.draw.rectangle(corner1, corner2, corner3, corner4)
|
37
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
|
38
51
|
end
|
39
52
|
end
|
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
|
@@ -23,10 +23,6 @@ module Gruff
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def background_image=(image)
|
27
|
-
@image = image
|
28
|
-
end
|
29
|
-
|
30
26
|
def background(columns, rows, scale, theme_options)
|
31
27
|
case theme_options[:background_colors]
|
32
28
|
when Array
|
@@ -44,8 +40,8 @@ module Gruff
|
|
44
40
|
|
45
41
|
# Make a new image at the current size with a solid +color+.
|
46
42
|
def solid_background(columns, rows, color)
|
47
|
-
Magick::Image.new(columns, rows) do
|
48
|
-
|
43
|
+
Magick::Image.new(columns, rows) do |img|
|
44
|
+
img.background_color = color
|
49
45
|
end
|
50
46
|
end
|
51
47
|
|
@@ -97,8 +93,8 @@ module Gruff
|
|
97
93
|
|
98
94
|
# Use with a theme to make a transparent background
|
99
95
|
def render_transparent_background(columns, rows)
|
100
|
-
Magick::Image.new(columns, rows) do
|
101
|
-
|
96
|
+
Magick::Image.new(columns, rows) do |img|
|
97
|
+
img.background_color = 'transparent'
|
102
98
|
end
|
103
99
|
end
|
104
100
|
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
|