gruff 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98ee5b42ff833633329e8c3d6eb0bda9c9f390ef1b007a497bba41406a2252f6
4
- data.tar.gz: dd10520cbc862790a6c99610d497df0f470323328cc67bd35b60067d76cbb001
3
+ metadata.gz: cde92091d39ed0a45d754a184ce6d938b559334934ded0f94b040586b8736caf
4
+ data.tar.gz: 97c10dc9f3f6aa60ec5512935b527051d111f2121368bafd1d0a7b0c6ff529cc
5
5
  SHA512:
6
- metadata.gz: 17dd968e6fb2c606ae611827753d27acc15c34f6aba27c06e8b336891e152c0fa6a384ebd65632b3416b88dda3170d7f32688c47958111027efe2b08519e4c6c
7
- data.tar.gz: ca648c54fb85acb7e144ce23ba3fad5e678543ddd67a133c9bcd3adccbd889c47f3e6213fef2a7abed51cbf93efc688557aadf8b3dfba9db17c5e462e8f0ccfb
6
+ metadata.gz: 3ac67b830bb677be39811647f2fe91fdd3d9ca4db1f38b08d812d4c3cf5f2fd139af2f43436fd81fa00c49e78f526a4ab485cb484d803c71e58d3d8cca6ee7df
7
+ data.tar.gz: 1898e2bfc719cea2e14c463a18ec806782dcfbb8ddc25e3eb317d41d6be11cc65858120d2cee1faa4292d4efb05725c6ccb7fb8c1bd017817395060bae6539d5
@@ -18,9 +18,6 @@ Layout/AccessModifierIndentation:
18
18
  Layout/ClassStructure:
19
19
  Enabled: false
20
20
 
21
- Layout/CommentIndentation:
22
- Enabled: false
23
-
24
21
  Layout/FirstMethodArgumentLineBreak:
25
22
  Enabled: false
26
23
 
@@ -39,6 +36,9 @@ Lint/AssignmentInCondition:
39
36
  Lint/NumberConversion:
40
37
  Enabled: false
41
38
 
39
+ Style/ClassAndModuleChildren:
40
+ Enabled: false
41
+
42
42
  Style/ConditionalAssignment:
43
43
  Enabled: false
44
44
 
@@ -41,7 +41,7 @@ Metrics/BlockLength:
41
41
  # Offense count: 12
42
42
  # Configuration parameters: CountComments.
43
43
  Metrics/ClassLength:
44
- Max: 634
44
+ Max: 637
45
45
 
46
46
  # Offense count: 12
47
47
  # Configuration parameters: IgnoredMethods.
@@ -85,24 +85,6 @@ Security/Eval:
85
85
  Exclude:
86
86
  - 'test/gruff_test_case.rb'
87
87
 
88
- # Offense count: 1
89
- # Cop supports --auto-correct.
90
- # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
91
- # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
92
- # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
93
- # FunctionalMethods: let, let!, subject, watch
94
- # IgnoredMethods: lambda, proc, it
95
- Style/BlockDelimiters:
96
- Exclude:
97
- - 'test/test_accumulator_bar.rb'
98
-
99
- # Offense count: 33
100
- # Cop supports --auto-correct.
101
- # Configuration parameters: AutoCorrect, EnforcedStyle.
102
- # SupportedStyles: nested, compact
103
- Style/ClassAndModuleChildren:
104
- Enabled: false
105
-
106
88
  # Offense count: 39
107
89
  Style/Documentation:
