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
@@ -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