gruff 0.13.0-java → 0.16.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +79 -0
- data/.rubocop.yml +29 -31
- data/CHANGELOG.md +43 -0
- data/README.md +11 -5
- data/gruff.gemspec +8 -10
- data/lib/gruff/accumulator_bar.rb +4 -2
- data/lib/gruff/area.rb +9 -12
- data/lib/gruff/bar.rb +46 -31
- data/lib/gruff/base.rb +236 -207
- data/lib/gruff/bezier.rb +6 -8
- data/lib/gruff/box_plot.rb +174 -0
- data/lib/gruff/bullet.rb +17 -16
- data/lib/gruff/candlestick.rb +112 -0
- data/lib/gruff/dot.rb +14 -14
- data/lib/gruff/font.rb +42 -0
- data/lib/gruff/helper/bar_conversion.rb +5 -5
- data/lib/gruff/helper/bar_value_label.rb +26 -20
- data/lib/gruff/helper/stacked_mixin.rb +4 -3
- data/lib/gruff/histogram.rb +9 -7
- data/lib/gruff/line.rb +96 -83
- data/lib/gruff/mini/bar.rb +9 -6
- data/lib/gruff/mini/legend.rb +16 -12
- data/lib/gruff/mini/pie.rb +9 -6
- data/lib/gruff/mini/side_bar.rb +9 -6
- data/lib/gruff/net.rb +16 -22
- data/lib/gruff/patch/rmagick.rb +0 -1
- data/lib/gruff/patch/string.rb +2 -1
- data/lib/gruff/pie.rb +42 -75
- data/lib/gruff/renderer/bezier.rb +8 -9
- data/lib/gruff/renderer/circle.rb +8 -9
- data/lib/gruff/renderer/dash_line.rb +10 -10
- data/lib/gruff/renderer/dot.rb +15 -14
- data/lib/gruff/renderer/ellipse.rb +8 -9
- data/lib/gruff/renderer/line.rb +8 -11
- data/lib/gruff/renderer/polygon.rb +9 -10
- data/lib/gruff/renderer/polyline.rb +8 -9
- data/lib/gruff/renderer/rectangle.rb +11 -8
- data/lib/gruff/renderer/renderer.rb +25 -40
- data/lib/gruff/renderer/text.rb +21 -37
- data/lib/gruff/scatter.rb +86 -85
- data/lib/gruff/side_bar.rb +50 -37
- data/lib/gruff/side_stacked_bar.rb +26 -35
- data/lib/gruff/spider.rb +52 -28
- data/lib/gruff/stacked_area.rb +20 -16
- data/lib/gruff/stacked_bar.rb +44 -22
- data/lib/gruff/store/store.rb +6 -10
- data/lib/gruff/store/xy_data.rb +2 -0
- data/lib/gruff/themes.rb +6 -6
- data/lib/gruff/version.rb +1 -1
- data/lib/gruff.rb +70 -57
- data/rails_generators/gruff/templates/controller.rb +1 -1
- metadata +15 -32
- data/.rubocop_todo.yml +0 -182
- data/.travis.yml +0 -23
- data/assets/plastik/blue.png +0 -0
- data/assets/plastik/green.png +0 -0
- data/assets/plastik/red.png +0 -0
- data/lib/gruff/photo_bar.rb +0 -93
- data/lib/gruff/scene.rb +0 -198
- data/lib/gruff/store/custom_data.rb +0 -36
data/lib/gruff/base.rb
CHANGED
@@ -54,20 +54,18 @@ module Gruff
|
|
54
54
|
# { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
|
55
55
|
attr_writer :labels
|
56
56
|
|
57
|
-
# Used internally for spacing.
|
58
|
-
#
|
59
|
-
# By default, labels are centered over the point they represent.
|
60
|
-
attr_writer :center_labels_over_point
|
61
|
-
|
62
|
-
# Used internally for horizontal graph types. Default is +false+.
|
63
|
-
attr_writer :has_left_labels
|
64
|
-
|
65
57
|
# Set a label for the bottom of the graph.
|
66
58
|
attr_writer :x_axis_label
|
67
59
|
|
68
60
|
# Set a label for the left side of the graph.
|
69
61
|
attr_writer :y_axis_label
|
70
62
|
|
63
|
+
# Allow passing lambda to format labels for x axis.
|
64
|
+
attr_writer :x_axis_label_format
|
65
|
+
|
66
|
+
# Allow passing lambda to format labels for y axis.
|
67
|
+
attr_writer :y_axis_label_format
|
68
|
+
|
71
69
|
# Set increment of the vertical marking lines.
|
72
70
|
attr_writer :x_axis_increment
|
73
71
|
|
@@ -93,15 +91,6 @@ module Gruff
|
|
93
91
|
# Set the large title of the graph displayed at the top.
|
94
92
|
attr_writer :title
|
95
93
|
|
96
|
-
# Same as {#font=} but for the title.
|
97
|
-
attr_writer :title_font
|
98
|
-
|
99
|
-
# Specifies whether to draw the title bolded or not. Default is +true+.
|
100
|
-
attr_writer :bold_title
|
101
|
-
|
102
|
-
# Specifies the text color.
|
103
|
-
attr_writer :font_color
|
104
|
-
|
105
94
|
# Prevent drawing of line markers. Default is +false+.
|
106
95
|
attr_writer :hide_line_markers
|
107
96
|
|
@@ -118,21 +107,9 @@ module Gruff
|
|
118
107
|
# to +"No Data."+.
|
119
108
|
attr_writer :no_data_message
|
120
109
|
|
121
|
-
# Set the font size of the large title at the top of the graph. Default is +36+.
|
122
|
-
attr_writer :title_font_size
|
123
|
-
|
124
|
-
# Optionally set the size of the font. Based on an 800x600px graph.
|
125
|
-
# Default is +20+.
|
126
|
-
#
|
127
|
-
# Will be scaled down if the graph is smaller than 800px wide.
|
128
|
-
attr_writer :legend_font_size
|
129
|
-
|
130
110
|
# Display the legend under the graph. Default is +false+.
|
131
111
|
attr_writer :legend_at_bottom
|
132
112
|
|
133
|
-
# The font size of the labels around the graph. Default is +21+.
|
134
|
-
attr_writer :marker_font_size
|
135
|
-
|
136
113
|
# Set the color of the auxiliary lines.
|
137
114
|
attr_writer :marker_color
|
138
115
|
|
@@ -156,12 +133,6 @@ module Gruff
|
|
156
133
|
# Will be scaled down if graph is smaller than 800px wide.
|
157
134
|
attr_writer :legend_box_size
|
158
135
|
|
159
|
-
# Allow passing lambdas to format labels for x axis.
|
160
|
-
attr_writer :x_axis_label_format
|
161
|
-
|
162
|
-
# Allow passing lambdas to format labels for y axis.
|
163
|
-
attr_writer :y_axis_label_format
|
164
|
-
|
165
136
|
# If one numerical argument is given, the graph is drawn at 4/3 ratio
|
166
137
|
# according to the given width (+800+ results in 800x600, +400+ gives 400x300,
|
167
138
|
# etc.).
|
@@ -180,8 +151,11 @@ module Gruff
|
|
180
151
|
@columns.freeze
|
181
152
|
@rows.freeze
|
182
153
|
|
154
|
+
@has_left_labels = false
|
155
|
+
@center_labels_over_point = true
|
156
|
+
|
183
157
|
initialize_graph_scale
|
184
|
-
|
158
|
+
initialize_attributes
|
185
159
|
initialize_store
|
186
160
|
|
187
161
|
self.theme = Themes::KEYNOTE
|
@@ -209,7 +183,7 @@ module Gruff
|
|
209
183
|
#
|
210
184
|
# This makes it possible to set defaults in a subclass but still allow
|
211
185
|
# developers to change this values in their program.
|
212
|
-
def
|
186
|
+
def initialize_attributes
|
213
187
|
@marker_count = nil
|
214
188
|
@maximum_value = @minimum_value = nil
|
215
189
|
@labels = {}
|
@@ -217,13 +191,9 @@ module Gruff
|
|
217
191
|
@sorted_drawing = false
|
218
192
|
@title = nil
|
219
193
|
|
220
|
-
@title_font =
|
221
|
-
@
|
222
|
-
@
|
223
|
-
|
224
|
-
@marker_font_size = 21.0
|
225
|
-
@legend_font_size = 20.0
|
226
|
-
@title_font_size = 36.0
|
194
|
+
@title_font = Gruff::Font.new(size: 36.0, bold: true)
|
195
|
+
@marker_font = Gruff::Font.new(size: 21.0)
|
196
|
+
@legend_font = Gruff::Font.new(size: 20.0)
|
227
197
|
|
228
198
|
@top_margin = @bottom_margin = @left_margin = @right_margin = DEFAULT_MARGIN
|
229
199
|
@legend_margin = LEGEND_MARGIN
|
@@ -234,8 +204,6 @@ module Gruff
|
|
234
204
|
@no_data_message = 'No Data'
|
235
205
|
|
236
206
|
@hide_line_markers = @hide_legend = @hide_title = @hide_line_numbers = @legend_at_bottom = false
|
237
|
-
@center_labels_over_point = true
|
238
|
-
@has_left_labels = false
|
239
207
|
@label_stagger_height = 0
|
240
208
|
@label_max_size = 0
|
241
209
|
@label_truncation_style = :absolute
|
@@ -247,7 +215,7 @@ module Gruff
|
|
247
215
|
@x_axis_label_format = nil
|
248
216
|
@y_axis_label_format = nil
|
249
217
|
end
|
250
|
-
protected :
|
218
|
+
protected :initialize_attributes
|
251
219
|
|
252
220
|
# Sets the top, bottom, left and right margins to +margin+.
|
253
221
|
#
|
@@ -262,8 +230,62 @@ module Gruff
|
|
262
230
|
# @param font_path [String] The path to font.
|
263
231
|
#
|
264
232
|
def font=(font_path)
|
265
|
-
@
|
266
|
-
|
233
|
+
@title_font.path = font_path unless @title_font.path
|
234
|
+
@marker_font.path = font_path
|
235
|
+
@legend_font.path = font_path
|
236
|
+
end
|
237
|
+
|
238
|
+
# Same as {#font=} but for the title.
|
239
|
+
#
|
240
|
+
# @param font_path [String] The path to font.
|
241
|
+
#
|
242
|
+
def title_font=(font_path)
|
243
|
+
@title_font.path = font_path
|
244
|
+
end
|
245
|
+
|
246
|
+
# Set the font size of the large title at the top of the graph. Default is +36+.
|
247
|
+
#
|
248
|
+
# @param value [Numeric] title font size
|
249
|
+
#
|
250
|
+
def title_font_size=(value)
|
251
|
+
@title_font.size = value
|
252
|
+
end
|
253
|
+
|
254
|
+
# The font size of the labels around the graph. Default is +21+.
|
255
|
+
#
|
256
|
+
# @param value [Numeric] marker font size
|
257
|
+
#
|
258
|
+
def marker_font_size=(value)
|
259
|
+
@marker_font.size = value
|
260
|
+
end
|
261
|
+
|
262
|
+
# Optionally set the size of the font. Based on an 800x600px graph.
|
263
|
+
# Default is +20+.
|
264
|
+
#
|
265
|
+
# Will be scaled down if the graph is smaller than 800px wide.
|
266
|
+
#
|
267
|
+
# @param value [Numeric] legend font size
|
268
|
+
#
|
269
|
+
def legend_font_size=(value)
|
270
|
+
@legend_font.size = value
|
271
|
+
end
|
272
|
+
|
273
|
+
# Specifies whether to draw the title bolded or not. Default is +true+.
|
274
|
+
#
|
275
|
+
# @param value [Boolean] specifies whether to draw the title bolded or not.
|
276
|
+
#
|
277
|
+
def bold_title=(value)
|
278
|
+
@title_font.bold = value
|
279
|
+
end
|
280
|
+
|
281
|
+
# Specifies the text color.
|
282
|
+
#
|
283
|
+
# @param value [String] color
|
284
|
+
#
|
285
|
+
def font_color=(value)
|
286
|
+
@title_font.color = value
|
287
|
+
@marker_font.color = value
|
288
|
+
@legend_font.color = value
|
267
289
|
end
|
268
290
|
|
269
291
|
# Add a color to the list of available colors for lines.
|
@@ -332,12 +354,13 @@ module Gruff
|
|
332
354
|
}
|
333
355
|
@theme_options = defaults.merge options
|
334
356
|
|
357
|
+
self.marker_color = @theme_options[:marker_color]
|
358
|
+
self.font_color = @theme_options[:font_color] || @marker_color
|
359
|
+
|
335
360
|
@colors = @theme_options[:colors]
|
336
|
-
@marker_color = @theme_options[:marker_color]
|
337
361
|
@marker_shadow_color = @theme_options[:marker_shadow_color]
|
338
|
-
@font_color = @theme_options[:font_color] || @marker_color
|
339
362
|
|
340
|
-
Gruff::Renderer.
|
363
|
+
@renderer = Gruff::Renderer.new(@columns, @rows, @scale, @theme_options)
|
341
364
|
end
|
342
365
|
|
343
366
|
# Apply Apple's keynote theme.
|
@@ -399,7 +422,7 @@ module Gruff
|
|
399
422
|
#
|
400
423
|
# Set it after you have given all your data to the graph object.
|
401
424
|
def minimum_value
|
402
|
-
@minimum_value || store.min
|
425
|
+
(@minimum_value || store.min).to_f
|
403
426
|
end
|
404
427
|
attr_writer :minimum_value
|
405
428
|
|
@@ -409,7 +432,7 @@ module Gruff
|
|
409
432
|
# If you use this, you must set it after you have given all your data to
|
410
433
|
# the graph object.
|
411
434
|
def maximum_value
|
412
|
-
@maximum_value || store.max
|
435
|
+
(@maximum_value || store.max).to_f
|
413
436
|
end
|
414
437
|
attr_writer :maximum_value
|
415
438
|
|
@@ -439,8 +462,8 @@ module Gruff
|
|
439
462
|
def to_image
|
440
463
|
@to_image ||= begin
|
441
464
|
draw
|
442
|
-
|
443
|
-
|
465
|
+
renderer.finish
|
466
|
+
renderer.image
|
444
467
|
end
|
445
468
|
end
|
446
469
|
|
@@ -456,32 +479,34 @@ module Gruff
|
|
456
479
|
end
|
457
480
|
end
|
458
481
|
|
459
|
-
|
460
|
-
|
461
|
-
# Overridden by subclasses to do the actual plotting of the graph.
|
462
|
-
#
|
463
|
-
# Subclasses should start by calling super() for this method.
|
482
|
+
# Draw a graph.
|
464
483
|
def draw
|
484
|
+
setup_data
|
485
|
+
|
465
486
|
# Maybe should be done in one of the following functions for more granularity.
|
466
487
|
unless data_given?
|
467
488
|
draw_no_data
|
468
489
|
return
|
469
490
|
end
|
470
491
|
|
471
|
-
setup_data
|
472
492
|
setup_drawing
|
473
493
|
|
474
494
|
draw_legend
|
475
495
|
draw_line_markers
|
476
496
|
draw_axis_labels
|
477
497
|
draw_title
|
498
|
+
draw_graph
|
478
499
|
end
|
479
500
|
|
501
|
+
protected
|
502
|
+
|
503
|
+
attr_reader :renderer
|
504
|
+
|
480
505
|
# Perform data manipulation before calculating chart measurements
|
481
506
|
def setup_data # :nodoc:
|
482
507
|
if @y_axis_increment && !@hide_line_markers
|
483
|
-
self.maximum_value = [@y_axis_increment, maximum_value, (maximum_value
|
484
|
-
self.minimum_value = [minimum_value, (minimum_value
|
508
|
+
self.maximum_value = [@y_axis_increment, maximum_value, (maximum_value / @y_axis_increment).round * @y_axis_increment].max
|
509
|
+
self.minimum_value = [minimum_value, (minimum_value / @y_axis_increment).round * @y_axis_increment].min
|
485
510
|
end
|
486
511
|
end
|
487
512
|
|
@@ -520,7 +545,7 @@ module Gruff
|
|
520
545
|
@marker_count ||= begin
|
521
546
|
count = nil
|
522
547
|
(3..7).each do |lines|
|
523
|
-
if @spread
|
548
|
+
if @spread % lines == 0.0
|
524
549
|
count = lines and break
|
525
550
|
end
|
526
551
|
end
|
@@ -533,8 +558,8 @@ module Gruff
|
|
533
558
|
store.normalize(minimum: minimum_value, spread: @spread)
|
534
559
|
end
|
535
560
|
|
536
|
-
def calculate_spread
|
537
|
-
@spread = maximum_value
|
561
|
+
def calculate_spread
|
562
|
+
@spread = maximum_value - minimum_value
|
538
563
|
@spread = @spread > 0 ? @spread : 1
|
539
564
|
end
|
540
565
|
|
@@ -547,28 +572,24 @@ module Gruff
|
|
547
572
|
end
|
548
573
|
|
549
574
|
def hide_left_label_area?
|
550
|
-
@hide_line_markers
|
575
|
+
@hide_line_markers && @y_axis_label.nil?
|
551
576
|
end
|
552
577
|
|
553
578
|
def hide_bottom_label_area?
|
554
|
-
@hide_line_markers
|
579
|
+
@hide_line_markers && @x_axis_label.nil?
|
555
580
|
end
|
556
581
|
|
557
582
|
##
|
558
583
|
# Calculates size of drawable area, general font dimensions, etc.
|
559
584
|
|
560
585
|
def setup_graph_measurements
|
561
|
-
@marker_caps_height = setup_marker_caps_height
|
562
|
-
@title_caps_height = setup_title_caps_height
|
563
|
-
@legend_caps_height = setup_legend_caps_height
|
564
|
-
|
565
586
|
margin_on_right = graph_right_margin
|
566
587
|
@graph_right = @raw_columns - margin_on_right
|
567
588
|
@graph_left = setup_left_margin
|
568
589
|
@graph_top = setup_top_margin
|
569
590
|
@graph_bottom = setup_bottom_margin
|
570
591
|
|
571
|
-
@graph_width = @
|
592
|
+
@graph_width = @graph_right - @graph_left
|
572
593
|
@graph_height = @graph_bottom - @graph_top
|
573
594
|
end
|
574
595
|
|
@@ -578,17 +599,16 @@ module Gruff
|
|
578
599
|
# X Axis
|
579
600
|
# Centered vertically and horizontally by setting the
|
580
601
|
# height to 1.0 and the width to the width of the graph.
|
581
|
-
x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN +
|
602
|
+
x_axis_label_y_coordinate = @graph_bottom + (LABEL_MARGIN * 2) + marker_caps_height
|
582
603
|
|
583
|
-
|
584
|
-
text_renderer = Gruff::Renderer::Text.new(@x_axis_label, font: @font, size: @marker_font_size, color: @font_color)
|
604
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, @x_axis_label, font: @marker_font)
|
585
605
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
|
586
606
|
end
|
587
607
|
|
588
608
|
if @y_axis_label
|
589
609
|
# Y Axis, rotated vertically
|
590
|
-
text_renderer = Gruff::Renderer::Text.new(@y_axis_label, font: @
|
591
|
-
text_renderer.add_to_render_queue(1.0, @raw_rows, @left_margin +
|
610
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, @y_axis_label, font: @marker_font, rotation: -90)
|
611
|
+
text_renderer.add_to_render_queue(1.0, @raw_rows, @left_margin + (marker_caps_height / 2.0), 0.0, Magick::CenterGravity)
|
592
612
|
end
|
593
613
|
end
|
594
614
|
|
@@ -596,19 +616,19 @@ module Gruff
|
|
596
616
|
def draw_line_markers
|
597
617
|
return if @hide_line_markers
|
598
618
|
|
599
|
-
increment_scaled = @graph_height
|
619
|
+
increment_scaled = @graph_height / (@spread / @increment)
|
600
620
|
|
601
621
|
# Draw horizontal line markers and annotate with numbers
|
602
622
|
(0..marker_count).each do |index|
|
603
|
-
y = @graph_top + @graph_height - index
|
623
|
+
y = @graph_top + @graph_height - (index * increment_scaled)
|
604
624
|
|
605
|
-
|
606
|
-
|
625
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_color).render(@graph_left, y, @graph_right, y)
|
626
|
+
Gruff::Renderer::Line.new(renderer, color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1) if @marker_shadow_color
|
607
627
|
|
608
628
|
unless @hide_line_numbers
|
609
|
-
marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
|
629
|
+
marker_label = (BigDecimal(index.to_s) * BigDecimal(@increment.to_s)) + BigDecimal(minimum_value.to_s)
|
610
630
|
label = y_axis_label(marker_label, @increment)
|
611
|
-
text_renderer = Gruff::Renderer::Text.new(label, font: @
|
631
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font)
|
612
632
|
text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
|
613
633
|
end
|
614
634
|
end
|
@@ -626,45 +646,46 @@ module Gruff
|
|
626
646
|
|
627
647
|
legend_labels = store.data.map(&:label)
|
628
648
|
legend_square_width = @legend_box_size # small square with color of this item
|
629
|
-
|
649
|
+
legend_label_lines = calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
|
650
|
+
line_height = [legend_caps_height, legend_square_width].max + @legend_margin
|
630
651
|
|
631
|
-
current_x_offset = center(label_widths.first.sum)
|
632
652
|
current_y_offset = begin
|
633
653
|
if @legend_at_bottom
|
634
|
-
@graph_bottom + @legend_margin +
|
654
|
+
@graph_bottom + @legend_margin + legend_caps_height + LABEL_MARGIN + (@x_axis_label ? (LABEL_MARGIN * 2) + marker_caps_height : 0)
|
635
655
|
else
|
636
|
-
hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin +
|
656
|
+
hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + title_caps_height
|
637
657
|
end
|
638
658
|
end
|
639
659
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
# Wrap to next line and shrink available graph dimensions
|
665
|
-
current_y_offset += line_height
|
660
|
+
index = 0
|
661
|
+
legend_label_lines.each do |(legend_labels_width, legend_labels_line)|
|
662
|
+
current_x_offset = center(legend_labels_width)
|
663
|
+
|
664
|
+
legend_labels_line.each do |legend_label|
|
665
|
+
unless legend_label.empty?
|
666
|
+
legend_label_width = calculate_width(@legend_font, legend_label)
|
667
|
+
|
668
|
+
# Draw label
|
669
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, legend_label, font: @legend_font)
|
670
|
+
text_renderer.add_to_render_queue(legend_label_width,
|
671
|
+
legend_square_width,
|
672
|
+
current_x_offset + (legend_square_width * 1.7),
|
673
|
+
current_y_offset,
|
674
|
+
Magick::CenterGravity)
|
675
|
+
|
676
|
+
# Now draw box with color of this dataset
|
677
|
+
rect_renderer = Gruff::Renderer::Rectangle.new(renderer, color: store.data[index].color)
|
678
|
+
rect_renderer.render(current_x_offset,
|
679
|
+
current_y_offset,
|
680
|
+
current_x_offset + legend_square_width,
|
681
|
+
current_y_offset + legend_square_width)
|
682
|
+
|
683
|
+
current_x_offset += legend_label_width + (legend_square_width * 2.7)
|
666
684
|
end
|
685
|
+
index += 1
|
667
686
|
end
|
687
|
+
|
688
|
+
current_y_offset += line_height
|
668
689
|
end
|
669
690
|
end
|
670
691
|
|
@@ -672,32 +693,24 @@ module Gruff
|
|
672
693
|
def draw_title
|
673
694
|
return if hide_title?
|
674
695
|
|
675
|
-
|
676
|
-
font_weight = @bold_title ? Magick::BoldWeight : Magick::NormalWeight
|
677
|
-
font_size = @title_font_size
|
678
|
-
|
679
|
-
metrics = Renderer::Text.metrics(@title, font, font_size, font_weight)
|
696
|
+
metrics = text_metrics(@title_font, @title)
|
680
697
|
if metrics.width > @raw_columns
|
681
|
-
|
698
|
+
@title_font.size = @title_font.size * (@raw_columns / metrics.width) * 0.95
|
682
699
|
end
|
683
|
-
|
700
|
+
|
701
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, @title, font: @title_font)
|
684
702
|
text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
|
685
703
|
end
|
686
704
|
|
687
705
|
# Draws column labels below graph, centered over x_offset
|
688
|
-
|
689
|
-
# TODO Allow WestGravity as an option
|
690
|
-
def draw_label(x_offset, index, gravity = Magick::NorthGravity)
|
706
|
+
def draw_label(x_offset, index, gravity = Magick::NorthGravity, &block)
|
691
707
|
draw_unique_label(index) do
|
692
708
|
y_offset = @graph_bottom + LABEL_MARGIN
|
693
|
-
|
694
|
-
# TESTME
|
695
|
-
# FIXME: Consider chart types other than bar
|
696
|
-
# TODO: See if index.odd? is the best stragegy
|
697
709
|
y_offset += @label_stagger_height if index.odd?
|
698
710
|
|
699
711
|
if x_offset >= @graph_left && x_offset <= @graph_right
|
700
712
|
draw_label_at(1.0, 1.0, x_offset, y_offset, @labels[index], gravity)
|
713
|
+
yield if block
|
701
714
|
end
|
702
715
|
end
|
703
716
|
end
|
@@ -714,24 +727,30 @@ module Gruff
|
|
714
727
|
|
715
728
|
def draw_label_at(width, height, x, y, text, gravity = Magick::NorthGravity)
|
716
729
|
label_text = truncate_label_text(text)
|
717
|
-
text_renderer = Gruff::Renderer::Text.new(label_text, font: @
|
730
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label_text, font: @marker_font)
|
718
731
|
text_renderer.add_to_render_queue(width, height, x, y, gravity)
|
719
732
|
end
|
720
733
|
|
721
734
|
# Draws the data value over the data point in bar graphs
|
722
|
-
def draw_value_label(x_offset, y_offset, data_point,
|
723
|
-
return if @hide_line_markers
|
735
|
+
def draw_value_label(width, height, x_offset, y_offset, data_point, gravity = Magick::CenterGravity)
|
736
|
+
return if @hide_line_markers
|
724
737
|
|
725
|
-
|
726
|
-
text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
|
738
|
+
draw_label_at(width, height, x_offset, y_offset, data_point, gravity)
|
727
739
|
end
|
728
740
|
|
729
741
|
# Shows an error message because you have no data.
|
730
742
|
def draw_no_data
|
731
|
-
|
743
|
+
font = @title_font.dup
|
744
|
+
font.size = 80
|
745
|
+
font.bold = false
|
746
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, @no_data_message, font: font)
|
732
747
|
text_renderer.render(@raw_columns, @raw_rows, 0, 0, Magick::CenterGravity)
|
733
748
|
end
|
734
749
|
|
750
|
+
def draw_graph
|
751
|
+
raise 'Should implement this method at inherited class.'
|
752
|
+
end
|
753
|
+
|
735
754
|
# Resets everything to defaults (except data).
|
736
755
|
def reset_themes
|
737
756
|
@theme_options = {}
|
@@ -747,7 +766,7 @@ module Gruff
|
|
747
766
|
end
|
748
767
|
|
749
768
|
def clip_value_if_greater_than(value, max_value) # :nodoc:
|
750
|
-
|
769
|
+
value > max_value ? max_value : value
|
751
770
|
end
|
752
771
|
|
753
772
|
def significant(i) # :nodoc:
|
@@ -793,16 +812,16 @@ module Gruff
|
|
793
812
|
|
794
813
|
private
|
795
814
|
|
796
|
-
def
|
797
|
-
hide_bottom_label_area? ? 0 : calculate_caps_height(@
|
815
|
+
def marker_caps_height
|
816
|
+
hide_bottom_label_area? ? 0 : calculate_caps_height(@marker_font)
|
798
817
|
end
|
799
818
|
|
800
|
-
def
|
801
|
-
hide_title? ? 0 : calculate_caps_height(@
|
819
|
+
def title_caps_height
|
820
|
+
hide_title? ? 0 : calculate_caps_height(@title_font) * @title.lines.to_a.size
|
802
821
|
end
|
803
822
|
|
804
|
-
def
|
805
|
-
@hide_legend ? 0 : calculate_caps_height(@
|
823
|
+
def legend_caps_height
|
824
|
+
@hide_legend ? 0 : calculate_caps_height(@legend_font)
|
806
825
|
end
|
807
826
|
|
808
827
|
def graph_right_margin
|
@@ -813,7 +832,11 @@ module Gruff
|
|
813
832
|
# Make space for half the width of the rightmost column label.
|
814
833
|
# Might be greater than the number of columns if between-style bar markers are used.
|
815
834
|
last_label = @labels.keys.max.to_i
|
816
|
-
|
835
|
+
if last_label >= (column_count - 1) && @center_labels_over_point
|
836
|
+
calculate_width(@marker_font, truncate_label_text(@labels[last_label])) / 2.0
|
837
|
+
else
|
838
|
+
0
|
839
|
+
end
|
817
840
|
end
|
818
841
|
|
819
842
|
def setup_left_margin
|
@@ -821,34 +844,32 @@ module Gruff
|
|
821
844
|
|
822
845
|
text = begin
|
823
846
|
if @has_left_labels
|
824
|
-
@labels.values.reduce('') { |value, memo|
|
847
|
+
@labels.values.reduce('') { |value, memo| value.to_s.length > memo.to_s.length ? value : memo }
|
825
848
|
else
|
826
|
-
y_axis_label(maximum_value
|
849
|
+
y_axis_label(maximum_value, @increment)
|
827
850
|
end
|
828
851
|
end
|
829
|
-
longest_left_label_width = calculate_width(@
|
830
|
-
longest_left_label_width *= 1.25 if @has_left_labels
|
852
|
+
longest_left_label_width = calculate_width(@marker_font, truncate_label_text(text))
|
831
853
|
|
832
854
|
# Shift graph if left line numbers are hidden
|
833
|
-
line_number_width =
|
855
|
+
line_number_width = !@has_left_labels && (@hide_line_markers || @hide_line_numbers) ? 0.0 : (longest_left_label_width + LABEL_MARGIN)
|
834
856
|
|
835
|
-
@left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 :
|
857
|
+
@left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2))
|
836
858
|
end
|
837
859
|
|
838
860
|
def setup_top_margin
|
839
861
|
# When @hide title, leave a title_margin space for aesthetics.
|
840
862
|
# Same with @hide_legend
|
841
863
|
@top_margin +
|
842
|
-
(hide_title? ? @title_margin :
|
843
|
-
(
|
864
|
+
(hide_title? ? @title_margin : title_caps_height + @title_margin) +
|
865
|
+
(@hide_legend || @legend_at_bottom ? @legend_margin : calculate_legend_height + @legend_margin)
|
844
866
|
end
|
845
867
|
|
846
868
|
def setup_bottom_margin
|
847
|
-
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin +
|
869
|
+
graph_bottom_margin = hide_bottom_label_area? ? @bottom_margin : @bottom_margin + marker_caps_height + LABEL_MARGIN
|
848
870
|
graph_bottom_margin += (calculate_legend_height + @legend_margin) if @legend_at_bottom
|
849
871
|
|
850
|
-
x_axis_label_height = @x_axis_label.nil? ? 0.0 :
|
851
|
-
# FIXME: Consider chart types other than bar
|
872
|
+
x_axis_label_height = @x_axis_label.nil? ? 0.0 : marker_caps_height + (LABEL_MARGIN * 2)
|
852
873
|
@raw_rows - graph_bottom_margin - x_axis_label_height - @label_stagger_height
|
853
874
|
end
|
854
875
|
|
@@ -868,29 +889,31 @@ module Gruff
|
|
868
889
|
# Return a formatted string representing a number value that should be
|
869
890
|
# printed as a label.
|
870
891
|
def label(value, increment)
|
871
|
-
label =
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
892
|
+
label = begin
|
893
|
+
if increment
|
894
|
+
if increment >= 10 || (increment * 1) == (increment * 1).to_i.to_f
|
895
|
+
sprintf('%0i', value)
|
896
|
+
elsif increment >= 1.0 || (increment * 10) == (increment * 10).to_i.to_f
|
897
|
+
sprintf('%0.1f', value)
|
898
|
+
elsif increment >= 0.1 || (increment * 100) == (increment * 100).to_i.to_f
|
899
|
+
sprintf('%0.2f', value)
|
900
|
+
elsif increment >= 0.01 || (increment * 1000) == (increment * 1000).to_i.to_f
|
901
|
+
sprintf('%0.3f', value)
|
902
|
+
elsif increment >= 0.001 || (increment * 10_000) == (increment * 10_000).to_i.to_f
|
903
|
+
sprintf('%0.4f', value)
|
904
|
+
else
|
905
|
+
value.to_s
|
906
|
+
end
|
907
|
+
elsif (@spread % (marker_count == 0 ? 1 : marker_count) == 0) || !@y_axis_increment.nil?
|
908
|
+
value.to_i.to_s
|
909
|
+
elsif @spread > 10.0
|
910
|
+
sprintf('%0i', value)
|
911
|
+
elsif @spread >= 3.0
|
912
|
+
sprintf('%0.2f', value)
|
913
|
+
else
|
914
|
+
value.to_s
|
915
|
+
end
|
916
|
+
end
|
894
917
|
|
895
918
|
parts = label.split('.')
|
896
919
|
parts[0] = parts[0].commify
|
@@ -914,44 +937,31 @@ module Gruff
|
|
914
937
|
end
|
915
938
|
|
916
939
|
def calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
|
917
|
-
|
918
|
-
|
940
|
+
label_widths = [[]]
|
941
|
+
label_lines = [[]]
|
919
942
|
legend_labels.each do |label|
|
920
|
-
width = calculate_width(@
|
921
|
-
label_width = width + legend_square_width * 2.7
|
943
|
+
width = calculate_width(@legend_font, label)
|
944
|
+
label_width = width + (legend_square_width * 2.7)
|
922
945
|
label_widths.last.push label_width
|
946
|
+
label_lines.last.push label
|
923
947
|
|
924
948
|
if label_widths.last.sum > (@raw_columns * 0.9)
|
925
949
|
label_widths.push [label_widths.last.pop]
|
950
|
+
label_lines.push [label_lines.last.pop]
|
926
951
|
end
|
927
952
|
end
|
928
953
|
|
929
|
-
label_widths
|
954
|
+
label_widths.map(&:sum).zip(label_lines)
|
930
955
|
end
|
931
956
|
|
932
957
|
def calculate_legend_height
|
933
958
|
return 0.0 if @hide_legend
|
934
959
|
|
935
960
|
legend_labels = store.data.map(&:label)
|
936
|
-
|
937
|
-
|
938
|
-
legend_height = 0.0
|
939
|
-
|
940
|
-
legend_labels.each_with_index do |legend_label, _index|
|
941
|
-
next if legend_label.empty?
|
942
|
-
|
943
|
-
label_widths.first.shift
|
944
|
-
if label_widths.first.empty?
|
945
|
-
label_widths.shift
|
946
|
-
line_height = [@legend_caps_height, legend_square_width].max + @legend_margin
|
947
|
-
unless label_widths.empty?
|
948
|
-
# Wrap to next line and shrink available graph dimensions
|
949
|
-
legend_height += line_height
|
950
|
-
end
|
951
|
-
end
|
952
|
-
end
|
961
|
+
legend_label_lines = calculate_legend_label_widths_for_each_line(legend_labels, @legend_box_size)
|
962
|
+
line_height = [legend_caps_height, @legend_box_size].max
|
953
963
|
|
954
|
-
|
964
|
+
(line_height * legend_label_lines.count) + (@legend_margin * (legend_label_lines.count - 1))
|
955
965
|
end
|
956
966
|
|
957
967
|
# Returns the height of the capital letter 'X' for the current font and
|
@@ -959,8 +969,19 @@ module Gruff
|
|
959
969
|
#
|
960
970
|
# Not scaled since it deals with dimensions that the regular scaling will
|
961
971
|
# handle.
|
962
|
-
def calculate_caps_height(
|
963
|
-
|
972
|
+
def calculate_caps_height(font)
|
973
|
+
calculate_height(font, 'X')
|
974
|
+
end
|
975
|
+
|
976
|
+
# Returns the height of a string at this point size.
|
977
|
+
#
|
978
|
+
# Not scaled since it deals with dimensions that the regular scaling will
|
979
|
+
# handle.
|
980
|
+
def calculate_height(font, text)
|
981
|
+
text = text.to_s
|
982
|
+
return 0 if text.empty?
|
983
|
+
|
984
|
+
metrics = text_metrics(font, text)
|
964
985
|
metrics.height
|
965
986
|
end
|
966
987
|
|
@@ -968,20 +989,24 @@ module Gruff
|
|
968
989
|
#
|
969
990
|
# Not scaled since it deals with dimensions that the regular
|
970
991
|
# scaling will handle.
|
971
|
-
def calculate_width(
|
992
|
+
def calculate_width(font, text)
|
972
993
|
text = text.to_s
|
973
994
|
return 0 if text.empty?
|
974
995
|
|
975
|
-
metrics =
|
996
|
+
metrics = text_metrics(font, text)
|
976
997
|
metrics.width
|
977
998
|
end
|
978
999
|
|
1000
|
+
def text_metrics(font, text)
|
1001
|
+
Gruff::Renderer::Text.new(renderer, text, font: font).metrics
|
1002
|
+
end
|
1003
|
+
|
979
1004
|
def calculate_increment
|
980
1005
|
if @y_axis_increment.nil?
|
981
1006
|
# Try to use a number of horizontal lines that will come out even.
|
982
1007
|
#
|
983
1008
|
# TODO Do the same for larger numbers...100, 75, 50, 25
|
984
|
-
@increment =
|
1009
|
+
@increment = @spread > 0 && marker_count > 0 ? significant(@spread / marker_count) : 1
|
985
1010
|
else
|
986
1011
|
# TODO: Make this work for negative values
|
987
1012
|
self.marker_count = (@spread / @y_axis_increment).to_i
|
@@ -989,9 +1014,13 @@ module Gruff
|
|
989
1014
|
end
|
990
1015
|
end
|
991
1016
|
|
992
|
-
# Used for degree
|
1017
|
+
# Used for degree <=> radian conversions
|
993
1018
|
def deg2rad(angle)
|
994
|
-
angle *
|
1019
|
+
(angle * Math::PI) / 180.0
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
def rad2deg(angle)
|
1023
|
+
(angle / Math::PI) * 180.0
|
995
1024
|
end
|
996
1025
|
end
|
997
1026
|
|