gruff 0.12.2 → 0.15.0
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 +66 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +34 -27
- data/CHANGELOG.md +29 -0
- data/README.md +15 -7
- data/assets/fonts/LICENSE.txt +202 -0
- data/assets/fonts/Roboto-Bold.ttf +0 -0
- data/assets/fonts/Roboto-Regular.ttf +0 -0
- data/gruff.gemspec +9 -10
- data/lib/gruff/accumulator_bar.rb +3 -1
- data/lib/gruff/area.rb +5 -8
- data/lib/gruff/bar.rb +32 -49
- data/lib/gruff/base.rb +199 -115
- data/lib/gruff/bezier.rb +4 -6
- data/lib/gruff/bullet.rb +12 -11
- data/lib/gruff/dot.rb +13 -14
- data/lib/gruff/font.rb +39 -0
- data/lib/gruff/helper/bar_conversion.rb +27 -12
- data/lib/gruff/helper/bar_value_label.rb +71 -0
- data/lib/gruff/helper/stacked_mixin.rb +1 -2
- data/lib/gruff/histogram.rb +9 -7
- data/lib/gruff/line.rb +57 -50
- data/lib/gruff/mini/bar.rb +9 -6
- data/lib/gruff/mini/legend.rb +12 -8
- data/lib/gruff/mini/pie.rb +9 -6
- data/lib/gruff/mini/side_bar.rb +9 -6
- data/lib/gruff/net.rb +9 -15
- data/lib/gruff/patch/rmagick.rb +0 -1
- data/lib/gruff/patch/string.rb +1 -1
- data/lib/gruff/pie.rb +23 -65
- data/lib/gruff/renderer/bezier.rb +8 -9
- data/lib/gruff/renderer/circle.rb +8 -9
- data/lib/gruff/renderer/dash_line.rb +9 -10
- data/lib/gruff/renderer/dot.rb +13 -14
- data/lib/gruff/renderer/ellipse.rb +8 -9
- data/lib/gruff/renderer/line.rb +8 -9
- data/lib/gruff/renderer/polygon.rb +9 -10
- data/lib/gruff/renderer/polyline.rb +8 -9
- data/lib/gruff/renderer/rectangle.rb +7 -8
- data/lib/gruff/renderer/renderer.rb +25 -40
- data/lib/gruff/renderer/text.rb +21 -29
- data/lib/gruff/scatter.rb +55 -75
- data/lib/gruff/scene.rb +28 -18
- data/lib/gruff/side_bar.rb +35 -54
- data/lib/gruff/side_stacked_bar.rb +14 -17
- data/lib/gruff/spider.rb +11 -20
- data/lib/gruff/stacked_area.rb +10 -11
- data/lib/gruff/stacked_bar.rb +14 -15
- 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 +68 -55
- data/rails_generators/gruff/templates/controller.rb +1 -1
- metadata +34 -20
- data/.rubocop_todo.yml +0 -190
- 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/helper/bar_value_label_mixin.rb +0 -33
- data/lib/gruff/photo_bar.rb +0 -93
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,42 +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_weight = font_weight
|
53
|
-
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
|
54
46
|
|
55
47
|
# The old ImageMagick causes SEGV with string which has '%' + alphabet (eg. '%S').
|
56
48
|
# This format is used to embed value into a string using image properties.
|
57
49
|
# However, gruff use plain image as canvas which does not have any property.
|
58
50
|
# So, in here, it just escape % in order to avoid SEGV.
|
59
|
-
text = text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
51
|
+
text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
60
52
|
|
61
|
-
draw.get_type_metrics(image, text)
|
53
|
+
@renderer.draw.get_type_metrics(@renderer.image, text)
|
62
54
|
end
|
63
55
|
end
|
64
56
|
end
|
data/lib/gruff/scatter.rb
CHANGED
@@ -28,60 +28,18 @@ class Gruff::Scatter < Gruff::Base
|
|
28
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
29
|
attr_writer :disable_significant_rounding_x_axis
|
30
30
|
|
31
|
-
# Allow
|
32
|
-
attr_writer :
|
31
|
+
# Allow for vertical marker lines.
|
32
|
+
attr_writer :show_vertical_markers
|
33
33
|
|
34
34
|
# Allow using vertical labels in the X axis (and setting the label margin).
|
35
35
|
attr_writer :x_label_margin
|
36
36
|
attr_writer :use_vertical_x_labels
|
37
37
|
|
38
|
-
# Allow
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@store = Gruff::Store.new(Gruff::Store::XYData)
|
44
|
-
end
|
45
|
-
private :initialize_store
|
46
|
-
|
47
|
-
def initialize_ivars
|
48
|
-
super
|
49
|
-
|
50
|
-
@baseline_x_color = @baseline_y_color = 'red'
|
51
|
-
@baseline_x_value = @baseline_y_value = nil
|
52
|
-
@circle_radius = nil
|
53
|
-
@disable_significant_rounding_x_axis = false
|
54
|
-
@enable_vertical_line_markers = false
|
55
|
-
@marker_x_count = nil
|
56
|
-
@maximum_x_value = @minimum_x_value = nil
|
57
|
-
@stroke_width = nil
|
58
|
-
@use_vertical_x_labels = false
|
59
|
-
@x_axis_label_format = nil
|
60
|
-
@x_label_margin = nil
|
61
|
-
@y_axis_label_format = nil
|
62
|
-
end
|
63
|
-
private :initialize_ivars
|
64
|
-
|
65
|
-
def draw
|
66
|
-
super
|
67
|
-
return unless data_given?
|
68
|
-
|
69
|
-
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
70
|
-
@x_increment = (@x_spread > 1) ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
|
71
|
-
|
72
|
-
store.norm_data.each do |data_row|
|
73
|
-
data_row.coordinates.each do |x_value, y_value|
|
74
|
-
next if y_value.nil? || x_value.nil?
|
75
|
-
|
76
|
-
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
77
|
-
new_y = @graph_top + (@graph_height - y_value * @graph_height)
|
78
|
-
|
79
|
-
# Reset each time to avoid thin-line errors
|
80
|
-
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
81
|
-
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
82
|
-
Gruff::Renderer::Circle.new(color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
83
|
-
end
|
84
|
-
end
|
38
|
+
# Allow enabling vertical lines. When you have a lot of data, they can work great.
|
39
|
+
# @deprecated Please use +show_vertical_markers+ attribute instead.
|
40
|
+
def enable_vertical_line_markers=(value)
|
41
|
+
warn '#enable_vertical_line_markers= is deprecated. Please use `show_vertical_markers` attribute instead'
|
42
|
+
@show_vertical_markers = value
|
85
43
|
end
|
86
44
|
|
87
45
|
# The first parameter is the name of the dataset. The next two are the
|
@@ -137,6 +95,44 @@ class Gruff::Scatter < Gruff::Base
|
|
137
95
|
|
138
96
|
private
|
139
97
|
|
98
|
+
def initialize_store
|
99
|
+
@store = Gruff::Store.new(Gruff::Store::XYData)
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize_attributes
|
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
|
+
# 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
|
+
store.norm_data.each do |data_row|
|
122
|
+
data_row.coordinates.each do |x_value, y_value|
|
123
|
+
next if y_value.nil? || x_value.nil?
|
124
|
+
|
125
|
+
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
126
|
+
new_y = @graph_top + (@graph_height - y_value * @graph_height)
|
127
|
+
|
128
|
+
# Reset each time to avoid thin-line errors
|
129
|
+
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
130
|
+
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
131
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
140
136
|
def setup_data
|
141
137
|
# Update the global min/max values for the x data
|
142
138
|
@maximum_x_value ||= store.max_x
|
@@ -152,7 +148,7 @@ private
|
|
152
148
|
super
|
153
149
|
end
|
154
150
|
|
155
|
-
def calculate_spread
|
151
|
+
def calculate_spread
|
156
152
|
super
|
157
153
|
@x_spread = @maximum_x_value.to_f - @minimum_x_value.to_f
|
158
154
|
@x_spread = @x_spread > 0 ? @x_spread : 1
|
@@ -180,18 +176,18 @@ private
|
|
180
176
|
end
|
181
177
|
@marker_x_count ||= 4
|
182
178
|
end
|
183
|
-
@x_increment =
|
179
|
+
@x_increment = @x_spread > 0 ? (@x_spread / @marker_x_count) : 1
|
184
180
|
unless @disable_significant_rounding_x_axis
|
185
181
|
@x_increment = significant(@x_increment)
|
186
182
|
end
|
187
183
|
else
|
188
184
|
# TODO: Make this work for negative values
|
189
|
-
@maximum_x_value = [
|
185
|
+
@maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment].max
|
190
186
|
@minimum_x_value = @minimum_x_value.floor
|
191
187
|
calculate_spread
|
192
188
|
normalize
|
193
189
|
|
194
|
-
|
190
|
+
@marker_x_count = (@x_spread / @x_axis_increment).to_i
|
195
191
|
@x_increment = @x_axis_increment
|
196
192
|
end
|
197
193
|
increment_x_scaled = @graph_width.to_f / (@x_spread / @x_increment)
|
@@ -199,43 +195,27 @@ private
|
|
199
195
|
# Draw vertical line markers and annotate with numbers
|
200
196
|
(0..@marker_x_count).each do |index|
|
201
197
|
# TODO: Fix the vertical lines, and enable them by default. Not pretty when they don't match up with top y-axis line
|
202
|
-
if @
|
198
|
+
if @show_vertical_markers
|
203
199
|
x = @graph_left + @graph_width - index.to_f * increment_x_scaled
|
204
200
|
|
205
|
-
line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
|
201
|
+
line_renderer = Gruff::Renderer::Line.new(renderer, color: @marker_color, shadow_color: @marker_shadow_color)
|
206
202
|
line_renderer.render(x, @graph_top, x, @graph_bottom)
|
207
203
|
end
|
208
204
|
|
209
205
|
unless @hide_line_numbers
|
210
|
-
marker_label = index * @x_increment + @minimum_x_value.
|
206
|
+
marker_label = BigDecimal(index.to_s) * BigDecimal(@x_increment.to_s) + BigDecimal(@minimum_x_value.to_s)
|
211
207
|
y_offset = @graph_bottom + (@x_label_margin || LABEL_MARGIN)
|
212
208
|
x_offset = get_x_coord(index.to_f, increment_x_scaled, @graph_left)
|
213
209
|
|
214
|
-
label =
|
210
|
+
label = x_axis_label(marker_label, @x_increment)
|
215
211
|
rotation = -90.0 if @use_vertical_x_labels
|
216
|
-
text_renderer = Gruff::Renderer::Text.new(label, font: @
|
212
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
|
217
213
|
text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
|
218
214
|
end
|
219
215
|
end
|
220
216
|
end
|
221
217
|
|
222
|
-
def
|
223
|
-
if @y_axis_label_format
|
224
|
-
@y_axis_label_format.call(value)
|
225
|
-
else
|
226
|
-
super
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def vertical_label(value, increment)
|
231
|
-
if @x_axis_label_format
|
232
|
-
@x_axis_label_format.call(value)
|
233
|
-
else
|
234
|
-
label(value, increment)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
def get_x_coord(x_data_point, width, offset) #:nodoc:
|
218
|
+
def get_x_coord(x_data_point, width, offset)
|
239
219
|
x_data_point * width + offset
|
240
220
|
end
|
241
221
|
end
|
data/lib/gruff/scene.rb
CHANGED
@@ -52,7 +52,7 @@ class Gruff::Scene < Gruff::Base
|
|
52
52
|
# Join all the custom paths and filter out the empty ones
|
53
53
|
image_paths = @layers.map(&:path).reject(&:empty?)
|
54
54
|
images = Magick::ImageList.new(*image_paths)
|
55
|
-
|
55
|
+
renderer.background_image = images.flatten_images
|
56
56
|
end
|
57
57
|
|
58
58
|
def layers=(ordered_list)
|
@@ -73,12 +73,20 @@ class Gruff::Scene < Gruff::Base
|
|
73
73
|
case method_name.to_s
|
74
74
|
when /^(\w+)_group=$/
|
75
75
|
add_group Regexp.last_match(1), *args
|
76
|
-
return
|
77
76
|
when /^(\w+)=$/
|
78
77
|
set_input Regexp.last_match(1), args.first
|
79
|
-
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def respond_to_missing?(method_sym, include_private)
|
84
|
+
case method_sym.to_s
|
85
|
+
when /^(\w+)_group=$/, /^(\w+)=$/
|
86
|
+
true
|
87
|
+
else
|
88
|
+
super
|
80
89
|
end
|
81
|
-
super
|
82
90
|
end
|
83
91
|
|
84
92
|
private
|
@@ -90,7 +98,7 @@ private
|
|
90
98
|
def set_input(input_name, input_value)
|
91
99
|
if !@groups[input_name].nil?
|
92
100
|
@groups[input_name].send_updates(input_value)
|
93
|
-
elsif chosen_layer = @layers.find { |layer| layer.name == input_name }
|
101
|
+
elsif (chosen_layer = @layers.find { |layer| layer.name == input_name })
|
94
102
|
chosen_layer.update input_value
|
95
103
|
end
|
96
104
|
end
|
@@ -121,7 +129,7 @@ class Gruff::Layer
|
|
121
129
|
def initialize(base_dir, folder_name)
|
122
130
|
@base_dir = base_dir.to_s
|
123
131
|
@name = folder_name.to_s
|
124
|
-
@filenames = Dir.open(File.join(base_dir, folder_name)).entries.
|
132
|
+
@filenames = Dir.open(File.join(base_dir, folder_name)).entries.grep(/^[^.]+\.png$/).sort
|
125
133
|
@selected_filename = select_default
|
126
134
|
end
|
127
135
|
|
@@ -132,18 +140,20 @@ class Gruff::Layer
|
|
132
140
|
|
133
141
|
# Choose the appropriate filename for this layer, based on the input
|
134
142
|
def update(value)
|
135
|
-
@selected_filename =
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
143
|
+
@selected_filename = begin
|
144
|
+
case value.to_s
|
145
|
+
when /^(true|false)$/
|
146
|
+
select_boolean value
|
147
|
+
when /^(\w|\s)+$/
|
148
|
+
select_string value
|
149
|
+
when /^-?(\d+\.)?\d+$/
|
150
|
+
select_numeric value
|
151
|
+
when /(\d\d):(\d\d):\d\d/
|
152
|
+
select_time "#{Regexp.last_match(1)}#{Regexp.last_match(2)}"
|
153
|
+
else
|
154
|
+
select_default
|
155
|
+
end
|
156
|
+
end
|
147
157
|
# Finally, try to use 'default' if we're still blank
|
148
158
|
@selected_filename ||= select_default
|
149
159
|
end
|
data/lib/gruff/side_bar.rb
CHANGED
@@ -19,15 +19,13 @@
|
|
19
19
|
# g.write('sidebar.png')
|
20
20
|
#
|
21
21
|
class Gruff::SideBar < Gruff::Base
|
22
|
-
using String::GruffCommify
|
23
|
-
|
24
22
|
# Spacing factor applied between bars.
|
25
23
|
attr_writer :bar_spacing
|
26
24
|
|
27
25
|
# Spacing factor applied between a group of bars belonging to the same label.
|
28
26
|
attr_writer :group_spacing
|
29
27
|
|
30
|
-
# Set the number output format
|
28
|
+
# Set the number output format string or lambda.
|
31
29
|
# Default is +"%.2f"+.
|
32
30
|
attr_writer :label_formatting
|
33
31
|
|
@@ -38,27 +36,24 @@ class Gruff::SideBar < Gruff::Base
|
|
38
36
|
# Prevent drawing of column labels left of a side bar graph. Default is +false+.
|
39
37
|
attr_writer :hide_labels
|
40
38
|
|
41
|
-
|
39
|
+
# With Side Bars use the data label for the marker value to the left of the bar.
|
40
|
+
# @deprecated
|
41
|
+
def use_data_label=(_value)
|
42
|
+
warn '#use_data_label is deprecated. It is no longer effective.'
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def initialize_attributes
|
42
48
|
super
|
43
49
|
@bar_spacing = 0.9
|
44
50
|
@group_spacing = 10
|
45
51
|
@label_formatting = nil
|
46
52
|
@show_labels_for_bar_values = false
|
47
53
|
@hide_labels = false
|
48
|
-
end
|
49
|
-
private :initialize_ivars
|
50
|
-
|
51
|
-
def draw
|
52
54
|
@has_left_labels = true
|
53
|
-
super
|
54
|
-
|
55
|
-
return unless data_given?
|
56
|
-
|
57
|
-
draw_bars
|
58
55
|
end
|
59
56
|
|
60
|
-
protected
|
61
|
-
|
62
57
|
def hide_labels?
|
63
58
|
@hide_labels
|
64
59
|
end
|
@@ -71,55 +66,44 @@ protected
|
|
71
66
|
@hide_line_markers
|
72
67
|
end
|
73
68
|
|
74
|
-
|
69
|
+
# Value to avoid completely overwriting the coordinate axis
|
70
|
+
AXIS_MARGIN = 0.5
|
75
71
|
|
76
|
-
def
|
72
|
+
def draw_graph
|
77
73
|
# Setup spacing.
|
78
74
|
#
|
79
75
|
bars_width = (@graph_height - calculate_spacing) / column_count.to_f
|
80
76
|
bar_width = bars_width / store.length
|
81
|
-
height = Array.new(column_count, 0)
|
82
|
-
length = Array.new(column_count, @graph_left)
|
83
77
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
84
78
|
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
79
|
+
# Setup the BarConversion Object
|
80
|
+
conversion = Gruff::BarConversion.new(
|
81
|
+
top: @graph_right, bottom: @graph_left,
|
82
|
+
minimum_value: minimum_value, maximum_value: maximum_value, spread: @spread
|
83
|
+
)
|
89
84
|
|
90
85
|
store.norm_data.each_with_index do |data_row, row_index|
|
91
86
|
data_row.points.each_with_index do |data_point, point_index|
|
92
87
|
group_spacing = @group_spacing * @scale * point_index
|
93
88
|
|
94
|
-
# Using the original calculations from the stacked bar chart
|
95
|
-
# to get the difference between
|
96
|
-
# part of the bart chart we wish to stack.
|
97
|
-
temp1 = @graph_left + (@graph_width - data_point * @graph_width - height[point_index])
|
98
|
-
temp2 = @graph_left + @graph_width - height[point_index]
|
99
|
-
difference = temp2 - temp1
|
100
|
-
|
101
|
-
left_x = length[point_index] - 1
|
102
89
|
left_y = @graph_top + (bars_width * point_index) + (bar_width * row_index) + padding + group_spacing
|
103
|
-
right_x = left_x + difference
|
104
90
|
right_y = left_y + bar_width * @bar_spacing
|
105
91
|
|
106
|
-
|
92
|
+
left_x, right_x = conversion.get_top_bottom_scaled(data_point).sort
|
107
93
|
|
108
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
|
109
|
-
rect_renderer.render(left_x, left_y, right_x, right_y)
|
94
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
95
|
+
rect_renderer.render(left_x + AXIS_MARGIN, left_y, right_x + AXIS_MARGIN, right_y)
|
110
96
|
|
111
97
|
# Calculate center based on bar_width and current row
|
98
|
+
label_center = left_y + bars_width / 2
|
112
99
|
|
113
|
-
if
|
114
|
-
|
115
|
-
draw_label(label_center, row_index, store.norm_data[row_index].label)
|
116
|
-
else
|
117
|
-
label_center = left_y + bars_width / 2
|
118
|
-
draw_label(label_center, point_index)
|
119
|
-
end
|
100
|
+
# Subtract half a bar width to center left if requested
|
101
|
+
draw_label(label_center, point_index)
|
120
102
|
if @show_labels_for_bar_values
|
121
|
-
|
122
|
-
|
103
|
+
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, bar_width) do |x, y, text|
|
105
|
+
draw_value_label(x, y, text)
|
106
|
+
end
|
123
107
|
end
|
124
108
|
end
|
125
109
|
end
|
@@ -139,14 +123,14 @@ private
|
|
139
123
|
line_diff = (@graph_right - @graph_left) / number_of_lines
|
140
124
|
x = @graph_right - (line_diff * index) - 1
|
141
125
|
|
142
|
-
line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
|
126
|
+
line_renderer = Gruff::Renderer::Line.new(renderer, color: @marker_color, shadow_color: @marker_shadow_color)
|
143
127
|
line_renderer.render(x, @graph_bottom, x, @graph_top)
|
144
128
|
|
145
|
-
diff = index - number_of_lines
|
146
|
-
marker_label = diff.abs * increment + minimum_value
|
147
|
-
|
148
129
|
unless @hide_line_numbers
|
149
|
-
|
130
|
+
diff = index - number_of_lines
|
131
|
+
marker_label = BigDecimal(diff.abs.to_s) * BigDecimal(increment.to_s) + BigDecimal(minimum_value.to_s)
|
132
|
+
label = x_axis_label(marker_label, @increment)
|
133
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font)
|
150
134
|
text_renderer.add_to_render_queue(0, 0, x, @graph_bottom + LABEL_MARGIN, Magick::CenterGravity)
|
151
135
|
end
|
152
136
|
end
|
@@ -155,12 +139,9 @@ private
|
|
155
139
|
##
|
156
140
|
# Draw on the Y axis instead of the X
|
157
141
|
|
158
|
-
def draw_label(y_offset, index
|
142
|
+
def draw_label(y_offset, index)
|
159
143
|
draw_unique_label(index) do
|
160
|
-
|
161
|
-
|
162
|
-
text_renderer = Gruff::Renderer::Text.new(lbl, font: @font, size: @marker_font_size, color: @font_color)
|
163
|
-
text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, Magick::EastGravity)
|
144
|
+
draw_label_at(@graph_left - LABEL_MARGIN, 1.0, 0.0, y_offset, @labels[index], Magick::EastGravity)
|
164
145
|
end
|
165
146
|
end
|
166
147
|
|
@@ -21,7 +21,6 @@
|
|
21
21
|
#
|
22
22
|
class Gruff::SideStackedBar < Gruff::SideBar
|
23
23
|
include StackedMixin
|
24
|
-
include BarValueLabelMixin
|
25
24
|
|
26
25
|
# Spacing factor applied between bars.
|
27
26
|
attr_writer :bar_spacing
|
@@ -29,7 +28,7 @@ class Gruff::SideStackedBar < Gruff::SideBar
|
|
29
28
|
# Number of pixels between bar segments.
|
30
29
|
attr_writer :segment_spacing
|
31
30
|
|
32
|
-
# Set the number output format
|
31
|
+
# Set the number output format string or lambda.
|
33
32
|
# Default is +"%.2f"+.
|
34
33
|
attr_writer :label_formatting
|
35
34
|
|
@@ -40,24 +39,23 @@ class Gruff::SideStackedBar < Gruff::SideBar
|
|
40
39
|
# Prevent drawing of column labels left of a side stacked bar graph. Default is +false+.
|
41
40
|
attr_writer :hide_labels
|
42
41
|
|
43
|
-
|
42
|
+
private
|
43
|
+
|
44
|
+
def initialize_attributes
|
44
45
|
super
|
45
46
|
@bar_spacing = 0.9
|
46
47
|
@segment_spacing = 2.0
|
47
48
|
@label_formatting = nil
|
48
49
|
@show_labels_for_bar_values = false
|
49
50
|
@hide_labels = false
|
51
|
+
@has_left_labels = true
|
50
52
|
end
|
51
|
-
private :initialize_ivars
|
52
53
|
|
53
|
-
def
|
54
|
-
@has_left_labels = true
|
54
|
+
def setup_data
|
55
55
|
calculate_maximum_by_stack
|
56
56
|
super
|
57
57
|
end
|
58
58
|
|
59
|
-
protected
|
60
|
-
|
61
59
|
def hide_labels?
|
62
60
|
@hide_labels
|
63
61
|
end
|
@@ -70,9 +68,7 @@ protected
|
|
70
68
|
@hide_line_markers
|
71
69
|
end
|
72
70
|
|
73
|
-
|
74
|
-
|
75
|
-
def draw_bars
|
71
|
+
def draw_graph
|
76
72
|
# Setup spacing.
|
77
73
|
#
|
78
74
|
# Columns sit stacked.
|
@@ -80,7 +76,7 @@ private
|
|
80
76
|
height = Array.new(column_count, 0)
|
81
77
|
length = Array.new(column_count, @graph_left)
|
82
78
|
padding = (bar_width * (1 - @bar_spacing)) / 2
|
83
|
-
|
79
|
+
stack_bar_value_label = Gruff::BarValueLabel::StackedBar.new
|
84
80
|
|
85
81
|
store.norm_data.each_with_index do |data_row, row_index|
|
86
82
|
data_row.points.each_with_index do |data_point, point_index|
|
@@ -91,6 +87,7 @@ private
|
|
91
87
|
height[point_index]) + 1
|
92
88
|
temp2 = @graph_left + @graph_width - height[point_index] - 1
|
93
89
|
difference = temp2 - temp1
|
90
|
+
difference = 0 if row_index == 0 && difference < 0
|
94
91
|
|
95
92
|
left_x = length[point_index]
|
96
93
|
left_y = @graph_top + (bar_width * point_index) + padding
|
@@ -99,14 +96,14 @@ private
|
|
99
96
|
length[point_index] += difference
|
100
97
|
height[point_index] += (data_point * @graph_width - 2)
|
101
98
|
|
102
|
-
bar_value_label
|
103
|
-
bar_value_label
|
99
|
+
bar_value_label = Gruff::BarValueLabel::SideBar.new([left_x, left_y, right_x, right_y], store.data[row_index].points[point_index])
|
100
|
+
stack_bar_value_label.add(bar_value_label, point_index)
|
104
101
|
|
105
102
|
# if a data point is 0 it can result in weird really thing lines
|
106
103
|
# that shouldn't even be there being drawn on top of the existing
|
107
104
|
# bar - this is bad
|
108
105
|
if data_point != 0
|
109
|
-
rect_renderer = Gruff::Renderer::Rectangle.new(color: data_row.color)
|
106
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: data_row.color)
|
110
107
|
rect_renderer.render(left_x, left_y, right_x, right_y)
|
111
108
|
# Calculate center based on bar_width and current row
|
112
109
|
end
|
@@ -118,8 +115,8 @@ private
|
|
118
115
|
end
|
119
116
|
|
120
117
|
if @show_labels_for_bar_values
|
121
|
-
|
122
|
-
draw_value_label(x, y, text
|
118
|
+
stack_bar_value_label.prepare_rendering(@label_formatting, bar_width) do |x, y, text|
|
119
|
+
draw_value_label(x, y, text)
|
123
120
|
end
|
124
121
|
end
|
125
122
|
end
|