scruffy 0.2.6 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/{History.txt → CHANGES.txt} +15 -12
  2. data/README.txt +25 -25
  3. data/lib/scruffy.rb +0 -5
  4. data/lib/scruffy/components.rb +1 -0
  5. data/lib/scruffy/components/axes.rb +23 -0
  6. data/lib/scruffy/components/background.rb +3 -3
  7. data/lib/scruffy/components/base.rb +3 -0
  8. data/lib/scruffy/components/data_markers.rb +23 -8
  9. data/lib/scruffy/components/graphs.rb +4 -0
  10. data/lib/scruffy/components/grid.rb +45 -4
  11. data/lib/scruffy/components/legend.rb +63 -21
  12. data/lib/scruffy/components/title.rb +1 -1
  13. data/lib/scruffy/components/value_markers.rb +9 -16
  14. data/lib/scruffy/formatters.rb +41 -3
  15. data/lib/scruffy/graph.rb +27 -11
  16. data/lib/scruffy/graph_state.rb +5 -0
  17. data/lib/scruffy/helpers.rb +1 -0
  18. data/lib/scruffy/helpers/layer_container.rb +28 -4
  19. data/lib/scruffy/helpers/marker_helper.rb +25 -0
  20. data/lib/scruffy/helpers/point_container.rb +46 -17
  21. data/lib/scruffy/layers.rb +6 -1
  22. data/lib/scruffy/layers/bar.rb +35 -14
  23. data/lib/scruffy/layers/base.rb +51 -21
  24. data/lib/scruffy/layers/box.rb +114 -0
  25. data/lib/scruffy/layers/line.rb +31 -14
  26. data/lib/scruffy/layers/multi.rb +74 -0
  27. data/lib/scruffy/layers/multi_area.rb +119 -0
  28. data/lib/scruffy/layers/multi_bar.rb +51 -0
  29. data/lib/scruffy/layers/scatter.rb +13 -5
  30. data/lib/scruffy/layers/stacked.rb +2 -1
  31. data/lib/scruffy/rasterizers.rb +1 -0
  32. data/lib/scruffy/rasterizers/mini_magick_rasterizer.rb +24 -0
  33. data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +8 -2
  34. data/lib/scruffy/renderers.rb +2 -0
  35. data/lib/scruffy/renderers/axis_legend.rb +41 -0
  36. data/lib/scruffy/renderers/base.rb +6 -4
  37. data/lib/scruffy/renderers/basic.rb +20 -0
  38. data/lib/scruffy/renderers/standard.rb +7 -6
  39. data/lib/scruffy/themes.rb +37 -1
  40. data/lib/scruffy/version.rb +1 -7
  41. data/spec/output/array.svg +55 -0
  42. data/spec/output/hash.svg +55 -0
  43. data/spec/scruffy/graph_spec.rb +4 -4
  44. data/spec/scruffy/layers/base_spec.rb +15 -10
  45. metadata +84 -96
  46. data/CHANGES +0 -104
  47. data/License.txt +0 -20
  48. data/MIT-LICENSE +0 -20
  49. data/Manifest.txt +0 -104
  50. data/PostInstall.txt +0 -6
  51. data/README +0 -9
  52. data/Rakefile +0 -108
  53. data/config/hoe.rb +0 -78
  54. data/config/requirements.rb +0 -15
  55. data/script/console +0 -10
  56. data/script/destroy +0 -14
  57. data/script/generate +0 -14
  58. data/script/txt2html +0 -82
  59. data/setup.rb +0 -1585
  60. data/spec/scruffy/layers/line_spec.rb +0 -10
  61. data/tasks/deployment.rake +0 -34
  62. data/tasks/environment.rake +0 -7
  63. data/tasks/website.rake +0 -17
  64. data/test/graph_creation_test.rb +0 -101
  65. data/test/test_helper.rb +0 -2
  66. data/website/images/blank.gif.html +0 -7
  67. data/website/images/graphs/all_smiles.png +0 -0
  68. data/website/images/graphs/bar_test.png +0 -0
  69. data/website/images/graphs/bar_test.svg +0 -71
  70. data/website/images/graphs/line_test.png +0 -0
  71. data/website/images/graphs/line_test.svg +0 -60
  72. data/website/images/graphs/multi_test.png +0 -0
  73. data/website/images/graphs/multi_test.svg +0 -296
  74. data/website/images/graphs/pie_test.png +0 -0
  75. data/website/images/graphs/pie_test.svg +0 -40
  76. data/website/images/graphs/split_test.png +0 -0
  77. data/website/images/graphs/split_test.svg +0 -295
  78. data/website/images/graphs/stacking_test.png +0 -0
  79. data/website/images/graphs/stacking_test.svg +0 -146
  80. data/website/images/header.png +0 -0
  81. data/website/images/header_gradient.png +0 -0
  82. data/website/images/overlay.png +0 -0
  83. data/website/images/scruffy.png +0 -0
  84. data/website/index.html +0 -225
  85. data/website/index.txt +0 -204
  86. data/website/javascripts/application.js +0 -2
  87. data/website/javascripts/controls.js +0 -815
  88. data/website/javascripts/dragdrop.js +0 -913
  89. data/website/javascripts/effects.js +0 -958
  90. data/website/javascripts/lightbox.js +0 -437
  91. data/website/javascripts/prototype.js +0 -2006
  92. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  93. data/website/stylesheets/lightbox.css +0 -27
  94. data/website/stylesheets/screen.css +0 -147
  95. data/website/stylesheets/scruffy.css +0 -227
  96. data/website/template.html.erb +0 -47
