ramhoj-scruffy 0.2.6

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 (55) hide show
  1. data/README.txt +66 -0
  2. data/lib/scruffy.rb +25 -0
  3. data/lib/scruffy/components.rb +21 -0
  4. data/lib/scruffy/components/background.rb +24 -0
  5. data/lib/scruffy/components/base.rb +57 -0
  6. data/lib/scruffy/components/data_markers.rb +26 -0
  7. data/lib/scruffy/components/graphs.rb +48 -0
  8. data/lib/scruffy/components/grid.rb +19 -0
  9. data/lib/scruffy/components/label.rb +17 -0
  10. data/lib/scruffy/components/legend.rb +105 -0
  11. data/lib/scruffy/components/style_info.rb +22 -0
  12. data/lib/scruffy/components/title.rb +19 -0
  13. data/lib/scruffy/components/value_markers.rb +32 -0
  14. data/lib/scruffy/components/viewport.rb +37 -0
  15. data/lib/scruffy/formatters.rb +213 -0
  16. data/lib/scruffy/graph.rb +190 -0
  17. data/lib/scruffy/graph_state.rb +24 -0
  18. data/lib/scruffy/helpers.rb +12 -0
  19. data/lib/scruffy/helpers/canvas.rb +41 -0
  20. data/lib/scruffy/helpers/layer_container.rb +95 -0
  21. data/lib/scruffy/helpers/meta.rb +5 -0
  22. data/lib/scruffy/helpers/point_container.rb +70 -0
  23. data/lib/scruffy/layers.rb +24 -0
  24. data/lib/scruffy/layers/all_smiles.rb +137 -0
  25. data/lib/scruffy/layers/area.rb +46 -0
  26. data/lib/scruffy/layers/average.rb +67 -0
  27. data/lib/scruffy/layers/bar.rb +52 -0
  28. data/lib/scruffy/layers/base.rb +191 -0
  29. data/lib/scruffy/layers/line.rb +46 -0
  30. data/lib/scruffy/layers/pie.rb +123 -0
  31. data/lib/scruffy/layers/pie_slice.rb +119 -0
  32. data/lib/scruffy/layers/scatter.rb +21 -0
  33. data/lib/scruffy/layers/sparkline_bar.rb +39 -0
  34. data/lib/scruffy/layers/stacked.rb +87 -0
  35. data/lib/scruffy/rasterizers.rb +14 -0
  36. data/lib/scruffy/rasterizers/batik_rasterizer.rb +39 -0
  37. data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +27 -0
  38. data/lib/scruffy/renderers.rb +22 -0
  39. data/lib/scruffy/renderers/base.rb +93 -0
  40. data/lib/scruffy/renderers/cubed.rb +44 -0
  41. data/lib/scruffy/renderers/cubed3d.rb +53 -0
  42. data/lib/scruffy/renderers/empty.rb +22 -0
  43. data/lib/scruffy/renderers/pie.rb +20 -0
  44. data/lib/scruffy/renderers/reversed.rb +17 -0
  45. data/lib/scruffy/renderers/sparkline.rb +10 -0
  46. data/lib/scruffy/renderers/split.rb +48 -0
  47. data/lib/scruffy/renderers/standard.rb +36 -0
  48. data/lib/scruffy/themes.rb +156 -0
  49. data/lib/scruffy/version.rb +3 -0
  50. data/spec/output/array.svg +47 -0
  51. data/spec/output/hash.svg +47 -0
  52. data/spec/scruffy/graph_spec.rb +175 -0
  53. data/spec/scruffy/layers/base_spec.rb +30 -0
  54. data/spec/spec_helper.rb +8 -0
  55. metadata +155 -0