108
90
  Enabled: false
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.11.0
4
+ - Fix regression in empty data handling (#445)
5
+ - Rendering text in front most (#439)
6
+ - Allow to change settings even after entered the data in Gruff::Histogram (#437)
7
+ - Adjust label position in Gruff::Net (#436)
8
+ - Adjust LABEL_MARGIN value (#435)
9
+ - Add shadow line in marker line into Gruff::{Dot, SideBar, Scatter} (#430)
10
+ - Move no data message to the vertical center (#428)
11
+ - Remove the getter method in attributes for configuration (#424)
12
+ - Fix title margin in Gruff::Bullet if empty title was given (#422)
13
+
3
14
  ## 0.10.0
4
15
 
5
16
  * Add Histogram chart (#419)
data/Rakefile CHANGED
@@ -20,4 +20,28 @@ namespace :test do
20
20
  system "ruby #{file}"
21
21
  end
22
22
  end
23
+
24
+ desc 'Update expected image with output'
25
+ task :"image:update" do
26
+ require 'rmagick'
27
+ require 'fileutils'
28
+
29
+ update_expected_images = lambda do |expect_dir, output_dir|
30
+ Dir.glob("#{output_dir}/*.png") do |output_path|
31
+ file_name = File.basename(output_path)
32
+ expected_path = "#{expect_dir}/#{file_name}"
33
+
34
+ expected_image = Magick::Image.read(expected_path).first
35
+ output_image = Magick::Image.read(output_path).first
36
+ _, error = expected_image.compare_channel(output_image, Magick::PeakAbsoluteErrorMetric)
37
+
38
+ if error != 0.0
39
+ FileUtils.copy(output_path, expected_path)
40
+ end
41
+ end
42
+ end
43
+
44
+ update_expected_images.call('test/expected', 'test/output')
45
+ update_expected_images.call('test/expected_java', 'test/output_java')
46
+ end
23
47
  end
@@ -17,10 +17,10 @@ require 'gruff/base'
17
17
  #
18
18
  class Gruff::Area < Gruff::Base
19
19
  # Specifies the filling opacity in area graph. Default is +0.85+.
20
- attr_accessor :fill_opacity
20
+ attr_writer :fill_opacity
21
21
 
22
22
  # Specifies the stroke width in line around area graph. Default is +2.0+.
23
- attr_accessor :stroke_width
23
+ attr_writer :stroke_width
24
24
 
25
25
  def initialize_ivars
26
26
  super
@@ -20,22 +20,23 @@ require 'gruff/helper/bar_conversion'
20
20
  #
21
21
  class Gruff::Bar < Gruff::Base
22
22
  # Spacing factor applied between bars.
23
- attr_accessor :bar_spacing
23
+ attr_writer :bar_spacing
24
24
 
25
25
  # Spacing factor applied between a group of bars belonging to the same label.
26
- attr_accessor :group_spacing
26
+ attr_writer :group_spacing
27
27
 
28
28
  # Set the number output format for labels using sprintf.
29
29
  # Default is +"%.2f"+.
30
- attr_accessor :label_formatting
30
+ attr_writer :label_formatting
31
31
 
32
32
  # Output the values for the bars on a bar graph.
33
33
  # Default is +false+.
34
- attr_accessor :show_labels_for_bar_values
34
+ attr_writer :show_labels_for_bar_values
35
35
 
36
36
  def initialize_ivars
37
37
  super
38
38
  @spacing_factor = 0.9
39
+ @group_spacing = 10
39
40
  @label_formatting = nil
40
41
  @show_labels_for_bar_values = false
41
42
  end
@@ -72,7 +73,6 @@ protected
72
73
  #
73
74
  # Columns sit side-by-side.
74
75
  @bar_spacing ||= @spacing_factor # space between the bars
75
- @group_spacing ||= 10
76
76
 
77
77
  bar_width = (@graph_width - calculate_spacing) / (column_count * store.length).to_f
78
78
  padding = (bar_width * (1 - @bar_spacing)) / 2
@@ -20,28 +20,28 @@ module Gruff
20
20
  class Base
21
21
  # Space around text elements. Mostly used for vertical spacing.
22
22
  LEGEND_MARGIN = TITLE_MARGIN = 20.0
23
- LABEL_MARGIN = 10.0
23
+ LABEL_MARGIN = 15.0
24
24
  DEFAULT_MARGIN = 20.0
25
25
 
26
26
  DEFAULT_TARGET_WIDTH = 800.0
27
27
 
28
28
  # Blank space above the graph. Default is +20+.
29
- attr_accessor :top_margin
29
+ attr_writer :top_margin
30
30
 
31
31
  # Blank space below the graph. Default is +20+.
32
- attr_accessor :bottom_margin
32
+ attr_writer :bottom_margin
33
33
 
34
34
  # Blank space to the right of the graph. Default is +20+.
35
- attr_accessor :right_margin
35
+ attr_writer :right_margin
36
36
 
37
37
  # Blank space to the left of the graph. Default is +20+.
38
- attr_accessor :left_margin
38
+ attr_writer :left_margin
39
39
 
40
40
  # Blank space below the title. Default is +20+.
41
- attr_accessor :title_margin
41
+ attr_writer :title_margin
42
42
 
43
43
  # Blank space below the legend. Default is +20+.
44
- attr_accessor :legend_margin
44
+ attr_writer :legend_margin
45
45
 
46
46
  # A hash of names for the individual columns, where the key is the array
47
47
  # index for the column this label represents.
@@ -50,118 +50,113 @@ module Gruff
50
50
  #
51
51
  # @example
52
52
  # { 0 => 2005, 3 => 2006, 5 => 2007, 7 => 2008 }
53
- attr_accessor :labels
53
+ attr_writer :labels
54
54
 
55
55
  # Used internally for spacing.
56
56
  #
57
57
  # By default, labels are centered over the point they represent.
58
- attr_accessor :center_labels_over_point
58
+ attr_writer :center_labels_over_point
59
59
 
60
60
  # Used internally for horizontal graph types. Default is +false+.
61
- attr_accessor :has_left_labels
61
+ attr_writer :has_left_labels
62
62
 
63
63
  # Set a label for the bottom of the graph.
64
- attr_accessor :x_axis_label
64
+ attr_writer :x_axis_label
65
65
 
66
66
  # Set a label for the left side of the graph.
67
- attr_accessor :y_axis_label
67
+ attr_writer :y_axis_label
68
68
 
69
69
  # Set increment of the vertical marking lines.
70
- attr_accessor :x_axis_increment
70
+ attr_writer :x_axis_increment
71
71
 
72
72
  # Set increment of the horizontal marking lines.
73
- attr_accessor :y_axis_increment
73
+ attr_writer :y_axis_increment
74
74
 
75
75
  # Height of staggering between labels (Bar graph only).
76
- attr_accessor :label_stagger_height
76
+ attr_writer :label_stagger_height
77
77
 
78
78
  # Truncates labels if longer than max specified.
79
- attr_accessor :label_max_size
79
+ attr_writer :label_max_size
80
80
 
81
- # How truncated labels visually appear if they exceed {#label_max_size}.
81
+ # How truncated labels visually appear if they exceed {#label_max_size=}.
82
82
  #
83
83
  # - +:absolute+ - does not show trailing dots to indicate truncation. This is the default.
84
- # - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size}
84
+ # - +:trailing_dots+ - shows trailing dots to indicate truncation (note that {#label_max_size=}
85
85
  # must be greater than 3).
86
- attr_accessor :label_truncation_style
86
+ attr_writer :label_truncation_style
87
87
 
88
88
  # Get or set the list of colors that will be used to draw the bars or lines.
89
89
  attr_accessor :colors
90
90
 
91
91
  # Set the large title of the graph displayed at the top.
92
- attr_accessor :title
92
+ attr_writer :title
93
93
 
94
- # Font used for titles, labels, etc. Works best if you provide the full
95
- # path to the TTF font file. RMagick must be built with the Freetype
96
- # libraries for this to work properly.
97
- attr_reader :font
98
-
99
- # Same as {#font} but for the title.
100
- attr_accessor :title_font
94
+ # Same as {#font=} but for the title.
95
+ attr_writer :title_font
101
96
 
102
97
  # Specifies whether to draw the title bolded or not. Default is +true+.
103
- attr_accessor :bold_title
98
+ attr_writer :bold_title
104
99
 
105
100
  # Specifies the text color.
106
- attr_accessor :font_color
101
+ attr_writer :font_color
107
102
 
108
103
  # Prevent drawing of line markers. Default is +false+.
109
- attr_accessor :hide_line_markers
104
+ attr_writer :hide_line_markers
110
105
 
111
106
  # Prevent drawing of the legend. Default is +false+.
112
- attr_accessor :hide_legend
107
+ attr_writer :hide_legend
113
108
 
114
109
  # Prevent drawing of the title. Default is +false+.
115
- attr_accessor :hide_title
110
+ attr_writer :hide_title
116
111
 
117
112
  # Prevent drawing of line numbers. Default is +false+.
118
- attr_accessor :hide_line_numbers
113
+ attr_writer :hide_line_numbers
119
114
 
120
115
  # Set a message shown when there is no data. Fits up to 20 characters. Defaults
121
116
  # to +"No Data."+.
122
- attr_accessor :no_data_message
117
+ attr_writer :no_data_message
123
118
 
124
119
  # Set the font size of the large title at the top of the graph. Default is +36+.
125
- attr_accessor :title_font_size
120
+ attr_writer :title_font_size
126
121
 
127
122
  # Optionally set the size of the font. Based on an 800x600px graph.
128
123
  # Default is +20+.
129
124
  #
130
125
  # Will be scaled down if the graph is smaller than 800px wide.
131
- attr_accessor :legend_font_size
126
+ attr_writer :legend_font_size
132
127
 
133
128
  # Display the legend under the graph. Default is +false+.
134
- attr_accessor :legend_at_bottom
129
+ attr_writer :legend_at_bottom
135
130
 
136
131
  # The font size of the labels around the graph. Default is +21+.
137
- attr_accessor :marker_font_size
132
+ attr_writer :marker_font_size
138
133
 
139
134
  # Set the color of the auxiliary lines.
140
- attr_accessor :marker_color
135
+ attr_writer :marker_color
141
136
 
142
137
  # Set the shadow color of the auxiliary lines.
143
- attr_accessor :marker_shadow_color
138
+ attr_writer :marker_shadow_color
144
139
 
145
140
  # Set the number of horizontal lines shown for reference.
146
- attr_accessor :marker_count
141
+ attr_writer :marker_count
147
142
 
148
143
  # Set to +true+ if you want the data sets sorted with largest avg values drawn
149
144
  # first. Default is +false+.
150
- attr_accessor :sort
145
+ attr_writer :sort
151
146
 
152
147
  # Set to +true+ if you want the data sets drawn with largest avg values drawn
153
148
  # first. This does not affect the legend. Default is +false+.
154
- attr_accessor :sorted_drawing
149
+ attr_writer :sorted_drawing
155
150
 
156
151
  # Optionally set the size of the colored box by each item in the legend.
157
152
  # Default is +20.0+.
158
153
  #
159
154
  # Will be scaled down if graph is smaller than 800px wide.
160
- attr_accessor :legend_box_size
155
+ attr_writer :legend_box_size
161
156
 
162
157
  # With Side Bars use the data label for the marker value to the left of the bar.
163
158
  # Default is +false+.
164
- attr_accessor :use_data_label
159
+ attr_writer :use_data_label
165
160
 
166
161
  # If one numerical argument is given, the graph is drawn at 4/3 ratio
167
162
  # according to the given width (+800+ results in 800x600, +400+ gives 400x300,
@@ -173,9 +168,7 @@ module Gruff
173
168
  #
174
169
  def initialize(target_width = DEFAULT_TARGET_WIDTH)
175
170
  if target_width.is_a?(String)
176
- geometric_width, geometric_height = target_width.split('x')
177
- @columns = geometric_width.to_f
178
- @rows = geometric_height.to_f
171
+ @columns, @rows = target_width.split('x').map(&:to_f)
179
172
  else
180
173
  @columns = target_width.to_f
181
174
  @rows = target_width.to_f * 0.75
@@ -183,19 +176,14 @@ module Gruff
183
176
  @columns.freeze
184
177
  @rows.freeze
185
178
 
179
+ initialize_graph_scale
186
180
  initialize_ivars
181
+ initialize_store
187
182
 
188
183
  self.theme = Themes::KEYNOTE
189
184
  end
190
185
 
191
- # Set instance variables for this object.
192
- #
193
- # Subclasses can override this, call super, then set values separately.
194
- #
195
- # This makes it possible to set defaults in a subclass but still allow
196
- # developers to change this values in their program.
197
- def initialize_ivars
198
- # Internal for calculations
186
+ def initialize_graph_scale
199
187
  @raw_columns = DEFAULT_TARGET_WIDTH
200
188
  @raw_rows = DEFAULT_TARGET_WIDTH * (@rows / @columns)
201
189
  @raw_columns.freeze
@@ -203,10 +191,23 @@ module Gruff
203
191
 
204
192
  @scale = @columns / @raw_columns
205
193
  @scale.freeze
194
+ end
195
+ protected :initialize_graph_scale
196
+
197
+ def initialize_store
198
+ @store = Gruff::Store.new(Gruff::Store::BaseData)
199
+ end
200
+ protected :initialize_store
206
201
 
202
+ # Initialize instance variable of attribures
203
+ #
204
+ # Subclasses can override this, call super, then set values separately.
205
+ #
206
+ # This makes it possible to set defaults in a subclass but still allow
207
+ # developers to change this values in their program.
208
+ def initialize_ivars
207
209
  @marker_count = nil
208
210
  @maximum_value = @minimum_value = nil
209
- @increment = nil
210
211
  @labels = {}
211
212
  @sort = false
212
213
  @sorted_drawing = false
@@ -235,14 +236,10 @@ module Gruff
235
236
  @label_max_size = 0
236
237
  @label_truncation_style = :absolute
237
238
 
238
- @theme_options = {}
239
-
240
239
  @use_data_label = false
241
240
  @x_axis_increment = nil
242
241
  @x_axis_label = @y_axis_label = nil
243
242
  @y_axis_increment = nil
244
-
245
- @store = Gruff::Store.new(Gruff::Store::BaseData)
246
243
  end
247
244
  protected :initialize_ivars
248
245
 
@@ -298,11 +295,20 @@ module Gruff
298
295
  # graph.theme = {
299
296
  # colors: %w(orange purple green white red),
300
297
  # marker_color: 'blue',
301
- # background_colors: ['black', 'grey', :top_bottom]
298
+ # background_colors: ['black', 'grey'],
299
+ # background_direction: :top_bottom
302
300
  # }
303
301
  #
304
302
  # +background_image: 'squirrel.png'+ is also possible.
305
303
  #
304
+ # +background_direction+ accepts one of following parameters.
305
+ # - +:top_bottom+
306
+ # - +:bottom_top+
307
+ # - +:left_right+
308
+ # - +:right_left+
309
+ # - +:topleft_bottomright+
310
+ # - +:topright_bottomleft+
311
+ #
306
312
  # (Or hopefully something better looking than that.)
307
313
  #
308
314
  # @param options [Hash] The optional setting for theme
@@ -413,9 +419,11 @@ module Gruff
413
419
  end
414
420
 
415
421
  # Return the graph as a rendered binary blob.
416
- def to_blob(file_format = 'PNG')
422
+ #
423
+ # @param image_format [String] The image format of binary blob.
424
+ def to_blob(image_format = 'PNG')
417
425
  draw
418
- Gruff::Renderer.to_blob(file_format)
426
+ Gruff::Renderer.to_blob(image_format)
419
427
  end
420
428
 
421
429
  protected
@@ -496,57 +504,17 @@ module Gruff
496
504
  # Calculates size of drawable area, general font dimensions, etc.
497
505
 
498
506
  def setup_graph_measurements
499
- @marker_caps_height = @hide_line_markers ? 0 : calculate_caps_height(@marker_font_size)
500
- @title_caps_height = hide_title? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
501
- @legend_caps_height = @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
502
-
503
- if @hide_line_markers
504
- @graph_left = @left_margin
505
- @graph_right_margin = @right_margin
506
- @graph_bottom_margin = @bottom_margin
507
- else
508
- if @has_left_labels
509
- longest_left_label_width = calculate_width(@marker_font_size,
510
- labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
511
- else
512
- longest_left_label_width = calculate_width(@marker_font_size,
513
- label(maximum_value.to_f, @increment))
514
- end
515
-
516
- # Shift graph if left line numbers are hidden
517
- line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
518
-
519
- @graph_left = @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
520
-
521
- # Make space for half the width of the rightmost column label.
522
- # Might be greater than the number of columns if between-style bar markers are used.
523
- last_label = @labels.keys.max.to_i
524
- extra_room_for_long_label = begin
525
- (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
526
- end
527
- @graph_right_margin = @right_margin + extra_room_for_long_label
528
-
529
- @graph_bottom_margin = @bottom_margin + @marker_caps_height + LABEL_MARGIN
530
- end
531
-
532
- @graph_right = @raw_columns - @graph_right_margin
533
- @graph_width = @raw_columns - @graph_left - @graph_right_margin
507
+ @marker_caps_height = setup_marker_caps_height
508
+ @title_caps_height = setup_title_caps_height
509
+ @legend_caps_height = setup_legend_caps_height
534
510
 
535
- # When @hide title, leave a title_margin space for aesthetics.
536
- # Same with @hide_legend
537
- @graph_top = begin
538
- if @legend_at_bottom
539
- @top_margin
540
- else
541
- @top_margin +
542
- (hide_title? ? title_margin : @title_caps_height + title_margin) +
543
- (@hide_legend ? legend_margin : @legend_caps_height + legend_margin)
544
- end
545
- end
511
+ margin_on_right = graph_right_margin
512
+ @graph_right = @raw_columns - margin_on_right
513
+ @graph_left = setup_left_margin
514
+ @graph_top = setup_top_margin
515
+ @graph_bottom = setup_bottom_margin
546
516
 
547
- x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
548
- # FIXME: Consider chart types other than bar
549
- @graph_bottom = @raw_rows - @graph_bottom_margin - x_axis_label_height - @label_stagger_height
517
+ @graph_width = @raw_columns - @graph_left - margin_on_right
550
518
  @graph_height = @graph_bottom - @graph_top
551
519
  end
552
520
 
@@ -556,17 +524,17 @@ module Gruff
556
524
  # X Axis
557
525
  # Centered vertically and horizontally by setting the
558
526
  # height to 1.0 and the width to the width of the graph.
559
- x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN * 2 + @marker_caps_height
527
+ x_axis_label_y_coordinate = @graph_bottom + LABEL_MARGIN + @marker_caps_height
560
528
 
561
529
  # TODO: Center between graph area
562
530
  text_renderer = Gruff::Renderer::Text.new(@x_axis_label, font: @font, size: @marker_font_size, color: @font_color)
563
- text_renderer.render(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
531
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0.0, x_axis_label_y_coordinate)
564
532
  end
565
533
 
566
534
  if @y_axis_label
567
535
  # Y Axis, rotated vertically
568
536
  text_renderer = Gruff::Renderer::Text.new(@y_axis_label, font: @font, size: @marker_font_size, color: @font_color, rotation: -90)
569
- text_renderer.render(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
537
+ text_renderer.add_to_render_queue(1.0, @raw_rows, @left_margin + @marker_caps_height / 2.0, 0.0, Magick::CenterGravity)
570
538
  end
571
539
  end
572
540
 
@@ -580,17 +548,14 @@ module Gruff
580
548
  (0..@marker_count).each do |index|
581
549
  y = @graph_top + @graph_height - index.to_f * increment_scaled
582
550
 
583
- Gruff::Renderer::Line.new(color: @marker_color).render(@graph_left, y, @graph_right, y)
584
- #If the user specified a marker shadow color, draw a shadow just below it
585
- if @marker_shadow_color
586
- Gruff::Renderer::Line.new(color: @marker_shadow_color).render(@graph_left, y + 1, @graph_right, y + 1)
587
- end
551
+ line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
552
+ line_renderer.render(@graph_left, y, @graph_right, y)
588
553
 
589
554
  unless @hide_line_numbers
590
555
  marker_label = BigDecimal(index.to_s) * BigDecimal(@increment.to_s) + BigDecimal(minimum_value.to_s)
591
556
  label = label(marker_label, @increment)
592
557
  text_renderer = Gruff::Renderer::Text.new(label, font: @font, size: @marker_font_size, color: @font_color)
593
- text_renderer.render(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
558
+ text_renderer.add_to_render_queue(@graph_left - LABEL_MARGIN, 1.0, 0.0, y, Magick::EastGravity)
594
559
  end
595
560
  end
596
561
  end
@@ -613,27 +578,15 @@ module Gruff
613
578
  return if @hide_legend
614
579
 
615
580
  legend_labels = store.data.map(&:label)
616
-
617
581
  legend_square_width = @legend_box_size # small square with color of this item
618
-
619
- # May fix legend drawing problem at small sizes
620
- label_widths = [[]] # Used to calculate line wrap
621
- legend_labels.each do |label|
622
- width = calculate_width(@legend_font_size, label)
623
- label_width = width + legend_square_width * 2.7
624
- label_widths.last.push label_width
625
-
626
- if sum(label_widths.last) > (@raw_columns * 0.9)
627
- label_widths.push [label_widths.last.pop]
628
- end
629
- end
582
+ label_widths = calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
630
583
 
631
584
  current_x_offset = center(sum(label_widths.first))
632
585
  current_y_offset = begin
633
586
  if @legend_at_bottom
634
- @graph_height + title_margin
587
+ @graph_height + @title_margin
635
588
  else
636
- hide_title? ? @top_margin + title_margin : @top_margin + title_margin + @title_caps_height
589
+ hide_title? ? @top_margin + @title_margin : @top_margin + @title_margin + @title_caps_height
637
590
  end
638
591
  end
639
592
 
@@ -642,7 +595,7 @@ module Gruff
642
595
 
643
596
  # Draw label
644
597
  text_renderer = Gruff::Renderer::Text.new(legend_label, font: @font, size: @legend_font_size, color: @font_color)
645
- text_renderer.render(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
598
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, current_x_offset + (legend_square_width * 1.7), current_y_offset, Magick::WestGravity)
646
599
 
647
600
  # Now draw box with color of this dataset
648
601
  rect_renderer = Gruff::Renderer::Rectangle.new(color: store.data[index].color)
@@ -651,23 +604,21 @@ module Gruff
651
604
  current_x_offset + legend_square_width,
652
605
  current_y_offset + legend_square_width / 2.0)
653
606
 
654
- width = calculate_width(legend_font_size, legend_label)
655
- current_string_offset = width + (legend_square_width * 2.7)
607
+ width = calculate_width(@legend_font_size, legend_label)
608
+ current_x_offset += width + (legend_square_width * 2.7)
609
+ label_widths.first.shift
656
610
 
657
611
  # Handle wrapping
658
- label_widths.first.shift
659
612
  if label_widths.first.empty?
660
613
  label_widths.shift
661
614
  current_x_offset = center(sum(label_widths.first)) unless label_widths.empty?
662
- line_height = [@legend_caps_height, legend_square_width].max + legend_margin
615
+ line_height = [@legend_caps_height, legend_square_width].max + @legend_margin
663
616
  unless label_widths.empty?
664
617
  # Wrap to next line and shrink available graph dimensions
665
618
  current_y_offset += line_height
666
619
  @graph_top += line_height
667
620
  @graph_height = @graph_bottom - @graph_top
668
621
  end
669
- else
670
- current_x_offset += current_string_offset
671
622
  end
672
623
  end
673
624
  end
@@ -685,7 +636,7 @@ module Gruff
685
636
  font_size = font_size * (@raw_columns / metrics.width) * 0.95
686
637
  end
687
638
  text_renderer = Gruff::Renderer::Text.new(@title, font: font, size: font_size, color: @font_color, weight: font_weight)
688
- text_renderer.render(@raw_columns, 1.0, 0, @top_margin)
639
+ text_renderer.add_to_render_queue(@raw_columns, 1.0, 0, @top_margin)
689
640
  end
690
641
 
691
642
  # Draws column labels below graph, centered over x_offset
@@ -700,11 +651,11 @@ module Gruff
700
651
  # TODO: See if index.odd? is the best stragegy
701
652
  y_offset += @label_stagger_height if index.odd?
702
653
 
703
- label_text = truncate_label_text(labels[index].to_s)
654
+ label_text = truncate_label_text(@labels[index].to_s)
704
655
 
705
656
  if x_offset >= @graph_left && x_offset <= @graph_right
706
657
  text_renderer = Gruff::Renderer::Text.new(label_text, font: @font, size: @marker_font_size, color: @font_color)
707
- text_renderer.render(1.0, 1.0, x_offset, y_offset, gravity)
658
+ text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset, gravity)
708
659
  end
709
660
  end
710
661
  end
@@ -724,13 +675,13 @@ module Gruff
724
675
  return if @hide_line_markers && !bar_value
725
676
 
726
677
  text_renderer = Gruff::Renderer::Text.new(data_point, font: @font, size: @marker_font_size, color: @font_color)
727
- text_renderer.render(1.0, 1.0, x_offset, y_offset)
678
+ text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
728
679
  end
729
680
 
730
681
  # Shows an error message because you have no data.
731
682
  def draw_no_data
732
683
  text_renderer = Gruff::Renderer::Text.new(@no_data_message, font: @font, size: 80, color: @font_color)
733
- text_renderer.render(@raw_columns, @raw_rows / 2.0, 0, 10, Magick::CenterGravity)
684
+ text_renderer.render(@raw_columns, @raw_rows, 0, 0, Magick::CenterGravity)
734
685
  end
735
686
 
736
687
  # Resets everything to defaults (except data).
@@ -794,6 +745,63 @@ module Gruff
794
745
 
795
746
  private
796
747
 
748
+ def setup_marker_caps_height
749
+ @hide_line_markers ? 0 : calculate_caps_height(@marker_font_size)
750
+ end
751
+
752
+ def setup_title_caps_height
753
+ hide_title? ? 0 : calculate_caps_height(@title_font_size) * @title.lines.to_a.size
754
+ end
755
+
756
+ def setup_legend_caps_height
757
+ @hide_legend ? 0 : calculate_caps_height(@legend_font_size)
758
+ end
759
+
760
+ def graph_right_margin
761
+ @hide_line_markers ? @right_margin : @right_margin + extra_room_for_long_label
762
+ end
763
+
764
+ def extra_room_for_long_label
765
+ # Make space for half the width of the rightmost column label.
766
+ # Might be greater than the number of columns if between-style bar markers are used.
767
+ last_label = @labels.keys.max.to_i
768
+ (last_label >= (column_count - 1) && @center_labels_over_point) ? calculate_width(@marker_font_size, @labels[last_label]) / 2.0 : 0
769
+ end
770
+
771
+ def setup_left_margin
772
+ return @left_margin if @hide_line_markers
773
+
774
+ if @has_left_labels
775
+ longest_left_label_width = calculate_width(@marker_font_size,
776
+ @labels.values.reduce('') { |value, memo| (value.to_s.length > memo.to_s.length) ? value : memo }) * 1.25
777
+ else
778
+ longest_left_label_width = calculate_width(@marker_font_size,
779
+ label(maximum_value.to_f, @increment))
780
+ end
781
+ # Shift graph if left line numbers are hidden
782
+ line_number_width = @hide_line_numbers && !@has_left_labels ? 0.0 : (longest_left_label_width + LABEL_MARGIN * 2)
783
+
784
+ @left_margin + line_number_width + (@y_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN * 2)
785
+ end
786
+
787
+ def setup_top_margin
788
+ return @top_margin if @legend_at_bottom
789
+
790
+ # When @hide title, leave a title_margin space for aesthetics.
791
+ # Same with @hide_legend
792
+ @top_margin +
793
+ (hide_title? ? @title_margin : @title_caps_height + @title_margin) +
794
+ (@hide_legend ? @legend_margin : @legend_caps_height + @legend_margin)
795
+ end
796
+
797
+ def setup_bottom_margin
798
+ graph_bottom_margin = @hide_line_markers ? @bottom_margin : @bottom_margin + @marker_caps_height + LABEL_MARGIN
799
+
800
+ x_axis_label_height = @x_axis_label.nil? ? 0.0 : @marker_caps_height + LABEL_MARGIN
801
+ # FIXME: Consider chart types other than bar
802
+ @raw_rows - graph_bottom_margin - x_axis_label_height - @label_stagger_height
803
+ end
804
+
797
805
  def truncate_label_text(text)
798
806
  return text if text.size <= @label_max_size
799
807
 
@@ -838,6 +846,22 @@ module Gruff
838
846
  parts.join('.')
839
847
  end
840
848
 
849
+ def calculate_legend_label_widths_for_each_line(legend_labels, legend_square_width)
850
+ # May fix legend drawing problem at small sizes
851
+ label_widths = [[]] # Used to calculate line wrap
852
+ legend_labels.each do |label|
853
+ width = calculate_width(@legend_font_size, label)
854
+ label_width = width + legend_square_width * 2.7
855
+ label_widths.last.push label_width
856
+
857
+ if sum(label_widths.last) > (@raw_columns * 0.9)
858
+ label_widths.push [label_widths.last.pop]
859
+ end
860
+ end
861
+
862
+ label_widths
863
+ end
864
+
841
865
  # Returns the height of the capital letter 'X' for the current font and
842
866
  # size.
843
867
  #