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 122
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 136
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, ty = 0, 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 42
def set_viewbox_none(width, height)
    sx, sy = 1.0, 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