@@ -7,7 +7,7 @@ module Scruffy
7
7
  :class => 'title',
8
8
  :x => (bounds[:width] / 2),
9
9
  :y => bounds[:height],
10
- 'font-size' => relative(100),
10
+ 'font-size' => options[:theme].title_font_size || relative(100),
11
11
  'font-family' => options[:theme].font_family,
12
12
  :fill => options[:theme].marker,
13
13
  :stroke => 'none', 'stroke-width' => '0',
@@ -1,31 +1,24 @@
1
1
  module Scruffy
2
2
  module Components
3
3
  class ValueMarkers < Base
4
- attr_accessor :markers
5
4
 
5
+ include Scruffy::Helpers::Marker
6
+
7
+ attr_accessor :markers
8
+
6
9
  def draw(svg, bounds, options={})
7
10
  markers = (options[:markers] || self.markers) || 5
8
- all_values = []
9
-
10
- (0...markers).each do |idx|
11
- marker = ((1 / (markers - 1).to_f) * idx) * bounds[:height]
12
- all_values << (options[:max_value] - options[:min_value]) * ((1 / (markers - 1).to_f) * idx) + options[:min_value]
13
- end
14
11
 
15
- (0...markers).each do |idx|
16
- marker = ((1 / (markers - 1).to_f) * idx) * bounds[:height]
17
- marker_value = (options[:max_value] - options[:min_value]) * ((1 / (markers - 1).to_f) * idx) + options[:min_value]
18
- marker_value = options[:value_formatter].route_format(marker_value, idx, options.merge({:all_values => all_values})) if options[:value_formatter]
12
+ each_marker(markers, options[:min_value], options[:max_value], bounds[:height], options, :value_formatter) do |label, y|
19
13
 
