The methods in this module describe the user-coordinate space. RVG and Pattern objects are stretchable.
# 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
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
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
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
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
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
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