gruff 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ K���L'G�X��W�R=r�a<p�"D�Íj/��P���G���CU&��ܱ��{s�ƈvE��
2
+ �_��P�{�76��oފ��I@u3BJ���$q��QXA
3
+ �7���u�&Wؔ5�uZ���m�F�c���s;�"�h�ԑx�%�qP�R�K(x?g�v�S1ҼV���ں|�
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.3.3
2
+
3
+ * Legend line wrapping [Mat Schaffer]
4
+ * Stacked area graph fixes [James Coglan]
5
+
6
+ == 0.3.2
7
+
8
+ * Include init.rb for use as a Rails plugin.
9
+
1
10
  == 0.3.1
2
11
 
3
12
  * Fixed missing bullet graph bug (experimental, will be in a future release).
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005 Geoffrey Grosenbach boss@topfunky.com
1
+ Copyright (c) 2005-2008 Topfunky Corporation boss@topfunky.com
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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
- See samples at http://nubyonrails.com/pages/gruff
5
+ == Samples
6
6
 
7
- See the test suite in test/line_test.rb for examples.
7
+ http://nubyonrails.com/pages/gruff
8
8
 
9
9
  == Documentation
10
10
 
11
- Most of the documentation is in the Gruff::Base class.
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 test on packaged files to make sure they are all there"
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
@@ -0,0 +1,2 @@
1
+ # For Rails
2
+ require 'gruff'
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[1].each_with_index do |data_point, index|
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[1].each_with_index do |data_point, point_index|
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.1'
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 = false
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
- '#a9dada', # blue
384
- '#aedaa9', # green
385
- '#daaea9', # peach
386
- '#dadaa9', # yellow
387
- '#a9a9da', # dk purple
388
- '#daaeda', # purple
389
- '#dadada' # grey
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
- '#282828', #
405
- '#383838', #
406
- '#686868', #
407
- '#989898', #
408
- '#c8c8c8', #
409
- '#e8e8e8', #
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
- @has_data = true if @minimum_value < 0
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
- self.format = fileformat
474
+ self.format = fileformat
473
475
  end
474
476
  end
475
477
 
476
-
477
478
 
478
- protected
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
- @raw_columns - @right_margin, @raw_rows - @bottom_margin)
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
- calculate_caps_height(@marker_font_size)
552
+ calculate_caps_height(@marker_font_size)
549
553
  @title_caps_height = @hide_title ? 0 :
550
- calculate_caps_height(@title_font_size)
554
+ calculate_caps_height(@title_font_size)
551
555
  @legend_caps_height = @hide_legend ? 0 :
552
- calculate_caps_height(@legend_font_size)
556
+ calculate_caps_height(@legend_font_size)
553
557
 
554
558
  if @hide_line_markers
555
559
  (@graph_left,
556
- @graph_right_margin,
557
- @graph_bottom_margin) = [@left_margin, @right_margin, @bottom_margin]
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
- labels.values.inject('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
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
- label(@maximum_value.to_f))
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
- 0.0 :
571
- (longest_left_label_width + LABEL_MARGIN * 2)
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
- calculate_width(@marker_font_size, @labels[last_label])/2.0 :
581
- 0
582
- @graph_right_margin = @right_margin + extra_room_for_long_label
583
-
584
- @graph_bottom_margin = @bottom_margin +
585
- @marker_caps_height + LABEL_MARGIN
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
- (@hide_title ? TITLE_MARGIN : @title_caps_height + TITLE_MARGIN * 2) +
595
- (@hide_legend ? LEGEND_MARGIN : @legend_caps_height + LEGEND_MARGIN * 2)
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
- @marker_caps_height + LABEL_MARGIN
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
- @raw_columns, 1.0,
619
- 0.0, x_axis_label_y_coordinate,
620
- @x_axis_label, @scale)
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
- 1.0, @raw_rows,
630
- @left_margin + @marker_caps_height / 2.0, 0.0,
631
- @y_axis_label, @scale)
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
- @graph_left - LABEL_MARGIN, 1.0,
688
- 0.0, y,
689
- label(marker_label), @scale)
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
- # Draws a legend with the names of the datasets matched to the colors used
720
- # to draw them.
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
- metrics = @d.get_type_metrics(@base_image, @legend_labels.join(''))
733
- legend_text_width = metrics.width
734
- legend_width = legend_text_width +
735
- (@legend_labels.length * legend_square_width * 2.7)
736
- legend_left = (@raw_columns - legend_width) / 2
737
- legend_increment = legend_width / @legend_labels.length.to_f
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 = legend_left
740
- current_y_offset = @hide_title ?
741
- @top_margin + LEGEND_MARGIN :
742
- @top_margin +
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
- debug { @d.line 0.0, current_y_offset, @raw_columns, current_y_offset }
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
- @raw_columns, 1.0,
759
- current_x_offset + (legend_square_width * 1.7), current_y_offset,
760
- legend_label.to_s, @scale)
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
- current_y_offset - legend_square_width / 2.0,
767
- current_x_offset + legend_square_width,
768
- current_y_offset + legend_square_width / 2.0)
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
- current_x_offset += current_string_offset
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
- @raw_columns, 1.0,
790
- 0, @top_margin,
791
- @title, @scale)
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
- 1.0, 1.0,
811
- x_offset, y_offset,
812
- @labels[index], @scale)
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
- @d.fill = @font_color
821
- @d.font = @font if @font
822
- @d.stroke('transparent')
823
- @d.font_weight = NormalWeight
824
- @d.pointsize = scale_fontsize(80)
825
- @d.gravity = CenterGravity
826
- @d = @d.annotate_scaled( @base_image,
827
- @raw_columns, @raw_rows/2.0,
828
- 0, 10,
829
- @no_data_message, @scale)
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
- GradientFill.new(0, 0, 100, 0, top_color, bottom_color))
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
- def less_than_min?(data_point, index=0) # :nodoc:
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
- def min(data_point, index) # :nodoc:
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[1]) <=> sums(a[1]) }
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[1].each_with_index do |value, index|
1016
+ value_set[DATA_VALUES_INDEX].each_with_index do |value, index|
977
1017
  stacked_values[index] += value
978
1018
  end
979
- value_set[1] = stacked_values.dup
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
- scaled_width, scaled_height,
1066
- x * scale, y * scale,
1067
- text)
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
-