module Magick::RVG::Stretchable
def add_viewbox_primitives(width, height, gc)
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
def align_to_viewport(width, height, sx, sy)
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
def initialize(*_args)
def initialize(*_args) super() @vbx_x, @vbx_y, @vbx_width, @vbx_height = nil @meet_or_slice = 'meet' @align = nil end
def set_viewbox_meet(width, height)
def set_viewbox_meet(width, height) sx = sy = [width / @vbx_width, height / @vbx_height].min [sx, sy] end
def set_viewbox_none(width, height)
def set_viewbox_none(width, height) sx = 1.0 sy = 1.0 sx = width / @vbx_width if @vbx_width sy = height / @vbx_height if @vbx_height [sx, sy] end
def set_viewbox_slice(width, height)
def set_viewbox_slice(width, height) sx = sy = [width / @vbx_width, height / @vbx_height].max [sx, sy] end
def viewbox(x, y, width, height)
The arguments must be numbers and the +width+ and +height+
Describe a user coordinate system to be imposed on the viewbox.
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 raise(ArgumentError, "viewbox width must be > 0 (#{@vbx_width} given)") unless @vbx_width >= 0 raise(ArgumentError, "viewbox height must be > 0 (#{@vbx_height} given)") unless @vbx_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