scruffy 0.2.6 → 0.3.0.beta1

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.
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
@@ -26,6 +26,7 @@ module Scruffy::Layers
26
26
  attr_accessor :points
27
27
  attr_accessor :relevant_data
28
28
  attr_accessor :preferred_color
29
+ attr_accessor :preferred_outline
29
30
  attr_accessor :options # On-the-fly values for easy customization / acts as attributes.
30
31
 
31
32
  # The following attributes are set during the layer's render process,
@@ -34,6 +35,7 @@ module Scruffy::Layers
34
35
  attr_reader :height, :width
35
36
  attr_reader :min_value, :max_value
36
37
  attr_reader :color
38
+ attr_reader :outline
37
39
  attr_reader :opacity
38
40
  attr_reader :complexity
39
41
 
@@ -47,39 +49,53 @@ module Scruffy::Layers
47
49
  # title:: Name/title of data group
48
50
  # points:: Array of data points
49
51
  # preferred_color:: Color used to render this graph, overrides theme color.
52
+ # preferred_outline:: Color used to render this graph outline, overrides theme outline.
50
53
  # relevant_data:: Rarely used - indicates the data on this graph should not
51
54
  # included in any graph data aggregations, such as averaging data points.
55
+ # style:: SVG polyline style. (default: 'fill-opacity: 0; stroke-opacity: 0.35')
56
+ # stroke_width:: numeric value for width of line (0.1 - 10, default: 1)
57
+ # relativestroke:: stroke-width relative to image size? true or false (default)
58
+ # shadow:: Display line shadow? true or false (default)
59
+ # dots:: Display co-ord dots? true or false (default)
52
60
  def initialize(options = {})
53
61
  @title = options.delete(:title) || ''
54
- @preferred_color = options.delete(:preferred_color)
62
+ @preferred_color = options.delete(:color)
63
+ @preferred_outline = options.delete(:outline)
55
64
  @relevant_data = options.delete(:relevant_data) || true
56
65
  @points = options.delete(:points) || []
57
66
  @points.extend Scruffy::Helpers::PointContainer unless @points.kind_of? Scruffy::Helpers::PointContainer
58
-
67
+
68
+ options[:stroke_width] ||= 1
69
+ options[:dots] ||= false
70
+ options[:shadow] ||= false
71
+ options[:style] ||= false
72
+ options[:relativestroke] ||= false
73
+
59
74
  @options = options
75
+
60
76
  end
61
-
77
+
62
78
  # Builds SVG code for this graph using the provided Builder object.
63
79
  # This method actually generates data needed by this graph, then passes the
64
80
  # rendering responsibilities to Base#draw.
65
81
  #
66
82
  # svg:: a Builder object used to create SVG code.
67
- def render(svg, options = {})
83
+ def render(svg, options)
68
84
  setup_variables(options)
69
85
  coords = generate_coordinates(options)
70
-
86
+
71
87
  draw(svg, coords, options)
72
88
  end
73
-
89
+
74
90
  # The method called by Base#draw to render the graph.
75
- #
91
+ #
76
92
  # svg:: a Builder object to use for creating SVG code.
77
93
  # coords:: An array of coordinates relating to the graph's data points. ie: [[100, 120], [200, 140], [300, 40]]
78
94
  # options:: Optional arguments.
79
95
  def draw(svg, coords, options={})
80
96
  raise RenderError, "You must override the Base#draw method."
81
97
  end
82
-
98
+
83
99
  # Returns a hash with information to be used by the legend.
84
100
  #
85
101
  # Alternatively, returns nil if you don't want this layer to be in the legend,
@@ -90,14 +106,14 @@ module Scruffy::Layers
90
106
  # must be rendered AFTER layers.
91
107
  def legend_data
92
108
  if relevant_data? && @color
