module Magick::RVG::Stretchable

The methods in this module describe the user-coordinate space. RVG and Pattern objects are stretchable.

Public Class Methods

new(*args, &block) click to toggle source
Calls superclass method
# File lib/rvg/stretchable.rb, line 123
def initialize(*args, &block)
  super()
  @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil
  @meet_or_slice = 'meet'
  @align = nil
end

Public Instance Methods

viewbox(x, y, width, height) { |self| ... } click to toggle source

Describe a user coordinate system to be imposed on the viewbox. The arguments must be numbers and the width and height arguments must be positive.

# File lib/rvg/stretchable.rb, line 137
def viewbox(x, y, width, height)
  begin
    @vbx_x = Float(x)
    @vbx_y = Float(y)
    @vbx_width = Float(width)
    @vbx_height = Float(height)
  rescue ArgumentError
    raise ArgumentError, "arguments must be convertable to float (got #{x.class}, #{y.class}, #{width.class}, #{height.class})"
  end
  fail(ArgumentError, "viewbox width must be > 0 (#{width} given)") unless width >= 0
  fail(ArgumentError, "viewbox height must be > 0 (#{height} given)") unless height >= 0

  # return the user-coordinate space attributes if defined
  class << self
    unless defined? @redefined
    @redefined = true
    define_method(:x) { @vbx_x }
    define_method(:y) { @vbx_y }
    define_method(:width) { @vbx_width}
    define_method(:height) { @vbx_height }
    end
  end

  yield(self) if block_given?
  self
end

Private Instance Methods

add_viewbox_primitives(width, height, gc) click to toggle source

Establish the viewbox as necessary

# File lib/rvg/stretchable.rb, line 90
def add_viewbox_primitives(width, height, gc)
  @vbx_width  ||= width
  @vbx_height ||= height
  @vbx_x ||= 0.0
  @vbx_y ||= 0.0

  if @align == 'none'
    sx, sy = set_viewbox_none(width, height)
    tx = 0
    ty = 0
  elsif @meet_or_slice == 'meet'
    sx, sy = set_viewbox_meet(width, height)
    tx, ty = align_to_viewport(width, height, sx, sy)
  else
    sx, sy = set_viewbox_slice(width, height)
    tx, ty = align_to_viewport(width, height, sx, sy)
  end

  # Establish clipping path around the current viewport
  name = __id__.to_s
  gc.define_clip_path(name) do
    gc.path("M0,0 l#{width},0 l0,#{height} l-#{width},0 l0,-#{height}z")
  end

  gc.clip_path(name)
  # Add a non-scaled translation if meet or slice
  gc.translate(tx, ty) if tx.abs > 1.0e-10 || ty.abs > 1.0e-10
  # Scale viewbox as necessary
  gc.scale(sx, sy) if sx != 1.0 || sy != 1.0
  # Add a scaled translation if non-0 origin
  gc.translate(-@vbx_x, -@vbx_y) if @vbx_x.abs != 0.0 || @vbx_y.abs != 0
end
align_to_viewport(width, height, sx, sy) click to toggle source

Use align attribute to compute x- and y-offset from viewport's upper-left corner.

# File lib/rvg/stretchable.rb, line 56
def align_to_viewport(width, height, sx, sy)
  tx = case @align
       when /\AxMin/
         0
       when NilClass, /\AxMid/
         (width - @vbx_width*sx) / 2.0
       when /\AxMax/
         width - @vbx_width*sx
  end

  ty = case @align
       when /YMin\z/
         0
       when NilClass, /YMid\z/
         (height - @vbx_height*sy) / 2.0
       when /YMax\z/
         height - @vbx_height*sy
  end
  [tx, ty]
end
set_viewbox_meet(width, height) click to toggle source

Scale to smaller viewbox dimension

# File lib/rvg/stretchable.rb, line 78
def set_viewbox_meet(width, height)
  sx = sy = [width / @vbx_width, height / @vbx_height].min
  [sx, sy]
end
set_viewbox_none(width, height) click to toggle source

Scale to fit

# File lib/rvg/stretchable.rb, line 41
def set_viewbox_none(width, height)
  sx = 1.0
  sy = 1.0

  if @vbx_width
    sx = width / @vbx_width
  end
  if @vbx_height
    sy = height / @vbx_height
  end

  [sx, sy]
end
set_viewbox_slice(width, height) click to toggle source

Scale to larger viewbox dimension

# File lib/rvg/stretchable.rb, line 84
def set_viewbox_slice(width, height)
  sx = sy = [width / @vbx_width, height / @vbx_height].max
  [sx, sy]
end