gruff 0.3.1 → 0.3.3
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.
- data.tar.gz.sig +3 -0
- data/History.txt +9 -0
- data/MIT-LICENSE +1 -1
- data/Manifest.txt +7 -0
- data/README.txt +12 -3
- data/Rakefile +3 -1
- data/init.rb +2 -0
- data/lib/gruff/area.rb +1 -1
- data/lib/gruff/bar.rb +1 -1
- data/lib/gruff/base.rb +186 -147
- data/lib/gruff/bullet.rb +109 -0
- data/lib/gruff/line.rb +3 -3
- data/lib/gruff/net.rb +5 -5
- data/lib/gruff/photo_bar.rb +1 -1
- data/lib/gruff/pie.rb +5 -5
- data/lib/gruff/side_bar.rb +1 -1
- data/lib/gruff/side_stacked_bar.rb +2 -2
- data/lib/gruff/spider.rb +4 -4
- data/lib/gruff/stacked_area.rb +2 -1
- data/lib/gruff/stacked_bar.rb +4 -4
- data/rails_generators/gruff/gruff_generator.rb +63 -0
- data/rails_generators/gruff/templates/controller.rb +32 -0
- data/rails_generators/gruff/templates/functional_test.rb +24 -0
- data/test/gruff_test_case.rb +5 -1
- data/test/test_bar.rb +2 -2
- data/test/test_bullet.rb +26 -26
- data/test/test_legend.rb +37 -40
- data/test/test_line.rb +36 -16
- data/test/test_stacked_area.rb +52 -0
- metadata +35 -5
- metadata.gz.sig +2 -0
data.tar.gz.sig
ADDED
data/History.txt
CHANGED
data/MIT-LICENSE
CHANGED
data/Manifest.txt
CHANGED
@@ -30,12 +30,14 @@ assets/pc306715.jpg
|
|
30
30
|
assets/plastik/blue.png
|
31
31
|
assets/plastik/green.png
|
32
32
|
assets/plastik/red.png
|
33
|
+
init.rb
|
33
34
|
lib/gruff.rb
|
34
35
|
lib/gruff/accumulator_bar.rb
|
35
36
|
lib/gruff/area.rb
|
36
37
|
lib/gruff/bar.rb
|
37
38
|
lib/gruff/bar_conversion.rb
|
38
39
|
lib/gruff/base.rb
|
40
|
+
lib/gruff/bullet.rb
|
39
41
|
lib/gruff/deprecated.rb
|
40
42
|
lib/gruff/line.rb
|
41
43
|
lib/gruff/mini/bar.rb
|
@@ -52,11 +54,15 @@ lib/gruff/spider.rb
|
|
52
54
|
lib/gruff/stacked_area.rb
|
53
55
|
lib/gruff/stacked_bar.rb
|
54
56
|
lib/gruff/stacked_mixin.rb
|
57
|
+
rails_generators/gruff/gruff_generator.rb
|
58
|
+
rails_generators/gruff/templates/controller.rb
|
59
|
+
rails_generators/gruff/templates/functional_test.rb
|
55
60
|
test/gruff_test_case.rb
|
56
61
|
test/test_accumulator_bar.rb
|
57
62
|
test/test_area.rb
|
58
63
|
test/test_bar.rb
|
59
64
|
test/test_base.rb
|
65
|
+
test/test_bullet.rb
|
60
66
|
test/test_legend.rb
|
61
67
|
test/test_line.rb
|
62
68
|
test/test_mini_bar.rb
|
@@ -69,4 +75,5 @@ test/test_scene.rb
|
|
69
75
|
test/test_side_bar.rb
|
70
76
|
test/test_sidestacked_bar.rb
|
71
77
|
test/test_spider.rb
|
78
|
+
test/test_stacked_area.rb
|
72
79
|
test/test_stacked_bar.rb
|
data/README.txt
CHANGED
@@ -2,13 +2,22 @@
|
|
2
2
|
|
3
3
|
A library for making beautiful graphs.
|
4
4
|
|
5
|
-
|
5
|
+
== Samples
|
6
6
|
|
7
|
-
|
7
|
+
http://nubyonrails.com/pages/gruff
|
8
8
|
|
9
9
|
== Documentation
|
10
10
|
|
11
|
-
|
11
|
+
http://gruff.rubyforge.org
|
12
|
+
|
13
|
+
See the test suite in test/line_test.rb for examples.
|
14
|
+
|
15
|
+
== Rails Plugin
|
16
|
+
|
17
|
+
Gruff is easy to use with Rails.
|
18
|
+
|
19
|
+
gem install gruff
|
20
|
+
cd vendor/plugins && gem unpack gruff
|
12
21
|
|
13
22
|
== WARNING
|
14
23
|
|
data/Rakefile
CHANGED
@@ -15,7 +15,7 @@ Hoe.new('Gruff', Gruff::VERSION) do |p|
|
|
15
15
|
p.remote_rdoc_dir = '' # Release to root
|
16
16
|
end
|
17
17
|
|
18
|
-
desc "Simple
|
18
|
+
desc "Simple require on packaged files to make sure they are all there"
|
19
19
|
task :verify => :package do
|
20
20
|
# An error message will be displayed if files are missing
|
21
21
|
if system %(ruby -e "require 'pkg/gruff-#{Gruff::VERSION}/lib/gruff'")
|
@@ -23,6 +23,8 @@ task :verify => :package do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
task :release => :verify
|
27
|
+
|
26
28
|
namespace :test do
|
27
29
|
|
28
30
|
desc "Run mini tests"
|
data/init.rb
ADDED
data/lib/gruff/area.rb
CHANGED
@@ -16,7 +16,7 @@ class Gruff::Area < Gruff::Base
|
|
16
16
|
prev_x = prev_y = 0.0
|
17
17
|
@d = @d.fill data_row[DATA_COLOR_INDEX]
|
18
18
|
|
19
|
-
data_row[
|
19
|
+
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, index|
|
20
20
|
# Use incremented x and scaled y
|
21
21
|
new_x = @graph_left + (@x_increment * index)
|
22
22
|
new_y = @graph_top + (@graph_height - data_point * @graph_height)
|
data/lib/gruff/bar.rb
CHANGED
@@ -51,7 +51,7 @@ protected
|
|
51
51
|
# iterate over all normalised data
|
52
52
|
@norm_data.each_with_index do |data_row, row_index|
|
53
53
|
|
54
|
-
data_row[
|
54
|
+
data_row[DATA_VALUES_INDEX].each_with_index do |data_point, point_index|
|
55
55
|
# Use incremented x and scaled y
|
56
56
|
# x
|
57
57
|
left_x = @graph_left + (@bar_width * (row_index + point_index + ((@data.length - 1) * point_index)))
|
data/lib/gruff/base.rb
CHANGED
@@ -3,6 +3,7 @@ require 'RMagick'
|
|
3
3
|
|
4
4
|
require File.dirname(__FILE__) + '/deprecated'
|
5
5
|
|
6
|
+
##
|
6
7
|
# = Gruff. Graphs.
|
7
8
|
#
|
8
9
|
# Author:: Geoffrey Grosenbach boss@topfunky.com
|
@@ -15,10 +16,11 @@ require File.dirname(__FILE__) + '/deprecated'
|
|
15
16
|
# Breijs, Richard Cowin, and a cast of thousands.
|
16
17
|
#
|
17
18
|
# See Gruff::Base#theme= for setting themes.
|
19
|
+
|
18
20
|
module Gruff
|
19
21
|
|
20
22
|
# This is the version of Gruff you are using.
|
21
|
-
VERSION = '0.3.
|
23
|
+
VERSION = '0.3.3'
|
22
24
|
|
23
25
|
class Base
|
24
26
|
|
@@ -26,7 +28,7 @@ module Gruff
|
|
26
28
|
include Deprecated
|
27
29
|
|
28
30
|
# Draw extra lines showing where the margins and text centers are
|
29
|
-
DEBUG =
|
31
|
+
DEBUG = true
|
30
32
|
|
31
33
|
# Used for navigating the array of data to plot
|
32
34
|
DATA_LABEL_INDEX = 0
|
@@ -176,7 +178,7 @@ module Gruff
|
|
176
178
|
@rows = geometric_height.to_f
|
177
179
|
else
|
178
180
|
@columns = target_width.to_f
|
179
|
-
@rows = target_width.to_f * 0.75
|
181
|
+
@rows = target_width.to_f * 0.75
|
180
182
|
end
|
181
183
|
|
182
184
|
initialize_ivars
|
@@ -213,7 +215,7 @@ module Gruff
|
|
213
215
|
@marker_font_size = 21.0
|
214
216
|
@legend_font_size = 20.0
|
215
217
|
@title_font_size = 36.0
|
216
|
-
|
218
|
+
|
217
219
|
@legend_box_size = 20.0
|
218
220
|
|
219
221
|
@no_data_message = "No Data"
|
@@ -222,10 +224,10 @@ module Gruff
|
|
222
224
|
@center_labels_over_point = true
|
223
225
|
@has_left_labels = false
|
224
226
|
|
225
|
-
@additional_line_values = []
|
227
|
+
@additional_line_values = []
|
226
228
|
@additional_line_colors = []
|
227
229
|
@theme_options = {}
|
228
|
-
|
230
|
+
|
229
231
|
@x_axis_label = @y_axis_label = nil
|
230
232
|
@y_axis_increment = nil
|
231
233
|
@stacked = nil
|
@@ -276,7 +278,7 @@ module Gruff
|
|
276
278
|
#
|
277
279
|
def theme=(options)
|
278
280
|
reset_themes()
|
279
|
-
|
281
|
+
|
280
282
|
defaults = {
|
281
283
|
:colors => ['black', 'white'],
|
282
284
|
:additional_line_colors => [],
|
@@ -291,7 +293,7 @@ module Gruff
|
|
291
293
|
@marker_color = @theme_options[:marker_color]
|
292
294
|
@font_color = @theme_options[:font_color] || @marker_color
|
293
295
|
@additional_line_colors = @theme_options[:additional_line_colors]
|
294
|
-
|
296
|
+
|
295
297
|
render_background
|
296
298
|
end
|
297
299
|
|
@@ -347,7 +349,7 @@ module Gruff
|
|
347
349
|
@light_grey = '#999999'
|
348
350
|
@black = 'black'
|
349
351
|
@colors = [@green, @grey, @orange, @red, @white, @light_grey, @black]
|
350
|
-
|
352
|
+
|
351
353
|
self.theme = {
|
352
354
|
:colors => @colors,
|
353
355
|
:marker_color => 'white',
|
@@ -367,7 +369,7 @@ module Gruff
|
|
367
369
|
@dark_blue = '#3a5b87'
|
368
370
|
@black = 'black'
|
369
371
|
@colors = [@grey, @white, @dark_blue, @dark_pink, @green, @light_grey, @black]
|
370
|
-
|
372
|
+
|
371
373
|
self.theme = {
|
372
374
|
:colors => @colors,
|
373
375
|
:marker_color => 'white',
|
@@ -380,15 +382,15 @@ module Gruff
|
|
380
382
|
def theme_pastel
|
381
383
|
# Colors
|
382
384
|
@colors = [
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
385
|
+
'#a9dada', # blue
|
386
|
+
'#aedaa9', # green
|
387
|
+
'#daaea9', # peach
|
388
|
+
'#dadaa9', # yellow
|
389
|
+
'#a9a9da', # dk purple
|
390
|
+
'#daaeda', # purple
|
391
|
+
'#dadada' # grey
|
392
|
+
]
|
393
|
+
|
392
394
|
self.theme = {
|
393
395
|
:colors => @colors,
|
394
396
|
:marker_color => '#aea9a9', # Grey
|
@@ -401,14 +403,14 @@ module Gruff
|
|
401
403
|
def theme_greyscale
|
402
404
|
# Colors
|
403
405
|
@colors = [
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
406
|
+
'#282828', #
|
407
|
+
'#383838', #
|
408
|
+
'#686868', #
|
409
|
+
'#989898', #
|
410
|
+
'#c8c8c8', #
|
411
|
+
'#e8e8e8', #
|
412
|
+
]
|
413
|
+
|
412
414
|
self.theme = {
|
413
415
|
:colors => @colors,
|
414
416
|
:marker_color => '#aea9a9', # Grey
|
@@ -440,7 +442,7 @@ module Gruff
|
|
440
442
|
# Pre-normalize
|
441
443
|
data_points.each_with_index do |data_point, index|
|
442
444
|
next if data_point.nil?
|
443
|
-
|
445
|
+
|
444
446
|
# Setup max/min so spread starts at the low end of the data points
|
445
447
|
if @maximum_value.nil? && @minimum_value.nil?
|
446
448
|
@maximum_value = @minimum_value = data_point
|
@@ -450,9 +452,9 @@ module Gruff
|
|
450
452
|
# Original: @maximum_value = larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
|
451
453
|
@maximum_value = larger_than_max?(data_point) ? data_point : @maximum_value
|
452
454
|
@has_data = true if @maximum_value > 0
|
453
|
-
|
455
|
+
|
454
456
|
@minimum_value = less_than_min?(data_point) ? data_point : @minimum_value
|
455
|
-
|
457
|
+
@has_data = true if @minimum_value < 0
|
456
458
|
end
|
457
459
|
end
|
458
460
|
|
@@ -469,13 +471,13 @@ module Gruff
|
|
469
471
|
def to_blob(fileformat='PNG')
|
470
472
|
draw()
|
471
473
|
return @base_image.to_blob do
|
472
|
-
|
474
|
+
self.format = fileformat
|
473
475
|
end
|
474
476
|
end
|
475
477
|
|
476
|
-
|
477
478
|
|
478
|
-
|
479
|
+
|
480
|
+
protected
|
479
481
|
|
480
482
|
# Overridden by subclasses to do the actual plotting of the graph.
|
481
483
|
#
|
@@ -483,11 +485,11 @@ protected
|
|
483
485
|
def draw
|
484
486
|
make_stacked if @stacked
|
485
487
|
setup_drawing
|
486
|
-
|
488
|
+
|
487
489
|
debug {
|
488
490
|
# Outer margin
|
489
|
-
@d.rectangle( @left_margin, @top_margin,
|
490
|
-
|
491
|
+
@d.rectangle( @left_margin, @top_margin,
|
492
|
+
@raw_columns - @right_margin, @raw_rows - @bottom_margin)
|
491
493
|
# Graph area box
|
492
494
|
@d.rectangle( @graph_left, @graph_top, @graph_right, @graph_bottom)
|
493
495
|
}
|
@@ -504,11 +506,11 @@ protected
|
|
504
506
|
draw_no_data()
|
505
507
|
return
|
506
508
|
end
|
507
|
-
|
509
|
+
|
508
510
|
normalize()
|
509
511
|
setup_graph_measurements()
|
510
512
|
sort_norm_data() if @sort # Sort norm_data with avg largest values set first (for display)
|
511
|
-
|
513
|
+
|
512
514
|
draw_legend()
|
513
515
|
draw_line_markers()
|
514
516
|
draw_axis_labels()
|
@@ -520,9 +522,9 @@ protected
|
|
520
522
|
if @norm_data.nil? || force
|
521
523
|
@norm_data = []
|
522
524
|
return unless @has_data
|
523
|
-
|
525
|
+
|
524
526
|
calculate_spread
|
525
|
-
|
527
|
+
|
526
528
|
@data.each do |data_row|
|
527
529
|
norm_data_points = []
|
528
530
|
data_row[DATA_VALUES_INDEX].each do |data_point|
|
@@ -542,47 +544,50 @@ protected
|
|
542
544
|
@spread = @spread > 0 ? @spread : 1
|
543
545
|
end
|
544
546
|
|
547
|
+
##
|
545
548
|
# Calculates size of drawable area, general font dimensions, etc.
|
549
|
+
|
546
550
|
def setup_graph_measurements
|
547
551
|
@marker_caps_height = @hide_line_markers ? 0 :
|
548
|
-
|
552
|
+
calculate_caps_height(@marker_font_size)
|
549
553
|
@title_caps_height = @hide_title ? 0 :
|
550
|
-
|
554
|
+
calculate_caps_height(@title_font_size)
|
551
555
|
@legend_caps_height = @hide_legend ? 0 :
|
552
|
-
|
556
|
+
calculate_caps_height(@legend_font_size)
|
553
557
|
|
554
558
|
if @hide_line_markers
|
555
559
|
(@graph_left,
|
556
|
-
|
557
|
-
|
560
|
+
@graph_right_margin,
|
561
|
+
@graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
|
558
562
|
else
|
559
563
|
longest_left_label_width = 0
|
560
564
|
if @has_left_labels
|
561
565
|
longest_left_label_width = calculate_width(@marker_font_size,
|
562
|
-
|
566
|
+
labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
|
563
567
|
else
|
564
|
-
longest_left_label_width = calculate_width(@marker_font_size,
|
565
|
-
|
568
|
+
longest_left_label_width = calculate_width(@marker_font_size,
|
569
|
+
label(@maximum_value.to_f))
|
566
570
|
end
|
567
571
|
|
568
572
|
# Shift graph if left line numbers are hidden
|
569
|
-
line_number_width = @hide_line_numbers && !@has_left_labels ?
|
570
|
-
|
571
|
-
|
573
|
+
line_number_width = @hide_line_numbers && !@has_left_labels ?
|
574
|
+
0.0 :
|
575
|
+
(longest_left_label_width + LABEL_MARGIN * 2)
|
576
|
+
|
577
|
+
@graph_left = @left_margin +
|
578
|
+
line_number_width +
|
579
|
+
(@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
|
572
580
|
|
573
|
-
@graph_left = @left_margin +
|
574
|
-
line_number_width +
|
575
|
-
(@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
|
576
581
|
# Make space for half the width of the rightmost column label.
|
577
582
|
# Might be greater than the number of columns if between-style bar markers are used.
|
578
583
|
last_label = @labels.keys.sort.last.to_i
|
579
584
|
extra_room_for_long_label = (last_label >= (@column_count-1) && @center_labels_over_point) ?
|
580
|
-
|
581
|
-
|
582
|
-
@graph_right_margin =
|
583
|
-
|
584
|
-
@graph_bottom_margin =
|
585
|
-
|
585
|
+
calculate_width(@marker_font_size, @labels[last_label]) / 2.0 :
|
586
|
+
0
|
587
|
+
@graph_right_margin = @right_margin + extra_room_for_long_label
|
588
|
+
|
589
|
+
@graph_bottom_margin = @bottom_margin +
|
590
|
+
@marker_caps_height + LABEL_MARGIN
|
586
591
|
end
|
587
592
|
|
588
593
|
@graph_right = @raw_columns - @graph_right_margin
|
@@ -590,12 +595,12 @@ protected
|
|
590
595
|
|
591
596
|
# When @hide title, leave a TITLE_MARGIN space for aesthetics.
|
592
597
|
# Same with @hide_legend
|
593
|
-
@graph_top = @top_margin +
|
594
|
-
|
595
|
-
|
598
|
+
@graph_top = @top_margin +
|
599
|
+
(@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) +
|
600
|
+
(@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2)
|
596
601
|
|
597
602
|
x_axis_label_height = @x_axis_label.nil? ? 0.0 :
|
598
|
-
|
603
|
+
@marker_caps_height + LABEL_MARGIN
|
599
604
|
@graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height
|
600
605
|
@graph_height = @graph_bottom - @graph_top
|
601
606
|
end
|
@@ -614,10 +619,10 @@ protected
|
|
614
619
|
@d.stroke('transparent')
|
615
620
|
@d.pointsize = scale_fontsize(@marker_font_size)
|
616
621
|
@d.gravity = NorthGravity
|
617
|
-
@d = @d.annotate_scaled( @base_image,
|
618
|
-
|
619
|
-
|
620
|
-
|
622
|
+
@d = @d.annotate_scaled( @base_image,
|
623
|
+
@raw_columns, 1.0,
|
624
|
+
0.0, x_axis_label_y_coordinate,
|
625
|
+
@x_axis_label, @scale)
|
621
626
|
debug { @d.line 0.0, x_axis_label_y_coordinate, @raw_columns, x_axis_label_y_coordinate }
|
622
627
|
end
|
623
628
|
|
@@ -625,10 +630,10 @@ protected
|
|
625
630
|
# Y Axis, rotated vertically
|
626
631
|
@d.rotation = 90.0
|
627
632
|
@d.gravity = CenterGravity
|
628
|
-
@d = @d.annotate_scaled( @base_image,
|
629
|
-
|
630
|
-
|
631
|
-
|
633
|
+
@d = @d.annotate_scaled( @base_image,
|
634
|
+
1.0, @raw_rows,
|
635
|
+
@left_margin + @marker_caps_height / 2.0, 0.0,
|
636
|
+
@y_axis_label, @scale)
|
632
637
|
@d.rotation = -90.0
|
633
638
|
end
|
634
639
|
end
|
@@ -636,9 +641,9 @@ protected
|
|
636
641
|
# Draws horizontal background lines and labels
|
637
642
|
def draw_line_markers
|
638
643
|
return if @hide_line_markers
|
639
|
-
|
644
|
+
|
640
645
|
@d = @d.stroke_antialias false
|
641
|
-
|
646
|
+
|
642
647
|
if @y_axis_increment.nil?
|
643
648
|
# Try to use a number of horizontal lines that will come out even.
|
644
649
|
#
|
@@ -659,7 +664,7 @@ protected
|
|
659
664
|
@minimum_value = @minimum_value.floor
|
660
665
|
calculate_spread
|
661
666
|
normalize(true)
|
662
|
-
|
667
|
+
|
663
668
|
@marker_count = (@spread / @y_axis_increment).to_i
|
664
669
|
@increment = @y_axis_increment
|
665
670
|
end
|
@@ -668,7 +673,7 @@ protected
|
|
668
673
|
# Draw horizontal line markers and annotate with numbers
|
669
674
|
(0..@marker_count).each do |index|
|
670
675
|
y = @graph_top + @graph_height - index.to_f * @increment_scaled
|
671
|
-
|
676
|
+
|
672
677
|
@d = @d.stroke(@marker_color)
|
673
678
|
@d = @d.stroke_width 1
|
674
679
|
@d = @d.line(@graph_left, y, @graph_right, y)
|
@@ -681,43 +686,61 @@ protected
|
|
681
686
|
@d.stroke('transparent')
|
682
687
|
@d.pointsize = scale_fontsize(@marker_font_size)
|
683
688
|
@d.gravity = EastGravity
|
684
|
-
|
689
|
+
|
685
690
|
# Vertically center with 1.0 for the height
|
686
|
-
@d = @d.annotate_scaled( @base_image,
|
687
|
-
|
688
|
-
|
689
|
-
|
691
|
+
@d = @d.annotate_scaled( @base_image,
|
692
|
+
@graph_left - LABEL_MARGIN, 1.0,
|
693
|
+
0.0, y,
|
694
|
+
label(marker_label), @scale)
|
690
695
|
end
|
691
696
|
end
|
692
|
-
|
697
|
+
|
693
698
|
# # Submitted by a contibutor...the utility escapes me
|
694
699
|
# i = 0
|
695
700
|
# @additional_line_values.each do |value|
|
696
701
|
# @increment_scaled = @graph_height.to_f / (@maximum_value.to_f / value)
|
697
|
-
#
|
702
|
+
#
|
698
703
|
# y = @graph_top + @graph_height - @increment_scaled
|
699
|
-
#
|
704
|
+
#
|
700
705
|
# @d = @d.stroke(@additional_line_colors[i])
|
701
706
|
# @d = @d.line(@graph_left, y, @graph_right, y)
|
702
|
-
#
|
703
|
-
#
|
707
|
+
#
|
708
|
+
#
|
704
709
|
# @d.fill = @additional_line_colors[i]
|
705
710
|
# @d.font = @font if @font
|
706
711
|
# @d.stroke('transparent')
|
707
712
|
# @d.pointsize = scale_fontsize(@marker_font_size)
|
708
713
|
# @d.gravity = EastGravity
|
709
|
-
# @d = @d.annotate_scaled( @base_image,
|
714
|
+
# @d = @d.annotate_scaled( @base_image,
|
710
715
|
# 100, 20,
|
711
|
-
# -10, y - (@marker_font_size/2.0),
|
716
|
+
# -10, y - (@marker_font_size/2.0),
|
712
717
|
# "", @scale)
|
713
|
-
# i += 1
|
718
|
+
# i += 1
|
714
719
|
# end
|
715
|
-
|
720
|
+
|
716
721
|
@d = @d.stroke_antialias true
|
717
722
|
end
|
718
723
|
|
719
|
-
|
720
|
-
#
|
724
|
+
##
|
725
|
+
# Return the sum of values in an array.
|
726
|
+
#
|
727
|
+
# Duplicated to not conflict with active_support in Rails.
|
728
|
+
|
729
|
+
def sum(arr)
|
730
|
+
arr.inject(0) { |i, m| m + i }
|
731
|
+
end
|
732
|
+
|
733
|
+
##
|
734
|
+
# Return a calculation of center
|
735
|
+
|
736
|
+
def center(size)
|
737
|
+
(@raw_columns - size) / 2
|
738
|
+
end
|
739
|
+
|
740
|
+
##
|
741
|
+
# Draws a legend with the names of the datasets matched
|
742
|
+
# to the colors used to draw them.
|
743
|
+
|
721
744
|
def draw_legend
|
722
745
|
return if @hide_legend
|
723
746
|
|
@@ -729,23 +752,23 @@ protected
|
|
729
752
|
@d.font = @font if @font
|
730
753
|
@d.pointsize = @legend_font_size
|
731
754
|
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
755
|
+
label_widths = [[]] # Used to calculate line wrap
|
756
|
+
@legend_labels.each do |label|
|
757
|
+
metrics = @d.get_type_metrics(@base_image, label.to_s)
|
758
|
+
label_width = metrics.width + legend_square_width * 2.7
|
759
|
+
label_widths.last.push label_width
|
760
|
+
|
761
|
+
if sum(label_widths.last) > (@raw_columns * 0.9)
|
762
|
+
label_widths.push [label_widths.last.pop]
|
763
|
+
end
|
764
|
+
end
|
738
765
|
|
739
|
-
current_x_offset =
|
740
|
-
current_y_offset = @hide_title ?
|
741
|
-
|
742
|
-
|
743
|
-
TITLE_MARGIN + @title_caps_height +
|
744
|
-
LEGEND_MARGIN
|
766
|
+
current_x_offset = center(sum(label_widths.first))
|
767
|
+
current_y_offset = @hide_title ?
|
768
|
+
@top_margin + LEGEND_MARGIN :
|
769
|
+
@top_margin + TITLE_MARGIN + @title_caps_height + LEGEND_MARGIN
|
745
770
|
|
746
|
-
|
747
|
-
|
748
|
-
@legend_labels.each_with_index do |legend_label, index|
|
771
|
+
@legend_labels.each_with_index do |legend_label, index|
|
749
772
|
|
750
773
|
# Draw label
|
751
774
|
@d.fill = @font_color
|
@@ -754,23 +777,40 @@ protected
|
|
754
777
|
@d.stroke('transparent')
|
755
778
|
@d.font_weight = NormalWeight
|
756
779
|
@d.gravity = WestGravity
|
757
|
-
@d = @d.annotate_scaled( @base_image,
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
780
|
+
@d = @d.annotate_scaled( @base_image,
|
781
|
+
@raw_columns, 1.0,
|
782
|
+
current_x_offset + (legend_square_width * 1.7), current_y_offset,
|
783
|
+
legend_label.to_s, @scale)
|
784
|
+
|
762
785
|
# Now draw box with color of this dataset
|
763
786
|
@d = @d.stroke('transparent')
|
764
787
|
@d = @d.fill @data[index][DATA_COLOR_INDEX]
|
765
|
-
@d = @d.rectangle(current_x_offset,
|
766
|
-
|
767
|
-
|
768
|
-
|
788
|
+
@d = @d.rectangle(current_x_offset,
|
789
|
+
current_y_offset - legend_square_width / 2.0,
|
790
|
+
current_x_offset + legend_square_width,
|
791
|
+
current_y_offset + legend_square_width / 2.0)
|
769
792
|
|
770
793
|
@d.pointsize = @legend_font_size
|
771
794
|
metrics = @d.get_type_metrics(@base_image, legend_label.to_s)
|
772
795
|
current_string_offset = metrics.width + (legend_square_width * 2.7)
|
773
|
-
|
796
|
+
|
797
|
+
# Handle wrapping
|
798
|
+
label_widths.first.shift
|
799
|
+
if label_widths.first.empty?
|
800
|
+
debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
|
801
|
+
|
802
|
+
label_widths.shift
|
803
|
+
current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
|
804
|
+
line_height = [@legend_caps_height, legend_square_width].max + LEGEND_MARGIN
|
805
|
+
if label_widths.length > 0
|
806
|
+
# Wrap to next line and shrink available graph dimensions
|
807
|
+
current_y_offset += line_height
|
808
|
+
@graph_top += line_height
|
809
|
+
@graph_height = @graph_bottom - @graph_top
|
810
|
+
end
|
811
|
+
else
|
812
|
+
current_x_offset += current_string_offset
|
813
|
+
end
|
774
814
|
end
|
775
815
|
@color_index = 0
|
776
816
|
end
|
@@ -785,10 +825,10 @@ protected
|
|
785
825
|
@d.pointsize = scale_fontsize(@title_font_size)
|
786
826
|
@d.font_weight = BoldWeight
|
787
827
|
@d.gravity = NorthGravity
|
788
|
-
@d = @d.annotate_scaled( @base_image,
|
789
|
-
|
790
|
-
|
791
|
-
|
828
|
+
@d = @d.annotate_scaled( @base_image,
|
829
|
+
@raw_columns, 1.0,
|
830
|
+
0, @top_margin,
|
831
|
+
@title, @scale)
|
792
832
|
end
|
793
833
|
|
794
834
|
# Draws column labels below graph, centered over x_offset
|
@@ -807,9 +847,9 @@ protected
|
|
807
847
|
@d.pointsize = scale_fontsize(@marker_font_size)
|
808
848
|
@d.gravity = NorthGravity
|
809
849
|
@d = @d.annotate_scaled(@base_image,
|
810
|
-
|
811
|
-
|
812
|
-
|
850
|
+
1.0, 1.0,
|
851
|
+
x_offset, y_offset,
|
852
|
+
@labels[index], @scale)
|
813
853
|
@labels_seen[index] = 1
|
814
854
|
debug { @d.line 0.0, y_offset, @raw_columns, y_offset }
|
815
855
|
end
|
@@ -817,16 +857,16 @@ protected
|
|
817
857
|
|
818
858
|
# Shows an error message because you have no data.
|
819
859
|
def draw_no_data
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
860
|
+
@d.fill = @font_color
|
861
|
+
@d.font = @font if @font
|
862
|
+
@d.stroke('transparent')
|
863
|
+
@d.font_weight = NormalWeight
|
864
|
+
@d.pointsize = scale_fontsize(80)
|
865
|
+
@d.gravity = CenterGravity
|
866
|
+
@d = @d.annotate_scaled( @base_image,
|
867
|
+
@raw_columns, @raw_rows/2.0,
|
868
|
+
0, 10,
|
869
|
+
@no_data_message, @scale)
|
830
870
|
end
|
831
871
|
|
832
872
|
# Finds the best background to render based on the provided theme options.
|
@@ -852,8 +892,8 @@ protected
|
|
852
892
|
|
853
893
|
# Use with a theme definition method to draw a gradiated background.
|
854
894
|
def render_gradiated_background(top_color, bottom_color)
|
855
|
-
Image.new(@columns, @rows,
|
856
|
-
|
895
|
+
Image.new(@columns, @rows,
|
896
|
+
GradientFill.new(0, 0, 100, 0, top_color, bottom_color))
|
857
897
|
end
|
858
898
|
|
859
899
|
# Use with a theme to use an image (800x600 original) background.
|
@@ -903,7 +943,7 @@ protected
|
|
903
943
|
data_point > @maximum_value
|
904
944
|
end
|
905
945
|
|
906
|
-
|
946
|
+
def less_than_min?(data_point, index=0) # :nodoc:
|
907
947
|
data_point < @minimum_value
|
908
948
|
end
|
909
949
|
|
@@ -913,7 +953,7 @@ protected
|
|
913
953
|
end
|
914
954
|
|
915
955
|
# Overridden by subclasses that need it.
|
916
|
-
|
956
|
+
def min(data_point, index) # :nodoc:
|
917
957
|
data_point
|
918
958
|
end
|
919
959
|
|
@@ -941,7 +981,7 @@ protected
|
|
941
981
|
# Sort with largest overall summed value at front of array so it shows up
|
942
982
|
# correctly in the drawn graph.
|
943
983
|
def sort_norm_data
|
944
|
-
@norm_data.sort! { |a,b| sums(b[
|
984
|
+
@norm_data.sort! { |a,b| sums(b[DATA_VALUES_INDEX]) <=> sums(a[DATA_VALUES_INDEX]) }
|
945
985
|
end
|
946
986
|
|
947
987
|
def sums(data_set) # :nodoc:
|
@@ -973,14 +1013,14 @@ protected
|
|
973
1013
|
def make_stacked # :nodoc:
|
974
1014
|
stacked_values = Array.new(@column_count, 0)
|
975
1015
|
@data.each do |value_set|
|
976
|
-
value_set[
|
1016
|
+
value_set[DATA_VALUES_INDEX].each_with_index do |value, index|
|
977
1017
|
stacked_values[index] += value
|
978
1018
|
end
|
979
|
-
value_set[
|
1019
|
+
value_set[DATA_VALUES_INDEX] = stacked_values.dup
|
980
1020
|
end
|
981
1021
|
end
|
982
1022
|
|
983
|
-
private
|
1023
|
+
private
|
984
1024
|
|
985
1025
|
# Takes a block and draws it if DEBUG is true.
|
986
1026
|
#
|
@@ -1039,7 +1079,7 @@ private
|
|
1039
1079
|
|
1040
1080
|
# Returns the width of a string at this pointsize.
|
1041
1081
|
#
|
1042
|
-
# Not scaled since it deals with dimensions that the regular
|
1082
|
+
# Not scaled since it deals with dimensions that the regular
|
1043
1083
|
# scaling will handle.
|
1044
1084
|
def calculate_width(font_size, text)
|
1045
1085
|
@d.pointsize = font_size
|
@@ -1062,12 +1102,11 @@ module Magick
|
|
1062
1102
|
scaled_height = (height * scale) >= 1 ? (height * scale) : 1
|
1063
1103
|
|
1064
1104
|
self.annotate( img,
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1105
|
+
scaled_width, scaled_height,
|
1106
|
+
x * scale, y * scale,
|
1107
|
+
text)
|
1068
1108
|
end
|
1069
1109
|
|
1070
1110
|
end
|
1071
1111
|
|
1072
1112
|
end # Magick
|
1073
|
-
|