93
- {:title => title,
109
+ {:title => title,
94
110
  :color => @color,
95
111
  :priority => :normal}
96
112
  else
97
113
  nil
98
114
  end
99
115
  end
100
-
116
+
101
117
  # Returns the value of relevant_data
102
118
  def relevant_data?
103
119
  @relevant_data
@@ -107,12 +123,22 @@ module Scruffy::Layers
107
123
  def top_value
108
124
  @relevant_data ? points.maximum_value : nil
109
125
  end
110
-
126
+
111
127
  # The lowest data point on this layer, or nil if relevant_data == false
112
128
  def bottom_value
113
129
  @relevant_data ? points.minimum_value : nil
114
130
  end
115
131
 
132
+ # The highest data point on this layer, or nil if relevant_data == false
133
+ def bottom_key
134
+ @relevant_data ? points.minimum_key : nil
135
+ end
136
+
137
+ # The lowest data point on this layer, or nil if relevant_data == false
138
+ def top_key
139
+ @relevant_data ? points.maximum_key : nil
140
+ end
141
+
116
142
  # The sum of all values
117
143
  def sum_values
118
144
  points.sum
@@ -123,6 +149,7 @@ module Scruffy::Layers
123
149
  # itself.
124
150
  def setup_variables(options = {})
125
151
  @color = (preferred_color || options.delete(:color))
152
+ @outline = (preferred_outline || options.delete(:outline))
126
153
  @width, @height = options.delete(:size)
127
154
  @min_value, @max_value = options[:min_value], options[:max_value]
128
155
  @opacity = options[:opacity] || 1.0
@@ -132,21 +159,24 @@ module Scruffy::Layers
132
159
  # Optimistic generation of coordinates for layer to use. These coordinates are
133
160
  # just a best guess, and can be overridden or thrown away (for example, this is overridden
134
161
  # in pie charting and bar charts).
162
+
163
+ # Updated : Assuming n number of points, the graph is divided into n rectangles
164
+ # and the points are plotted in the middle of each rectangle. This allows bars to
165
+ # play nice with lines.
135
166
  def generate_coordinates(options = {})
136
- options[:point_distance] = width / (points.size - 1).to_f
167
+ dy = height.to_f / (options[:max_value] - options[:min_value])
168
+ dx = width.to_f / (options[:max_key] - options[:min_key] + 1)
137
169
 
138
- points.inject_with_index([]) do |memo, point, idx|
139
- x_coord = options[:point_distance] * idx
170
+ ret = []
171
+ points.each_point do |x, y|
172
+ if y
173
+ x_coord = dx * (x - options[:min_key]) + dx/2
174
+ y_coord = dy * (y - options[:min_value])
140
175
 
141
- if point
142
- relative_percent = ((point == min_value) ? 0 : ((point - min_value) / (max_value - min_value).to_f))
143
- y_coord = (height - (height * relative_percent))
144
-
145
- memo << [x_coord, y_coord]
176
+ ret << [x_coord, height - y_coord]
146
177
  end
147
-
148
- memo
149
178
  end
179
+ return ret
150
180
  end
151
181
 
152
182
  # Converts a percentage into a pixel value, relative to the height.
@@ -0,0 +1,114 @@
1
+ module Scruffy::Layers
2
+ # ==Scruffy::Layers::Box
3
+ #
4
+ # Author:: Brasten Sager
5
+ # Date:: August 6th, 2006
6
+ #
7
+ # Standard bar graph.
8
+ class Box < Base
9
+
10
+ # Draw box plot.
11
+ def draw(svg, coords, options = {})
12
+ coords.each_with_index do |coord,idx|
13
+ x, y, bar_height = (coord.first), coord.last, 1#(height - coord.last)
14
+
15
+ valh = max_value + min_value * -1 #value_height
16
+ maxh = max_value * height / valh #positive area height
17
+ minh = min_value * height / valh #negative area height
18
+ #puts "height = #{height} and max_value = #{max_value} and min_value = #{min_value} and y = #{y} and point = #{points[idx]}"
19
+
20
+ #if points[idx] > 0
21
+ # bar_height = points[idx]*maxh/max_value
22
+ #else
23
+ # bar_height = points[idx]*minh/min_value
24
+ #end
25
+
26
+ #puts " y = #{y} and point = #{points[idx]}"
27
+ #svg.g(:transform => "translate(-#{relative(0.5)}, -#{relative(0.5)})") {
28
+ # svg.rect( :x => x, :y => y, :width => @bar_width + relative(1), :height => bar_height + relative(1),
29
+ # :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
30
+ # svg.rect( :x => x+relative(0.5), :y => y+relative(2), :width => @bar_width + relative(1), :height => bar_height - relative(0.5),
31
+ # :style => "fill: black; fill-opacity: 0.15; stroke: none;" )
32
+ #
33
+ #}
34
+
35
+ svg.line(:x1=>x+@bar_width/2,:x2=>x+@bar_width/2,:y1=>y[0],:y2=>y[4], :style => "stroke:#{(outline.to_s || options[:theme].marker || 'white').to_s}; stroke-width:1")
36
+ svg.line(:x1=>x+@bar_width/4,:x2=>x+@bar_width/4*3,:y1=>y[0],:y2=>y[0], :style => "stroke:#{(outline.to_s || options[:theme].marker || 'white').to_s}; stroke-width:1")
37
+ svg.line(:x1=>x+@bar_width/4,:x2=>x+@bar_width/4*3,:y1=>y[4],:y2=>y[4], :style => "stroke:#{(outline.to_s || options[:theme].marker || 'white').to_s}; stroke-width:1")
38
+ svg.rect( :x => x, :y => y[1], :width => @bar_width, :height => (y[1]-y[3])*-1,
39
+ :fill => color.to_s, 'style' => "opacity: #{opacity}; stroke:#{(outline.to_s || options[:theme].marker || 'white').to_s}; stroke-width:1;" )
40
+ svg.line(:x1=>x,:x2=>x+@bar_width,:y1=>y[2],:y2=>y[2], :style => "stroke:#{(outline.to_s || options[:theme].marker || 'white').to_s}; stroke-width:1")
41
+ #svg.rect( :x => x, :y => y, :width => @bar_width, :height => bar_height,
42
+ # :fill => color.to_s, 'style' => "opacity: #{opacity}; stroke: none;" )
43
+ end
44
+ end
45
+
46
+
47
+ # Returns the highest value in any of this container's layers.
48
+ #
49
+ # If padding is set to :padded, a 15% padding is added to the highest value.
50
+ def top_value(padding=nil) # :nodoc:
51
+ topval = points[0].max
52
+ points.each do |point_set|
53
+ topval = ( (topval < point_set.max) ? point_set.max : topval )
54
+ end
55
+ #topval = layers.inject(0) { |max, layer| (max = ((max < layer.top_value) ? layer.top_value : max)) unless layer.top_value.nil?; max }
56
+ below_zero = (topval <= 0)
57
+ topval = padding == :padded ? (topval + ((topval - bottom_value(nil)) * 0.15)) : topval
58
+ (below_zero && topval > 0) ? 0 : topval
59
+ end
60
+
61
+ # Returns the lowest value in any of this container's layers.
62
+ #
63
+ # If padding is set to :padded, a 15% padding is added below the lowest value.
64
+ # If the lowest value is greater than zero, then the padding will not cross the zero line, preventing
65
+ # negative values from being introduced into the graph purely due to padding.
66
+ def bottom_value(padding=nil) # :nodoc:
67
+ botval = points[0].min
68
+ points.each do |point_set|
69
+ botval = ( (botval>point_set.min) ? point_set.min : botval )
70
+ end
71
+ #botval = layers.inject(0) do |min, layer|
72
+ # (min = ((min > layer.bottom_value) ? layer.bottom_value : min)) unless layer.bottom_value.nil?
73
+ # min
74
+ #end
75
+ above_zero = (botval >= 0)
76
+ botval = (botval - ((top_value(nil) - botval) * 0.15)) if padding == :padded
77
+
78
+ # Don't introduce negative values solely due to padding.
79
+ # A user-provided value must be negative before padding will extend into negative values.
80
+ (above_zero && botval < 0) ? 0 : botval
81
+ end
82
+
83
+ protected
84
+
85
+ # Due to the size of the bar graph, X-axis coords must
86
+ # be squeezed so that the bars do not hang off the ends
87
+ # of the graph.
88
+ #
89
+ # Unfortunately this just mean that bar-graphs and most other graphs
90
+ # end up on different points. Maybe adding a padding to the coordinates
91
+ # should be a graph-wide thing?
92
+ #
93
+ # Update : x-axis coords for lines and area charts should now line
94
+ # up with the center of bar charts.
95
+
96
+ def generate_coordinates(options = {})
97
+ @bar_width = (width / points.size) * 0.9
98
+ options[:point_distance] = (width - (width / points.size)) / (points.size - 1).to_f
99
+
100
+ #TODO more array work with index, try to rework to be accepting of hashes
101
+ coords = (0...points.size).map do |idx|
102
+ x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5) - (@bar_width * 0.5)
103
+ y_coords = []
104
+ points[idx].each do |point|
105
+ relative_percent = ((point == min_value) ? 0 : ((point - min_value) / (max_value - min_value).to_f))
106
+ y_coord = (height - (height * relative_percent))
107
+ y_coords << y_coord
108
+ end
109
+ [x_coord, y_coords]
110
+ end
111
+ coords
112
+ end
113
+ end
114
+ end
@@ -8,22 +8,39 @@ module Scruffy::Layers
8
8
  class Line < Base
