class Rasem::SVGTag

Attributes

attributes[R]
children[R]
tag[R]

Public Class Methods

new(tag, attributes={}, &block) click to toggle source
# File lib/rasem/svg_image.rb, line 79
def initialize(tag, attributes={}, &block)
  @tag = validate_tag(tag)
  @attributes = validate_attributes(attributes)
  @children = []

  if block
    instance_exec &block
  end
end

Public Instance Methods

append_child(child) click to toggle source
# File lib/rasem/svg_image.rb, line 276
def append_child(child)
  @children.push(child)
  child.push_defaults(merge_defaults()) if @defaults
  child
end
linearGradient(id, attributes={}, if_exists = :skip, &block) click to toggle source

special case for linearGradient

# File lib/rasem/svg_image.rb, line 220
def linearGradient(id, attributes={}, if_exists = :skip, &block)
  raise "image reference isn't set, cannot use 'defs' (and thus linearGradient) !" if @img.nil?
  @img.add_def(id, Rasem::SVGLinearGradient.new(@img, attributes), if_exists, &block)
end
matrix(a, b, c, d, e, f) click to toggle source
# File lib/rasem/svg_image.rb, line 125
def matrix(a, b, c, d, e, f)
  add_transform(:matrix, "#{a}, #{b}, #{c}, #{d}, #{e}, #{f}")
  self
end
merge_defaults() click to toggle source
# File lib/rasem/svg_image.rb, line 283
def merge_defaults()
  result = {}
  return result if @defaults.empty?
  @defaults.each { |d| result.merge!(d) }
  result
end
method_missing(meth, *args, &block) click to toggle source
Calls superclass method
# File lib/rasem/svg_image.rb, line 324
def method_missing(meth, *args, &block)
  #if method is a setter or a getter, check valid attributes:
  check = /^(?<name>.*)(?<op>=|\?)$/.match(meth)
  if check
    raise "Passing a code block to setter or getter is not permited!" if block
    name = validate_attribute(check[:name].to_sym)
    if check[:op] == '?'
      @attributes[name]
    elsif check[:op] == '='
      raise "Setting an attribute with multiple values is not permited!" if args.size > 1
      @attributes[name] = args[0]
    end
  elsif child = validate_child_name(meth)
    spawn_child(child, *args, &block)
  else
    super
  end
end
path(attributes = {}, &block) click to toggle source

special case for path block

# File lib/rasem/svg_image.rb, line 207
def path(attributes = {}, &block)
  append_child Rasem::SVGPath.new(@img, attributes, &block)
end
pop_defaults() click to toggle source
# File lib/rasem/svg_image.rb, line 297
def pop_defaults()
  @defaults.pop()
end
push_defaults(defaults) click to toggle source
# File lib/rasem/svg_image.rb, line 291
def push_defaults(defaults)
  @defaults = [] unless @defaults
  @defaults.push(defaults)
end
radialGradient(id, attributes={}, if_exists = :skip, &block) click to toggle source

special case for radialGradient

# File lib/rasem/svg_image.rb, line 227
def radialGradient(id, attributes={}, if_exists = :skip, &block)
  raise "image reference isn't set, cannot use 'defs' (and thus radialGradient) !" if @img.nil?
  @img.add_def(id, Rasem::SVGRadialGradient.new(@img, attributes), if_exists, &block)
end
raw(data) click to toggle source

special case for raw blocks.

# File lib/rasem/svg_image.rb, line 201
def raw(data)
  append_child Rasem::SVGRaw.new(@img, data)