@@ -0,0 +1,24 @@
1
+ # ===GraphState
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: September 27th, 2007
5
+ #
6
+ # State object for holding all of the graph's
7
+ # settings. Attempting to clean up the
8
+ # graph interface a bit.
9
+
10
+ module Scruffy
11
+ class GraphState
12
+
13
+ attr_accessor :title
14
+ attr_accessor :theme
15
+ attr_accessor :default_type
16
+ attr_accessor :point_markers
17
+ attr_accessor :value_formatter
18
+ attr_accessor :rasterizer
19
+
20
+ def initialize
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ # ==Scruffy Helpers
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: August 16th, 2006
5
+ #
6
+ # Modules which provide helper methods for various situations.
7
+ module Scruffy::Helpers; end
8
+
9
+ require 'scruffy/helpers/canvas'
10
+ require 'scruffy/helpers/layer_container'
11
+ require 'scruffy/helpers/point_container'
12
+ #require 'scruffy/helpers/meta'
@@ -0,0 +1,41 @@
1
+ module Scruffy::Helpers
2
+
3
+ # ==Scruffy::Helpers::Canvas
4
+ #
5
+ # Author:: Brasten Sager
6
+ # Date:: August 16th, 2006
7
+ #
8
+ # Provides common methods for canvas objects. Primarily used for providing
9
+ # spacial-type calculations where necessary.
10
+ module Canvas
11
+ attr_accessor :components
12
+
13
+ def reset_settings!
14
+ self.options = {}
15
+ end
16
+
17
+ def component(id, components=self.components)
18
+ components.find {|elem| elem.id == id}
19
+ end
20
+
21
+ def remove(id, components=self.components)
22
+ components.delete(component(id))
23
+ end
24
+
25
+ protected
26
+ # Converts percentage values into actual pixel values based on the known
27
+ # render size.
28
+ #
29
+ # Returns a hash consisting of :x, :y, :width, and :height elements.
30
+ def bounds_for(canvas_size, position, size)
31
+ return nil if (position.nil? || size.nil?)
32
+ bounds = {}
33
+ bounds[:x] = canvas_size.first * (position.first / 100.to_f)
34
+ bounds[:y] = canvas_size.last * (position.last / 100.to_f)
35
+ bounds[:width] = canvas_size.first * (size.first / 100.to_f)
36
+ bounds[:height] = canvas_size.last * (size.last / 100.to_f)
37
+ bounds
38
+ end
39
+ end # canvas
40
+
41
+ end # scruffy::helpers
@@ -0,0 +1,95 @@
1
+ module Scruffy::Helpers
2
+
3
+ # ==Scruffy::Helpers::LayerContainer
4
+ #
5
+ # Author:: Brasten Sager
6
+ # Date:: August 16th, 2006
7
+ #
8
+ # Adds some common functionality to any object which needs to act as a
9
+ # container for graph layers. The best example of this is the Scruffy::Graph
10
+ # object itself, but this module is also used by Scruffy::Layer::Stacked.
11
+ module LayerContainer
12
+
13
+ # Adds a Layer to the Graph/Container. Accepts either a list of
14
+ # arguments used to build a new layer, or a Scruffy::Layers::Base-derived
15
+ # object. When passing a list of arguments, all arguments are optional,
16
+ # but the arguments specified must be provided in a particular order:
17
+ # type (Symbol), title (String), points (Array), options (Hash).
18
+ #
19
+ # Both #add and #<< can be used.
20
+ #
21
+ # graph.add(:line, [100, 200, 150]) # Create and add an untitled line graph
22
+ #
23
+ # graph << (:line, "John's Sales", [150, 100]) # Create and add a titled line graph
24
+ #
25
+ # graph << Scruffy::Layers::Bar.new({...}) # Adds Bar layer to graph
26
+ #
27
+ def <<(*args, &block)
28
+ if args[0].kind_of?(Scruffy::Layers::Base)
29
+ layers << args[0]
30
+ else
31
+ type = args.first.is_a?(Symbol) ? args.shift : @default_type
32
+ title = args.shift if args.first.is_a?(String)
33
+
34
+ # Layer handles PointContainer mixin, don't do it here
35
+ points = [Array, Hash].include?(args.first.class) ? args.shift : []
36
+ options = args.first.is_a?(Hash) ? args.shift : {}
37
+
38
+ title ||= ''
39
+
40
+ raise ArgumentError,
41
+ 'You must specify a graph type (:area, :bar, :line, etc) if you do not have a default type specified.' if type.nil?
42
+
43
+ class_name = "Scruffy::Layers::#{to_camelcase(type.to_s)}"
44
+ layer_class = Kernel::module_eval(class_name)
45
+ options = {:points => points, :title => title}.merge options
46
+ layer = layer_class.new(options, &block)
47
+ layers << layer
48
+ end
49
+ layer
50
+ end
51
+
52
+ alias :add :<<
53
+
54
+
55
+ # Layer Writer
56
+ def layers=(val)
57
+ @layers = val
58
+ end
59
+
60
+ # Layer Reader
61
+ def layers
62
+ @layers ||= []
63
+ end
64
+
65
+ # Returns the highest value in any of this container's layers.
66
+ #
67
+ # If padding is set to :padded, a 15% padding is added to the highest value.
68
+ def top_value(padding=nil) # :nodoc:
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
71
+ end
72
+
73
+ # Returns the lowest value in any of this container's layers.
74
+ #
75
+ # If padding is set to :padded, a 15% padding is added below the lowest value.
76
+ # If the lowest value is greater than zero, then the padding will not cross the zero line, preventing
77
+ # negative values from being introduced into the graph purely due to padding.
78
+ 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))
82
+
83
+ # Don't introduce negative values solely due to padding.
84
+ # A user-provided value must be negative before padding will extend into negative values.
85
+ (above_zero && botval < 0) ? 0 : botval
86
+ end
87
+
88
+
89
+ protected
90
+ def to_camelcase(type) # :nodoc:
91
+ type.split('_').map { |e| e.capitalize }.join('')
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,5 @@
1
+ # module Scruffy::Helpers::MetaAttributes
2
+ # def singleton_class
3
+ # (class << self; self; end)
4
+ # end
5
+ # end
@@ -0,0 +1,70 @@
1
+ module Scruffy::Helpers
2
+
3
+ # ==Scruffy::Helpers::PointContainer
4
+ #
5
+ # Author:: Mat Schaffer
6
+ # Date:: March 22nd, 2007
7
+ #
8
+ # Allows all standard point operations to be called on both Array and Hash
9
+ module PointContainer
10
+ def self.extended point_set
11
+ point_set.extend(const_get(point_set.class.to_s))
12
+ end
13
+
14
+ def sortable_values
15
+ values.find_all { |v| v.respond_to? :<=> }
16
+ end
17
+
18
+ def summable_values
19
+ values.find_all { |v| v.respond_to? :+ }
20
+ end
21
+
22
+ def maximum_value
23
+ sortable_values.sort.last
24
+ end
25
+
26
+ def minimum_value
27
+ sortable_values.sort.first
28
+ end
29
+
30
+ def sum
31
+ summable_values.inject(0) { |sum, i| sum += i }
32
+ end
33
+
34
+ def inject_with_index memo
35
+ index = 0
36
+ inject(memo) do |memo, item|
37
+ ret = yield memo, item, index
38
+ index = index.succ
39
+ ret
40
+ end
41
+ end
42
+
43
+ module Array
44
+ def values
45
+ self
46
+ end
47
+ end
48
+
49
+ module Hash
50
+ def minimum_key
51
+ self.keys.sort.first
52
+ end
53
+
54
+ def maximum_key
55
+ self.keys.sort.last
56
+ end
57
+
58
+ def inject memo
59
+ (minimum_key..maximum_key).each do |i|
60
+ memo = yield memo, self[i]
61
+ end
62
+ memo
63
+ end
64
+
65
+ def size
66
+ maximum_key - minimum_key + 1
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,24 @@
1
+ # ==Scruffy::Layers
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: August 10th, 2006
5
+ #
6
+ # See documentation in Scruffy::Layers::Base
7
+ #
8
+ module Scruffy::Layers
9
+
10
+ # Should be raised whenever a predictable error during rendering occurs,
11
+ # particularly if you do not want to terminate the graph rendering process.
12
+ class RenderError < StandardError; end
13
+
14
+ end
15
+
16
+ require 'scruffy/layers/base'
17
+ require 'scruffy/layers/area'
18
+ require 'scruffy/layers/all_smiles'
19
+ require 'scruffy/layers/bar'
20
+ require 'scruffy/layers/line'
21
+ require 'scruffy/layers/average'
22
+ require 'scruffy/layers/stacked'
23
+ require 'scruffy/layers/pie'
24
+ require 'scruffy/layers/pie_slice'
@@ -0,0 +1,137 @@
1
+ module Scruffy::Layers
2
+ # ==Scruffy::Layers::AllSmiles
3
+ #
4
+ # Author:: Brasten Sager
5
+ # Date:: August 8th, 2006
6
+ #
7
+ # The AllSmiles graph consists of smiley faces for data points, with smiles or frowns depending upon
8
+ # their relative location on the graph. The highest point is crowned with a wizard hat. The Wizard
9
+ # Smiley eventually become 'Scruffy', our mascot.
10
+ #
11
+ # I don't know why.
12
+ #
13
+ # This graph only looks decent in SVG mode. If you're rasterizing the graph with ImageMagick, you
14
+ # must use the :complexity => :minimal option on Graph#render. This will make the graph look really
15
+ # nasty, but still better than if you try to rasterize with all the gradients in place.
16
+ class AllSmiles < Base
17
+ attr_accessor :standalone
18
+
19
+ # Returns a new AllSmiles graph.
20
+ #
21
+ # Options:
22
+ # standalone:: If set to true, dashed lines under smilies run vertically, like bar graphs.
23
+ # If false (default), dashed lines run from smiley to smiley, like a line-graph.
24
+ def initialize(options = {})
25
+ super
26
+ @standalone = options[:standalone] || false
27
+ end
28
+
29
+ # Renders graph.
30
+ def draw(svg, coords, options={})
31
+
32
+ hero_smiley = nil
33
+ coords.each { |c| hero_smiley = c.last if (hero_smiley.nil? || c.last < hero_smiley) }
34
+
35
+ svg.defs {
36
+ svg.radialGradient(:id => 'SmileyGradient', :cx => '50%',
37
+ :cy => '50%', :r => '50%', :fx => '30%', :fy => '30%') {
38
+
39
+ svg.stop(:offset => '0%', 'stop-color' => '#FFF')
40
+ svg.stop(:offset => '20%', 'stop-color' => '#FFC')
41
+ svg.stop(:offset => '45%', 'stop-color' => '#FF3')
42
+ svg.stop(:offset => '60%', 'stop-color' => '#FF0')
43
+ svg.stop(:offset => '90%', 'stop-color' => '#990')
44
+ svg.stop(:offset => '100%', 'stop-color' => '#220')
45
+ }
46
+ svg.radialGradient(:id => 'HeroGradient', :cx => '50%',
47
+ :cy => '50%', :r => '50%', :fx => '30%', :fy => '30%') {
48
+
49
+ svg.stop(:offset => '0%', 'stop-color' => '#FEE')
50
+ svg.stop(:offset => '20%', 'stop-color' => '#F0E0C0')
51
+ svg.stop(:offset => '45%', 'stop-color' => '#8A2A1A')
52
+ svg.stop(:offset => '60%', 'stop-color' => '#821')
53
+ svg.stop(:offset => '90%', 'stop-color' => '#210')
54
+ }
55
+ svg.radialGradient(:id => 'StarGradient', :cx => '50%',
56
+ :cy => '50%', :r => '50%', :fx => '30%', :fy => '30%') {
57
+
58
+ svg.stop(:offset => '0%', 'stop-color' => '#FFF')
59
+ svg.stop(:offset => '20%', 'stop-color' => '#EFEFEF')
60
+ svg.stop(:offset => '45%', 'stop-color' => '#DDD')
61
+ svg.stop(:offset => '60%', 'stop-color' => '#BBB')
62
+ svg.stop(:offset => '90%', 'stop-color' => '#888')
63
+ }
64
+ }
65
+
66
+ unless standalone
67
+ svg.polyline( :points => stringify_coords(coords).join(' '), :fill => 'none',
68
+ :stroke => '#660', 'stroke-width' => scaled(10), 'stroke-dasharray' => "#{scaled(10)}, #{scaled(10)}" )
69
+ end
70
+
71
+ # Draw smilies.
72
+ coords.each do |coord|
73
+ if standalone
74
+ svg.line( :x1 => coord.first, :y1 => coord.last, :x2 => coord.first, :y2 => height, :fill => 'none',
75
+ :stroke => '#660', 'stroke-width' => scaled(10), 'stroke-dasharray' => "#{scaled(10)}, #{scaled(10)}" )
76
+ end
77
+ svg.circle( :cx => coord.first + scaled(2), :cy => coord.last + scaled(2), :r => scaled(15),
78
+ :fill => 'black', :stroke => 'none', :opacity => 0.4)
79
+ svg.circle( :cx => coord.first, :cy => coord.last, :r => scaled(15),
80
+ :fill => (complexity == :minimal ? 'yellow' : 'url(#SmileyGradient)'), :stroke => 'black', 'stroke-width' => scaled(1) )
81
+ svg.line( :x1 => (coord.first - scaled(3)),
82
+ :x2 => (coord.first - scaled(3)),
83
+ :y1 => (coord.last),
84
+ :y2 => (coord.last - scaled(7)), :stroke => 'black', 'stroke-width' => scaled(1.4) )
85
+ svg.line( :x1 => (coord.first + scaled(3)),
86
+ :x2 => (coord.first + scaled(3)),
87
+ :y1 => (coord.last),
88
+ :y2 => (coord.last - scaled(7)), :stroke => 'black', 'stroke-width' => scaled(1.4) )
89
+
90
+
91
+ # Some minor mathematics for the smile/frown
92
+ percent = 1.0 - (coord.last.to_f / height.to_f)
93
+ corners = scaled(8 - (5 * percent))
94
+ anchor = scaled((20 * percent) - 5)
95
+
96
+ # Draw the mouth
97
+ svg.path( :d => "M#{coord.first - scaled(9)} #{coord.last + corners} Q#{coord.first} #{coord.last + anchor} #{coord.first + scaled(9)} #{coord.last + corners}",
98
+ :stroke => 'black', 'stroke-width' => scaled(1.4), :fill => 'none' )
99
+
100
+
101
+ # Wizard hat for hero smiley.
102
+ if coord.last == hero_smiley
103
+ svg.ellipse(:cx => coord.first, :cy => (coord.last - scaled(13)),
104
+ :rx => scaled(17), :ry => scaled(6.5), :fill => (complexity == :minimal ? 'purple' : 'url(#HeroGradient)'), :stroke => 'black', 'stroke-width' => scaled(1.4) )
105
+
106
+ svg.path(:d => "M#{coord.first} #{coord.last - scaled(60)} " +
107
+ "L#{coord.first + scaled(10)} #{coord.last - scaled(14)} " +
108
+ "C#{coord.first + scaled(10)},#{coord.last - scaled(9)} #{coord.first - scaled(10)},#{coord.last - scaled(9)} #{coord.first - scaled(10)},#{coord.last - scaled(14)}" +
109
+ "L#{coord.first} #{coord.last - scaled(60)}",
110
+ :stroke => 'black', 'stroke-width' => scaled(1.4), :fill => (complexity == :minimal ? 'purple' : 'url(#HeroGradient)'))
111
+
112
+ svg.path(:d => "M#{coord.first - scaled(4)} #{coord.last - scaled(23)}" +
113
+ "l-#{scaled(2.5)} #{scaled(10)} l#{scaled(7.5)} -#{scaled(5)} l-#{scaled(10)} 0 l#{scaled(7.5)} #{scaled(5)} l-#{scaled(2.5)} -#{scaled(10)}", :stroke => 'none', :fill => (complexity == :minimal ? 'white': 'url(#StarGradient)') )
114
+ svg.path(:d => "M#{coord.first + scaled(2)} #{coord.last - scaled(30)}" +
115
+ "l-#{scaled(2.5)} #{scaled(10)} l#{scaled(7.5)} -#{scaled(5)} l-#{scaled(10)} 0 l#{scaled(7.5)} #{scaled(5)} l-#{scaled(2.5)} -#{scaled(10)}", :stroke => 'none', :fill => (complexity == :minimal ? 'white': 'url(#StarGradient)') )
116
+ svg.path(:d => "M#{coord.first - scaled(2)} #{coord.last - scaled(33)}" +
117
+ "l-#{scaled(1.25)} #{scaled(5)} l#{scaled(3.75)} -#{scaled(2.5)} l-#{scaled(5)} 0 l#{scaled(3.75)} #{scaled(2.5)} l-#{scaled(1.25)} -#{scaled(5)}", :stroke => 'none', :fill => 'white' )
118
+ svg.path(:d => "M#{coord.first - scaled(2.2)} #{coord.last - scaled(32.7)}" +
119
+ "l-#{scaled(1.25)} #{scaled(5)} l#{scaled(3.75)} -#{scaled(2.5)} l-#{scaled(5)} 0 l#{scaled(3.75)} #{scaled(2.5)} l-#{scaled(1.25)} -#{scaled(5)}", :stroke => 'none', :fill => (complexity == :minimal ? 'white': 'url(#StarGradient)') )
120
+ svg.path(:d => "M#{coord.first + scaled(4.5)} #{coord.last - scaled(20)}" +
121
+ "l-#{scaled(1.25)} #{scaled(5)} l#{scaled(3.75)} -#{scaled(2.5)} l-#{scaled(5)} 0 l#{scaled(3.75)} #{scaled(2.5)} l-#{scaled(1.25)} -#{scaled(5)}", :stroke => 'none', :fill => (complexity == :minimal ? 'white': 'url(#StarGradient)') )
122
+ svg.path(:d => "M#{coord.first} #{coord.last - scaled(40)}" +
123
+ "l-#{scaled(1.25)} #{scaled(5)} l#{scaled(3.75)} -#{scaled(2.5)} l-#{scaled(5)} 0 l#{scaled(3.75)} #{scaled(2.5)} l-#{scaled(1.25)} -#{scaled(5)}", :stroke => 'none', :fill => (complexity == :minimal ? 'white': 'url(#StarGradient)') )
124
+
125
+ end
126
+
127
+ end
128
+ end
129
+
130
+ # Legacy (4 days old). Removed scaled from layout engine,
131
+ # changed to #relative, with different math involved.
132
+ # Translate here so I don't have to entirely redo this graph.
133
+ def scaled(pt)
134
+ relative(pt) / 2
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,46 @@
1
+ module Scruffy::Layers
2
+ # ==Scruffy::Layers::Area
3
+ #
4
+ # Author:: Brasten Sager
5
+ # Date:: August 6th, 2006
6
+ #
7
+ # Standard area graph.
8
+ class Area < Base
9
+
10
+ # Render area graph.
11
+ def draw(svg, coords, options={})
12
+ # svg.polygon wants a long string of coords.
13
+ points_value = "0,#{height} #{stringify_coords(coords).join(' ')} #{width},#{height}"
14
+
15
+ # Experimental, for later user.
16
+ # This was supposed to add some fun filters, 3d effects and whatnot.
17
+ # Neither ImageMagick nor Mozilla SVG render this well (at all). Maybe a future thing.
18
+ #
19
+ # svg.defs {
20
+ # svg.filter(:id => 'MyFilter', :filterUnits => 'userSpaceOnUse', :x => 0, :y => 0, :width => 200, :height => '120') {
21
+ # svg.feGaussianBlur(:in => 'SourceAlpha', :stdDeviation => 4, :result => 'blur')
22
+ # svg.feOffset(:in => 'blur', :dx => 4, :dy => 4, :result => 'offsetBlur')
23
+ # svg.feSpecularLighting( :in => 'blur', :surfaceScale => 5, :specularConstant => '.75',
24
+ # :specularExponent => 20, 'lighting-color' => '#bbbbbb',
25
+ # :result => 'specOut') {
26
+ # svg.fePointLight(:x => '-5000', :y => '-10000', :z => '20000')
27
+ # }
28
+ #
29
+ # svg.feComposite(:in => 'specOut', :in2 => 'SourceAlpha', :operator => 'in', :result => 'specOut')
30
+ # svg.feComposite(:in => 'sourceGraphic', :in2 => 'specOut', :operator => 'arithmetic',
31
+ # :k1 => 0, :k2 => 1, :k3 => 1, :k4 => 0, :result => 'litPaint')
32
+ #
33
+ # svg.feMerge {
34
+ # svg.feMergeNode(:in => 'offsetBlur')
35
+ # svg.feMergeNode(:in => 'litPaint')
36
+ # }
37
+ # }
38
+ # }
39
+ svg.g(:transform => "translate(0, -#{relative(2)})") {
40
+ svg.polygon(:points => points_value, :style => "fill: black; stroke: black; fill-opacity: 0.06; stroke-opacity: 0.06;")
41
+ }
42
+
43
+ svg.polygon(:points => points_value, :fill => color.to_s, :stroke => color.to_s, 'style' => "opacity: #{opacity}")
44
+ end
45
+ end
46
+ end