9
9
 
10
10
  # Renders line graph.
11
+ #
12
+ # Options:
13
+ # See initialize()
11
14
  def draw(svg, coords, options={})
12
- svg.g(:class => 'shadow', :transform => "translate(#{relative(0.5)}, #{relative(0.5)})") {
13
- svg.polyline( :points => stringify_coords(coords).join(' '), :fill => 'transparent',
14
- :stroke => 'black', 'stroke-width' => relative(2),
15
- :style => 'fill-opacity: 0; stroke-opacity: 0.35' )
16
-
17
- coords.each { |coord| svg.circle( :cx => coord.first, :cy => coord.last + relative(0.9), :r => relative(2),
18
- :style => "stroke-width: #{relative(2)}; stroke: black; opacity: 0.35;" ) }
19
- }
20
-
21
-
22
- svg.polyline( :points => stringify_coords(coords).join(' '), :fill => 'none',
23
- :stroke => color.to_s, 'stroke-width' => relative(2) )
15
+
16
+ # Include options provided when the object was created
17
+ options.merge!(@options)
18
+
19
+ stroke_width = (options[:relativestroke]) ? relative(options[:stroke_width]) : options[:stroke_width]
20
+ style = (options[:style]) ? options[:style] : ''
21
+
22
+ if options[:shadow]
23
+ svg.g(:class => 'shadow', :transform => "translate(#{relative(0.5)}, #{relative(0.5)})") {
24
+ svg.polyline( :points => stringify_coords(coords).join(' '), :fill => 'transparent',
25
+ :stroke => 'black', 'stroke-width' => stroke_width,
26
+ :style => 'fill-opacity: 0; stroke-opacity: 0.35' )
27
+
28
+ if options[:dots]
29
+ coords.each { |coord| svg.circle( :cx => coord.first, :cy => coord.last + relative(0.9), :r => stroke_width,
30
+ :style => "stroke-width: #{stroke_width}; stroke: black; opacity: 0.35;" ) }
31
+ end
32
+ }
33
+ end
34
+
24
35
 