end
rotate(angle, cx = nil, cy = nil) click to toggle source
# File lib/rasem/svg_image.rb, line 107
def rotate(angle, cx = nil, cy = nil)
  add_transform(:rotate, "#{angle}#{(cx.nil? or cy.nil?) ? "" : ", #{cx}, #{cy}"}")
  self
end
scale(sx, sy = 1) click to toggle source
# File lib/rasem/svg_image.rb, line 101
def scale(sx, sy = 1)
  add_transform(:scale, "#{sx}, #{sy}")
  self
end
skewX(angle) click to toggle source
# File lib/rasem/svg_image.rb, line 113
def skewX(angle)
  add_transform(:skewX, "#{angle}")
  self
end
skewY(angle) click to toggle source
# File lib/rasem/svg_image.rb, line 119
def skewY(angle)
  add_transform(:skewY, "#{angle}")
  self
end
spawn_child(nil, [hash], [...]) click to toggle source
# File lib/rasem/svg_image.rb, line 235
def spawn_child(tag, *args, &block)
  #expected args: nil, [hash], [...]
  parameters = {} if args.size == 0

  unless parameters #are empty
    parameters = args[0] if args[0].is_a? Hash
  end

  unless parameters #are set
    #try to find args expansion rule
    expansion = Rasem::SVG_EXPANSION[tag.to_sym]
    raise "Unnamed parameters for #{tag} are not allowed!" unless expansion
  
    if expansion.is_a? Array
      raise "Bad unnamed parameter count for #{tag}, expecting #{expansion.size} got #{if args.last.is_a? Hash then args.size-1 else args.size end}" unless (args.size == expansion.size and not args.last.is_a? Hash) or (args.size - 1 == expansion.size and args.last.is_a? Hash)
      parameters = Hash[expansion.zip(args)]
      if args.last.is_a? Hash
        parameters.merge! args.last
      end
    elsif expansion.is_a? Proc
      hash = args.pop if args.last.is_a? Hash
      parameters = expansion.call(args)
      parameters.merge! hash if hash
    else
      raise "Unexpected expansion mechanism: #{expansion.class}"
    end
  end

  # add default parameters if they are not overwritten
  merge_defaults().each do |key, value|
    parameters[key] = value unless parameters[key]
  end if @defaults

  Rasem::SVG_DEFAULTS[tag.to_sym].each do |key, value|
    parameters[key] = value unless parameters[key]
  end if Rasem::SVG_DEFAULTS[tag.to_sym]

  append_child(Rasem::SVGTagWithParent.new(@img, tag, parameters, &block))
end
to_s() click to toggle source
# File lib/rasem/svg_image.rb, line 369
def to_s
  str = ""
  write(str)
  return str
end
translate(tx, ty = 0) click to toggle source

Provide methods for SVG transformations

# File lib/rasem/svg_image.rb, line 95
def translate(tx, ty = 0)
  add_transform(:translate, "#{tx}, #{ty}")
  self
end
use(id, attributes = {}) click to toggle source

special case for use block

# File lib/rasem/svg_image.rb, line 213
def use(id, attributes = {})
  id = id.attributes[:id] if id.is_a? Rasem::SVGTag
  append_child Rasem::SVGTagWithParent.new(@img, "use", attributes.merge("xlink:href" => "##{id}"))
end
validate_attribute(attribute) click to toggle source
# File lib/rasem/svg_image.rb, line 168
def validate_attribute(attribute)
  raise "#{@tag} does not support attribute #{attribute}" unless Rasem::SVG_STRUCTURE[@tag.to_sym][:attributes].include?(attribute.to_sym)
  attribute.to_sym
end
validate_attributes(attributes) click to toggle source
# File lib/rasem/svg_image.rb, line 137
def validate_attributes(attributes)
  clean_attributes = {}
  transforms = {}
  styles = {}

  attributes.each do |attribute, value|
    if Rasem::SVG_TRANSFORM.include? attribute
      transforms[attribute] = value
    elsif Rasem::CSS_STYLE.include? attribute
      styles[attribute] = value
    else
      clean_attributes[validate_attribute(attribute)] = value
    end
  end

  #always prefer more verbose definition.
  unless transforms.empty?
    transforms.merge!(clean_attributes[:transform]) if clean_attributes[:transform]
    str = ""
    write_transforms(transforms, str)
    clean_attributes[validate_attribute(:transform)] = str
  end

  unless styles.empty?
    styles.merge!(clean_attributes[:style]) if clean_attributes[:style]
    clean_attributes[validate_attribute(:style)] = styles
  end
  clean_attributes
end
validate_child_name(name) click to toggle source
# File lib/rasem/svg_image.rb, line 311
def validate_child_name(name)
  #aliases the name (like, group instead of g)
  name = Rasem::SVG_ALIAS[name.to_sym] if Rasem::SVG_ALIAS[name.to_sym]

  #raises only if given name is an actual svg tag. In other case -- assumes user just mistyped.
  if Rasem::SVG_STRUCTURE[@tag.to_sym][:elements].include?(name.to_sym)
    name.to_sym
  elsif Rasem::SVG_ELEMENTS.include?(name.to_sym)
    raise "#{@tag} should not contain child #{name}" 
  end
end
validate_tag(tag) click to toggle source
# File lib/rasem/svg_image.rb, line 131
def validate_tag(tag)
  raise "#{tag} is not a valid tag" unless Rasem::SVG_ELEMENTS.include?(tag.to_sym)
  tag.to_sym
end
with_style(style={}, &proc) click to toggle source
# File lib/rasem/svg_image.rb, line 302
def with_style(style={}, &proc)
  push_defaults(style)
  # Call the block
  self.instance_exec(&proc)
  # Pop style again to revert changes
  pop_defaults()
end
write(output) click to toggle source
# File lib/rasem/svg_image.rb, line 344
def write(output)
  raise "Can not write to given output!" unless output.respond_to?(:<<)
  output << "<#{@tag.to_s}"
  @attributes.each do
    |attribute, value|
    output << " #{attribute.to_s}=\""
    if attribute == :style
      write_styles(value, output)
    elsif attribute == :points
      write_points(value, output)
    else
      output << "#{value.to_s}"
    end
    output << "\""
  end

  if @children.empty?
    output << "/>"
  else
    output << ">"
    @children.each { |c| c.write(output) }
    output << "</#{@tag.to_s}>"
  end  
end
write_points(points, output) click to toggle source
# File lib/rasem/svg_image.rb, line 191
def write_points(points, output)
  points.each_with_index do |value, index|
    output << value.to_s
    output << ',' if index.even?
    output << ' ' if (index.odd? and (index != points.size-1))
  end
end
write_styles(styles, output) click to toggle source
# File lib/rasem/svg_image.rb, line 174
def write_styles(styles, output)
  styles.each do |attribute, value|
    attribute = attribute.to_s
    attribute.gsub!('_','-')
    output << "#{attribute}:#{value};"
  end
end
write_transforms(transforms, output) click to toggle source
# File lib/rasem/svg_image.rb, line 183
def write_transforms(transforms, output)
  transforms.each do |attribute, value|
    value = [value] unless value.is_a?(Array)
    output << "#{attribute.to_s}(#{value.join(',')}) "
  end
end

Private Instance Methods

add_transform(type, params) click to toggle source
# File lib/rasem/svg_image.rb, line 378
def add_transform(type, params)
  attr_name = validate_attribute(:transform)
  @attributes[attr_name] = "" if @attributes[attr_name].nil?
  @attributes[attr_name] = @attributes[attr_name] + "#{type}(#{params})"
end