20
- svg.text( marker_value.to_s,
14
+ svg.text( label,
21
15
  :x => bounds[:width],
22
- :y => (bounds[:height] - marker),
23
- 'font-size' => relative(8),
16
+ :y => (bounds[:height] - y),
17
+ 'font-size' => options[:theme].marker_font_size || relative(8),
24
18
  'font-family' => options[:theme].font_family,
25
- :fill => ((options.delete(:marker_color_override) || options[:theme].marker) || 'white').to_s,
19
+ :fill => ((options[:marker_color_override] || options[:theme].marker) || 'white').to_s,
26
20
  'text-anchor' => 'end')
27
21
  end
28
-
29
22
  end
30
23
  end
31
24
  end
@@ -81,9 +81,11 @@ module Scruffy::Formatters
81
81
  #
82
82
  # separator:: decimal separator. Defaults to '.'
83
83
  # delimiter:: delimiter character. Defaults to ','
84
- # precision_limit:: upper limit for auto precision.
84
+ # precision_limit:: upper limit for auto precision. (Ignored if roundup is specified)
85
+ # roundup:: round up the number to the given interval
85
86
  def initialize(options = {})
86
87
  @precision = options[:precision] || :none
88
+ @roundup = options[:roundup] || :none
87
89
  @separator = options[:separator] || '.'
88
90
  @delimiter = options[:delimiter] || ','
89
91
  @precision_limit = options[:precision_limit] || 4
@@ -107,16 +109,32 @@ module Scruffy::Formatters
107
109
  my_separator = @separator
108
110
  my_separator = "" unless my_precision > 0
109
111
  begin
110
- parts = number_with_precision(target, my_precision).split('.')
112
+ number = ""
113
+
114
+ if @roundup == :none
115
+ parts = number_with_precision(target, my_precision).split('.')
116
+ number = parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + my_separator + parts[1].to_s
117
+ else
118
+ number = roundup(target.to_f, @roundup).to_i.to_s
119
+ end
111
120
 
112
- number = parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + my_separator + parts[1].to_s
113
121
  number
114
122
  rescue StandardError => e
115
123
  target
116
124
  end
117
125
  end
126
+
127
+
128
+ def roundup(target, nearest=100)
129
+ target % nearest == 0 ? target : target + nearest - (target % nearest)
130
+ end
131
+ def rounddown(target, nearest=100)
132
+ target % nearest == 0 ? target : target - (target % nearest)
133
+ end
118
134
  end
119
135
 
136
+
137
+
120
138
  # Currency formatter.
121
139
  #
122
140
  # Provides formatting for currencies.
@@ -150,9 +168,12 @@ module Scruffy::Formatters
150
168
  number = "(" + @unit + parts[0].to_i.abs.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s + ")"
151
169
  else
152
170
  number = @unit + parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s
171
+ number.gsub!(@unit + '-', '-' + @unit)
153
172
  end
154
173
  if (target.to_f < 0) && @negative_color
155
174
  options[:marker_color_override] = @negative_color
175
+ else
176
+ options[:marker_color_override] = nil
156
177
  end
157
178
  number
158
179
  rescue
@@ -191,5 +212,22 @@ module Scruffy::Formatters
191
212
  end
192
213
  end
193
214
  end
215
+
216
+
217
+ class Date < Base
218
+
219
+ def initialize(format_string, options = {})
220
+ @format_string = format_string
221
+ end
222
+
223
+ # Formats percentages.
224
+ def format(target, idx, options)
225
+ begin
226
+ target.strftime(@format_string)
227
+ rescue
228
+ target
229
+ end
230
+ end
231
+ end
194
232
 
195
233
  end
@@ -74,16 +74,18 @@ module Scruffy
74
74
  # doesn't necessarily mean they will make any logical sense together. We leave those decisions up to you. :)
75
75
 
76
76
  class Graph
77
- extend Forwardable;
77
+ extend Forwardable
78
78
 
79
79
  include Scruffy::Helpers::LayerContainer
80
80
 
81
81
  # Delegating these getters to the internal state object.
82
- def_delegators :internal_state, :title, :theme, :default_type,
83
- :point_markers, :value_formatter, :rasterizer
82
+ def_delegators :internal_state, :title,:x_legend,:y_legend, :theme, :default_type,
83
+ :point_markers,:point_markers_rotation,:point_markers_ticks, :value_formatter, :rasterizer,
84
+ :key_formatter
84
85
 
85
- def_delegators :internal_state, :title=, :theme=, :default_type=,
86
- :point_markers=, :value_formatter=, :rasterizer=
86
+ def_delegators :internal_state, :title=, :theme=,:x_legend=,:y_legend=, :default_type=,
87
+ :point_markers=,:point_markers_rotation=,:point_markers_ticks=, :value_formatter=, :rasterizer=,
88
+ :key_formatter=
87
89
 
88
90
  attr_reader :renderer # Writer defined below
89
91
 
@@ -96,11 +98,15 @@ module Scruffy
96
98
  # Options:
97
99
  #
98
100
  # title:: Graph's title
101
+ # x_legend :: Title for X Axis
102
+ # y_legend :: Title for Y Axis
99
103
  # theme:: A theme object to use when rendering graph
100
104
  # layers:: An array of Layers for this graph to use
101
105
  # default_type:: A symbol indicating the default type of Layer for this graph
102
106
  # value_formatter:: Sets a formatter used to modify marker values prior to rendering
103
107
  # point_markers:: Sets the x-axis marker values
108
+ # point_markers_rotation:: Sets the angle of rotation for x-axis marker values
109
+ # point_markers_ticks:: Sets a small tick mark above each marker value. Helful when used with rotation.
104
110
  # rasterizer:: Sets the rasterizer to use when rendering to an image format. Defaults to RMagick.
105
111
  def initialize(*args)
106
112
  self.default_type = args.shift if args.first.is_a?(Symbol)
@@ -108,12 +114,15 @@ module Scruffy
108
114
  raise ArgumentError, "The arguments provided are not supported." if args.size > 0
109
115
 
110
116
  options ||= {}
111
- self.theme = Scruffy::Themes::Keynote.new
117
+
118
+
119
+ self.theme = Scruffy::Themes::Standard.new
112
120
  self.renderer = Scruffy::Renderers::Standard.new
113
- self.rasterizer = Scruffy::Rasterizers::RMagickRasterizer.new
121
+ self.rasterizer = Scruffy::Rasterizers::MiniMagickRasterizer.new
114
122
  self.value_formatter = Scruffy::Formatters::Number.new
123
+ self.key_formatter = Scruffy::Formatters::Number.new
115
124
 
116
- %w(title theme layers default_type value_formatter point_markers rasterizer).each do |arg|
125
+ %w(title x_legend y_legend theme layers default_type value_formatter point_markers point_markers_rotation point_markers_ticks rasterizer key_formatter).each do |arg|
117
126
  self.send("#{arg}=".to_sym, options.delete(arg.to_sym)) unless options[arg.to_sym].nil?
118
127
  end
119
128
 
@@ -128,6 +137,7 @@ module Scruffy
128
137
  # theme:: Theme used to render graph for this render only.
129
138
  # min_value:: Overrides the calculated minimum value used for the graph.
130
139
  # max_value:: Overrides the calculated maximum value used for the graph.
140
+ # renderer:: Provide a Renderer object to use instead of the default.
131
141
  #
132
142
  # For other image formats:
133
143
  # as:: File format to render to ('PNG', 'JPG', etc)
@@ -135,14 +145,20 @@ module Scruffy
135
145
  def render(options = {})
136
146
  options[:theme] ||= theme
137
147
  options[:value_formatter] ||= value_formatter
148
+ options[:key_formatter] ||= key_formatter
138
149
  options[:point_markers] ||= point_markers
150
+ options[:point_markers_rotation] ||= point_markers_rotation
151
+ options[:point_markers_ticks] ||= point_markers_ticks
139
152
  options[:size] ||= (options[:width] ? [options[:width], (options.delete(:width) * 0.6).to_i] : [600, 360])
140
153
  options[:title] ||= title
154
+ options[:x_legend] ||= x_legend
155
+ options[:y_legend] ||= y_legend
141
156
  options[:layers] ||= layers
142
- options[:min_value] ||= bottom_value(:padded)
143
- options[:max_value] ||= top_value
157
+ options[:min_value] ||= bottom_value(options[:padding] ? options[:padding] : nil)
158
+ options[:max_value] ||= top_value(options[:padding] ? options[:padding] : nil)
159
+ options[:min_key] ||= bottom_key
160
+ options[:max_key] ||= top_key
144
161
  options[:graph] ||= self
145
-
146
162
 
147
163
  # Removed for now.
148
164
  # Added for making smaller fonts more legible, but may not be needed after all.
@@ -11,10 +11,15 @@ module Scruffy
11
11
  class GraphState
12
12
 
13
13
  attr_accessor :title
14
+ attr_accessor :x_legend
15
+ attr_accessor :y_legend
14
16
  attr_accessor :theme
15
17
  attr_accessor :default_type
16
18
  attr_accessor :point_markers
19
+ attr_accessor :point_markers_rotation
20
+ attr_accessor :point_markers_ticks
17
21
  attr_accessor :value_formatter
22
+ attr_accessor :key_formatter
18
23
  attr_accessor :rasterizer
19
24
 
20
25
  def initialize
@@ -9,4 +9,5 @@ module Scruffy::Helpers; end
9
9
  require 'scruffy/helpers/canvas'
10
10
  require 'scruffy/helpers/layer_container'
11
11
  require 'scruffy/helpers/point_container'
12
+ require 'scruffy/helpers/marker_helper'
12
13
  #require 'scruffy/helpers/meta'
@@ -67,7 +67,9 @@ module Scruffy::Helpers
67
67
  # If padding is set to :padded, a 15% padding is added to the highest value.
68
68
  def top_value(padding=nil) # :nodoc:
69
69
  topval = layers.inject(0) { |max, layer| (max = ((max < layer.top_value) ? layer.top_value : max)) unless layer.top_value.nil?; max }
70
- padding == :padded ? (topval - ((topval - bottom_value) * 0.15)) : topval
70
+ below_zero = (topval <= 0)
71
+ topval = padding == :padded ? (topval + ((topval - bottom_value) * 0.15)) : topval
72
+ (below_zero && topval > 0) ? 0 : topval
71
73
  end
72
74
 
73
75
  # Returns the lowest value in any of this container's layers.
@@ -76,15 +78,37 @@ module Scruffy::Helpers
76
78
  # If the lowest value is greater than zero, then the padding will not cross the zero line, preventing
77
79
  # negative values from being introduced into the graph purely due to padding.
78
80
  def bottom_value(padding=nil) # :nodoc:
79
- botval = layers.inject(top_value) { |min, layer| (min = ((min > layer.bottom_value) ? layer.bottom_value : min)) unless layer.bottom_value.nil?; min }
80
- above_zero = (botval > 0)
81
- botval = (botval - ((top_value - botval) * 0.15))
81
+ botval = layers.inject(0) do |min, layer|
82
+ (min = ((min > layer.bottom_value) ? layer.bottom_value : min)) unless layer.bottom_value.nil?
83
+ min
84
+ end
85
+ above_zero = (botval >= 0)
86
+ botval = (botval - ((top_value - botval) * 0.15)) if padding == :padded
82
87
 
83
88
  # Don't introduce negative values solely due to padding.
84
89
  # A user-provided value must be negative before padding will extend into negative values.
85
90
  (above_zero && botval < 0) ? 0 : botval
86
91
  end
87
92
 
93
+ def bottom_key(padding=nil)
94
+ return 0 unless layers.any?
95
+ min = layers[0].bottom_key
96
+ layers.each do |layer|
97
+ min = layer.bottom_key if min.nil? && !layer.bottom_key.nil?
98
+ (min = ((min > layer.bottom_key) ? layer.bottom_key : min)) unless layer.bottom_key.nil?
99
+ end
100
+ min
101
+ end
102
+
103
+ def top_key(padding=nil)
104
+ return 1 unless layers.any?
105
+ max = layers[0].top_key
106
+ layers.each do |layer|
107
+ max = layer.top_key if max.nil? && !layer.top_key.nil?
108
+ (max = ((max < layer.top_key) ? layer.top_key : max)) unless layer.top_key.nil?
109
+ end
110
+ max
111
+ end
88
112
 
89
113
  protected
90
114
  def to_camelcase(type) # :nodoc:
@@ -0,0 +1,25 @@
1
+ module Scruffy::Helpers
2
+
3
+ module Marker
4
+
5
+ def each_marker(markers, min, max, width, options, format_key)
6
+ all_values = []
7
+
8
+ (0...markers).each do |idx|
9
+ percent = idx.to_f / (markers-1)
10
+ all_values << min + (max - min) * percent
11
+ end
12
+
13
+ all_values.size.times do |idx|
14
+ dx = width/(markers - 1)
15
+
16
+ location = idx.to_f * dx #+ dx/2
17
+ marker_value = all_values[idx]
18
+ marker_value = options[format_key].route_format(marker_value, idx, options.merge({:all_values => all_values})) if options[format_key]
19
+
20
+ yield marker_value, location
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -8,27 +8,27 @@ module Scruffy::Helpers
8
8
  # Allows all standard point operations to be called on both Array and Hash
9
9
  module PointContainer
10
10
  def self.extended point_set
11
- point_set.extend(const_get(point_set.class.to_s))
11
+ point_set.extend(const_get("#{point_set.class.to_s}_ext"))
12
12
  end
13
13
 
14
- def sortable_values
15
- values.find_all { |v| v.respond_to? :<=> }
14
+ def sortable(values)
15
+ values.find_all { |v| v.respond_to?(:<=>) && !v.nil? }
16
16
  end
17
17
 
18
- def summable_values
19
- values.find_all { |v| v.respond_to? :+ }
18
+ def summable(values)
19
+ values.find_all { |v| v.respond_to?(:+) && !v.nil? }
20
20
  end
21
21
 
22
22
  def maximum_value
23
- sortable_values.sort.last
23
+ sortable(values).sort.last
24
24
  end
25
25
 
26
26
  def minimum_value
27
- sortable_values.sort.first
27
+ sortable(values).sort.first
28
28
  end
29
29
 
30
30
  def sum
31
- summable_values.inject(0) { |sum, i| sum += i }
31
+ summable(values).inject(0) { |sum, i| sum += i }
32
32
  end
33
33
 
34
34
  def inject_with_index memo
@@ -40,24 +40,53 @@ module Scruffy::Helpers
40
40
  end
41
41
  end
42
42
 
43
- module Array
43
+ def minimum_key
44
+ sortable(keys).sort.first
45
+ end
46
+
47
+ def maximum_key
48
+ sortable(keys).sort.last
49
+ end
50
+
51
+ module Array_ext
44
52
  def values
45
- self
53
+ return self unless is_coordinate_list?
54
+ collect { |x,y| y}
55
+ end
56
+
57
+ def keys
58
+ return [0,size-1] unless is_coordinate_list?
59
+ collect { |x,y| x}
60
+ end
61
+
62
+ def is_coordinate_list?
63
+ if any? && first.is_a?(Array) && first.size == 2
64
+ return true
65
+ end
66
+ return false
67
+ end
68
+
69
+ def each_point(&block)
70
+ if is_coordinate_list?
71
+ each{|x,y|block.call(x,y)}
72
+ else
73
+ size.times{|k|block.call(k,self[k])}
74
+ end
46
75
  end
47
76
  end
48
77
 
49
- module Hash
50
- def minimum_key
51
- self.keys.sort.first
78
+ module Hash_ext
79
+ def is_coordinate_list?
80
+ true
52
81
  end
53
82
 
54
- def maximum_key
55
- self.keys.sort.last
83
+ def each_point(&block)
84
+ keys.sort.each{|k|block.call(k,self[k])}
56
85
  end
57
86
 
58
87
  def inject memo
59
- (minimum_key..maximum_key).each do |i|
60
- memo = yield memo, self[i]
88
+ keys.sort.each do |k|
89
+ memo = yield memo, self[k]
61
90
  end
62
91
  memo
63
92
  end
@@ -15,10 +15,15 @@ end
15
15
 
16
16
  require 'scruffy/layers/base'
17
17
  require 'scruffy/layers/area'
18
+ require 'scruffy/layers/multi_area'
18
19
  require 'scruffy/layers/all_smiles'
19
20
  require 'scruffy/layers/bar'
21
+ require 'scruffy/layers/box'
20
22
  require 'scruffy/layers/line'
21
23
  require 'scruffy/layers/average'
22
24
  require 'scruffy/layers/stacked'
25
+ require 'scruffy/layers/multi'
26
+ require 'scruffy/layers/multi_bar'
23
27
  require 'scruffy/layers/pie'
24
- require 'scruffy/layers/pie_slice'
28
+ require 'scruffy/layers/pie_slice'
29
+ require 'scruffy/layers/scatter'
@@ -8,20 +8,36 @@ module Scruffy::Layers
8
8
  class Bar < Base
9
9
 
10
10
  # Draw bar graph.
11
+ # Now handles positive and negative values gracefully.
11
12
  def draw(svg, coords, options = {})
12
- coords.each do |coord|
13
- x, y, bar_height = (coord.first-(@bar_width * 0.5)), coord.last, (height - coord.last)
14
-
15
- svg.g(:transform => "translate(-#{relative(0.5)}, -#{relative(0.5)})") {
16
- svg.rect( :x => x, :y => y, :width => @bar_width + relative(1), :height => bar_height + relative(1),
17
- :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
18
- svg.rect( :x => x+relative(0.5), :y => y+relative(2), :width => @bar_width + relative(1), :height => bar_height - relative(0.5),
19
- :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
20
-
21
- }
13
+ coords.each_with_index do |coord,idx|
14
+ next if coord.nil?
15
+ x, y, bar_height = (coord.first), coord.last, 1#(height - coord.last)
16
+
17
+ valh = max_value + min_value * -1 #value_height
18
+ maxh = max_value * height / valh #positive area height
19
+ minh = min_value * height / valh #negative area height
20
+ #puts "height = #{height} and max_value = #{max_value} and min_value = #{min_value} and y = #{y} and point = #{points[idx]}"
21
+ if points[idx] > 0
22
+ bar_height = points[idx]*maxh/max_value
23
+ else
24
+ bar_height = points[idx]*minh/min_value
25
+ end
26
+
27
+ #puts " y = #{y} and point = #{points[idx]}"
28
+ unless options[:border] == false
29
+ svg.g(:transform => "translate(-#{relative(0.5)}, -#{relative(0.5)})") {
30
+ svg.rect( :x => x, :y => y, :width => @bar_width + relative(1), :height => bar_height + relative(1),
31
+ :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
32
+ svg.rect( :x => x+relative(0.5), :y => y+relative(2), :width => @bar_width + relative(1), :height => bar_height - relative(0.5),
33
+ :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
34
+ }
35
+ end
36
+
37
+ current_colour = color.is_a?(Array) ? color[idx % color.size] : color
22
38
 
23
39
  svg.rect( :x => x, :y => y, :width => @bar_width, :height => bar_height,
24
- :fill => color.to_s, 'style' => "opacity: #{opacity}; stroke: none;" )
40
+ :fill => current_colour.to_s, 'style' => "opacity: #{opacity}; stroke: none;" )
25
41
  end
26
42
  end
27
43
 
@@ -34,13 +50,18 @@ module Scruffy::Layers
34
50
  # Unfortunately this just mean that bar-graphs and most other graphs
35
51
  # end up on different points. Maybe adding a padding to the coordinates
36
52
  # should be a graph-wide thing?
53
+ #
54
+ # Update : x-axis coords for lines and area charts should now line
55
+ # up with the center of bar charts.
56
+
37
57
  def generate_coordinates(options = {})
38
- @bar_width = (width / points.size) * 0.9
58
+ @bar_width = (width / points.size) * 0.95
39
59
  options[:point_distance] = (width - (width / points.size)) / (points.size - 1).to_f
40
60
 
41
61
  #TODO more array work with index, try to rework to be accepting of hashes
42
- coords = (0...points.size).map do |idx|
43
- x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5)
62
+ coords = (0...points.size).map do |idx|
63
+ next if points[idx].nil?
64
+ x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5) - (@bar_width * 0.5)
44
65
 
45
66
  relative_percent = ((points[idx] == min_value) ? 0 : ((points[idx] - min_value) / (max_value - min_value).to_f))
46
67
  y_coord = (height - (height * relative_percent))