class SVGEE attr_reader :primitives, :defs, :supported_primitives def initialize(args) opts = {:width => '100%', :height => '100%'}.merge!(args) @width = opts[:width] @height = opts[:height] @style= opts[:style] @primitives = [] @defs = [] @supported_primitives = [:circle, :rectangle, :ellipse, :line, :polyline, :text] end def open_tag %{} end def close_tag %{} end private def add(primitive_string) @primitives << primitive_string end def add_def(definition_string) @defs << definition_string end def make_tag(primitive, args) if args.has_key?(:link) add link_and_tag(primitive, args) else add self.send("#{primitive}_tag", args) end return Primitive.new(primitive, args) end def link_and_tag(primitive, args) %{} + self.send("#{primitive}_tag", args) + %{} end def circle_tag(a = {}) %{} end def rectangle_tag(a = {}) %{} end def ellipse_tag(a = {}) %{} end def line_tag(a = {}) %{} end def polyline_tag(a={}) %{} end def polygon_tag(a={}) %{} end def text_tag(a = {}) %{#{a[:text]}} end def common_attributes(a={}) %{stroke="#{a[:stroke]}" stroke-width="#{a[:stroke_width]}" style="#{a[:style]}"} end def method_missing(primitive, args={}) #only used to dynamically select the primitive type.. raise NoMethodError if not self.supported_primitives.include?(primitive) #we're only doing the listed primitive types... self.send "make_tag", primitive, args end public def add_primitive(primitive_object) #adds a primitive object to the SVG args = {} primitive_object.instance_variables.each{|v| args[v.gsub(/@/,"").to_sym] = primitive_object.instance_variable_get(v) } primitive_string = args.delete(:primitive) make_tag(primitive_string, args) end def gradient(a) definition_string = case a[:type] when :radial %{} else %{} end a[:stops].each do |s| definition_string = definition_string + "\n" + %{} end add_def definition_string + (a[:type] == :linear ? '' : '') end def draw head = self.open_tag defstring = "" defstring = "\n" + self.defs.join("\n") + "\n \n" if not defs.empty? shapes = self.primitives.join("\n") close = self.close_tag head + defstring + shapes + close end end =begin How to use SVGEE s = SVGEE.new s.gradient(:radial => "grad1", :cx => 50, :cy => 50, :r => 50, :fx => 50, :fy => 50, :stops => [ {:offset => 0, :color => 'rgb(255,255,255)', :opacity => 0}, {:offset => 100, :color => 'rgb(0,0,255)', :opacity => 1},] ) s.circle(:x_center => 40, :y_center => 40, :radius => 20, :fill_color => "url(#grad1)") s.circle(:x_center => 250, :y_center => 250, :radius => 20, :fill_color => "url(#grad1)", :link => {:href => "http://www.bbc.co.uk"}) s.rectangle(:x => 125, :y => 125, :width => 100, :height => 50, :fill_color => 'red', :stroke => 'black', :stroke_width => 2, :style => "fill-opacity:0.1;stroke-opacity:0.9") s.rectangle(:x => 125, :y => 125, :round_x => 5, :round_y => 5, :width => 100, :height => 50, :fill_color => 'red', :stroke => 'black', :stroke_width => 2, :style => "fill-opacity:0.1;stroke-opacity:0.9") prim = s.ellipse(:x_center => 100, :y_center => 190, :x_radius => 40, :y_radius => 20, :fill_color => 'green', :stroke => 'black') s.line(:x1 => 10, :y1 => 10, :x2 => 145, :y2 => 145, :stroke_width => 5, :stroke => 'blue') s.polyline(:points => "2,2 400,440 600,440", :stroke_width => 10, :stroke => "#f00", :fill => "none") s.text(:x => 100, :y => 100, :fill => 'red', :text => "Look! A circle!", :style => "letter-spacing:2;font-family:Arial") s.text(:x => 100, :y => 400, :fill => 'green', :text => "This one is a link", :link => {:href => "http://www.bbc.co.uk"}) prim.update(:x_center => 200) s.add_primitive(prim) #add one of the returned, updated Primitive objects s.draw =end