25
- coords.each { |coord| svg.circle( :cx => coord.first, :cy => coord.last, :r => relative(2),
26
- :style => "stroke-width: #{relative(2)}; stroke: #{color.to_s}; fill: #{color.to_s}" ) }
36
+ svg.polyline( :points => stringify_coords(coords).join(' '), :fill => 'none', :stroke => @color.to_s,
37
+ 'stroke-width' => stroke_width, :style => style )
38
+
39
+ if options[:dots]
40
+ coords.each { |coord| svg.circle( :cx => coord.first, :cy => coord.last, :r => stroke_width,
41
+ :style => "stroke-width: #{stroke_width}; stroke: #{color.to_s}; fill: #{color.to_s}" ) }
42
+ end
43
+
27
44
  end
28
45
  end
29
46
  end
@@ -0,0 +1,74 @@
1
+ module Scruffy::Layers
2
+ # ==Scruffy::Layers::Multi
3
+ #
4
+ # Author:: Jeremy Green
5
+ # Date:: July 29th, 2009
6
+ #
7
+ # Based on:: Scruffy::Layers::Stacked by
8
+ # Author:: Brasten Sager
9
+ # Date:: August 12th, 2006
10
+ #
11
+ # Provides a generic way for displaying multiple bar graphs side by side.
12
+ class Multi < Base
13
+ include Scruffy::Helpers::LayerContainer
14
+
15
+ # Returns new Multi graph.
16
+ #
17
+ # You can provide a block for easily adding layers during (just after) initialization.
18
+ # Example:
19
+ # Multi.new do |multi|
20
+ # multi << Scruffy::Layers::Line.new( ... )
21
+ # multi.add(:multi_bar, 'My Bar', [...])
22
+ # end
23
+ #
24
+ # The initialize method passes itself to the block, and since multi is a LayerContainer,
25
+ # layers can be added just as if they were being added to Graph.
26
+ def initialize(options={}, &block)
27
+ super(options)
28
+
29
+ block.call(self) # Allow for population of data with a block during initialization.
30
+ end
31
+
32
+ # Overrides Base#render to fiddle with layers' points to achieve a multi effect.
33
+ def render(svg, options = {})
34
+ #TODO ensure this works with new points
35
+ #current_points = points
36
+ layers.each_with_index do |layer,i|
37
+
38
+ #real_points = layer.points
39
+ #layer.points = current_points
40
+ layer_options = options.dup
41
+
42
+ layer_options[:num_bars] = layers.size
43
+ layer_options[:position] = i
44
+ layer_options[:color] = layer.preferred_color || layer.color || options[:theme].next_color
45
+ layer.render(svg, layer_options)
46
+
47
+ options.merge(layer_options)
48
+
49
+ #layer.points = real_points
50
+ #layer.points.each_with_index { |val, idx| current_points[idx] -= val }
51
+ end
52
+ end
53
+
54
+ # A multi graph has many data sets. Return legend information for all of them.
55
+ def legend_data
56
+ if relevant_data?
57
+ retval = []
58
+ layers.each do |layer|
59
+ retval << layer.legend_data
60
+ end
61
+ retval
62
+ else
63
+ nil
64
+ end
65
+ end
66
+
67
+ # TODO, special points accessor
68
+
69
+
70
+ def points=(val)
71
+ throw ArgumentsError, "Multi layers cannot accept points, only other layers."
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,119 @@
1
+ module Scruffy::Layers
2
+ # ==Scruffy::Layers::MulitArea
3
+ #
4
+ # Author:: Martyn Taylor
5
+ # Date:: July 30th 2010
6
+ #
7
+ # Multi Area graph.
8
+
9
+ class MultiArea < Base
10
+
11
+ attr_accessor :baselines
12
+ attr_accessor :area_colors
13
+
14
+ def initialize(options = {}, &block)
15
+ super(options)
16
+ @area_colors = options[:area_colors] ? options[:area_colors] : nil
17
+ @baselines = options[:baselines] ? options[:baselines] : nil
18
+ end
19
+
20
+ # Render Multi Area graph.
21
+ def draw(svg, coords, options={})
22
+ # Check whether to use color from theme, or whether to use user defined colors from the area_colors array
23
+ color_count = nil
24
+ if @area_colors && @area_colors.size > 0
25
+ area_color = @area_colors[0]
26
+ color_count = 1
27
+ else
28
+ puts "Never Set Area Color"
29
+ area_color = color
30
+ end
31
+
32
+ # Draw Bottom Level Polygons (Original Coords)
33
+ draw_poly(svg, coords, area_color, options = {})
34
+
35
+ # Draw Lower Area Polygons
36
+ if @baselines
37
+ # Get the Color of this Area
38
+ puts "Drawing Baselines"
39
+ @baselines.sort! {|x,y| y <=> x }
40
+ @baselines.each do |baseline|
41
+ if color_count
42
+ area_color = area_colors[color_count]
43
+ color_count = color_count + 1
44
+ puts area_color.to_s
45
+ if color_count >= area_colors.size
46
+ color_count = 0
47
+ end
48
+ end
49
+
50
+ lower_poly_coords = create_lower_polygon_coords(translate_number(baseline), coords, options)
51
+ draw_poly(svg, lower_poly_coords, area_color, options = {})
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+ def draw_poly(svg, coords, color, options={})
58
+ points_value1 = "0,#{height} #{stringify_coords(coords).join(' ')} #{width},#{height}"
59
+ svg.polygon(:points => points_value1, :fill => color.to_s, :stroke => color.to_s, 'style' => "opacity: #{opacity}")
60
+ end
61
+
62
+ def calculate_intersection(baseline, point1, point2)
63
+ x1 = point1[0]
64
+ y1 = point1[1]
65
+ x2 = point2[0]
66
+ y2 = point2[1]
67
+
68
+ # Check whether baseline intersects with the two point line from these coords
69
+ if ((y2 >= baseline) && (y1 <= baseline)) || ((y1 >= baseline) && (y2 <= baseline))
70
+ # Calculate point of intersection
71
+ y = baseline.to_f
72
+ m = (y2.to_f - y1.to_f) / (x2.to_f - x1.to_f)
73
+ c = y1.to_f
74
+
75
+ x = (y.to_f - c.to_f) / m.to_f
76
+ return [x + x1, y]
77
+ elsif (y2 <= baseline) && (y1 <= baseline)
78
+ return nil
79
+ else
80
+ return [x2, y2]
81
+ end
82
+ end
83
+
84
+
85
+ def create_lower_polygon_coords(baseline, coords, options={})
86
+ lower_poly_coords = []
87
+ if coords[0][1] <= baseline
88
+ lower_poly_coords << [coords[0][0], baseline]
89
+ else
90
+ lower_poly_coords << coords[0]
91
+ end
92
+
93
+ coords.each_index do |index|
94
+ if index + 1 < coords.size
95
+ poi = calculate_intersection(baseline, coords[index], coords[index + 1])
96
+ if poi
97
+ lower_poly_coords << poi
98
+ if(coords[index + 1][1] > baseline)
99
+ lower_poly_coords << coords[index + 1]
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ if coords.last[1] <= baseline
106
+ lower_poly_coords << [coords.last[0], baseline]
107
+ else
108
+ lower_poly_coords << coords.last
109
+ end
110
+
111
+ return lower_poly_coords
112
+ end
113
+
114
+ def translate_number(baseline)
115
+ relative_percent = ((baseline == min_value) ? 0 : ((baseline.to_f - min_value.to_f) / (max_value.to_f - min_value.to_f).to_f))
116
+ return (height.to_f - (height.to_f * relative_percent))
117
+ end
118
+ end
119
+ end