Class: Fontisan::Svg::ViewBoxCalculator

Inherits:
Object
  • Object
show all
Defined in:
lib/fontisan/svg/view_box_calculator.rb

Overview

Calculates SVG viewBox and handles coordinate transformations

[‘ViewBoxCalculator`](lib/fontisan/svg/view_box_calculator.rb) manages the coordinate system transformation between font space and SVG space. Font coordinates use a Y-up system (ascender is positive), while SVG uses Y-down (origin at top-left).

Responsibilities:

  • Calculate appropriate viewBox for glyphs

  • Transform Y-coordinates (flip Y-axis)

  • Scale coordinates based on units-per-em

  • Provide consistent coordinate mapping

This is a pure utility class with no state or side effects.

Examples:

Transform a Y coordinate

calculator = ViewBoxCalculator.new(units_per_em: 1000, ascent: 800, descent: -200)
svg_y = calculator.transform_y(700)  # Font Y to SVG Y

Calculate viewBox for a glyph

viewbox = calculator.calculate_viewbox(x_min: 100, y_min: 0, x_max: 600, y_max: 700)
# => "100 100 500 700"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(units_per_em:, ascent:, descent:) ⇒ ViewBoxCalculator

Initialize calculator with font metrics

Parameters:

  • units_per_em (Integer)

    Units per em from font head table

  • ascent (Integer)

    Font ascent from hhea table

  • descent (Integer)

    Font descent from hhea table (typically negative)

Raises:

  • (ArgumentError)

    If parameters are invalid



43
44
45
46
47
48
49
# File 'lib/fontisan/svg/view_box_calculator.rb', line 43

def initialize(units_per_em:, ascent:, descent:)
  validate_parameters!(units_per_em, ascent, descent)

  @units_per_em = units_per_em
  @ascent = ascent
  @descent = descent
end

Instance Attribute Details

#ascentInteger (readonly)

Returns Font ascent.

Returns:

  • (Integer)

    Font ascent



32
33
34
# File 'lib/fontisan/svg/view_box_calculator.rb', line 32

def ascent
  @ascent
end

#descentInteger (readonly)

Returns Font descent (typically negative).

Returns:

  • (Integer)

    Font descent (typically negative)



35
36
37
# File 'lib/fontisan/svg/view_box_calculator.rb', line 35

def descent
  @descent
end

#units_per_emInteger (readonly)

Returns Units per em from font.

Returns:

  • (Integer)

    Units per em from font



29
30
31
# File 'lib/fontisan/svg/view_box_calculator.rb', line 29

def units_per_em
  @units_per_em
end

Instance Method Details

#calculate_viewbox(x_min:, y_min:, x_max:, y_max:) ⇒ String

Calculate viewBox string for SVG

Parameters:

  • x_min (Numeric)

    Minimum X coordinate

  • y_min (Numeric)

    Minimum Y coordinate

  • x_max (Numeric)

    Maximum X coordinate

  • y_max (Numeric)

    Maximum Y coordinate

Returns:

  • (String)

    ViewBox string “x y width height”



80
81
82
83
84
85
86
87
88
89
# File 'lib/fontisan/svg/view_box_calculator.rb', line 80

def calculate_viewbox(x_min:, y_min:, x_max:, y_max:)
  # Transform bounding box to SVG space
  svg_y_min = transform_y(y_max) # Y is flipped
  svg_y_max = transform_y(y_min)

  width = x_max - x_min
  height = svg_y_max - svg_y_min

  "#{x_min} #{svg_y_min} #{width} #{height}"
end

#font_viewboxString

Calculate font-level viewBox

Uses font metrics to create a viewBox covering the entire font space

Returns:

  • (String)

    ViewBox string for entire font



96
97
98
99
100
101
# File 'lib/fontisan/svg/view_box_calculator.rb', line 96

def font_viewbox
  # Typical font viewBox covers descent to ascent
  # Width is units_per_em
  height = ascent - descent
  "0 0 #{units_per_em} #{height}"
end

#scale_factor(target_units: 1000) ⇒ Float

Get scale factor for coordinate precision

Parameters:

  • target_units (Integer) (defaults to: 1000)

    Target units per em (default 1000)

Returns:

  • (Float)

    Scale factor



107
108
109
# File 'lib/fontisan/svg/view_box_calculator.rb', line 107

def scale_factor(target_units: 1000)
  target_units.to_f / units_per_em
end

#transform_point(font_x, font_y) ⇒ Array<Numeric>

Transform point from font space to SVG space

Parameters:

  • font_x (Numeric)

    X coordinate in font space

  • font_y (Numeric)

    Y coordinate in font space

Returns:

  • (Array<Numeric>)
    svg_x, svg_y


69
70
71
# File 'lib/fontisan/svg/view_box_calculator.rb', line 69

def transform_point(font_x, font_y)
  [font_x, transform_y(font_y)]
end

#transform_y(font_y) ⇒ Numeric

Transform Y coordinate from font space to SVG space

Font space: Y-up (ascender positive, descender negative) SVG space: Y-down (origin at top)

Transformation: svg_y = ascent - font_y

Parameters:

  • font_y (Numeric)

    Y coordinate in font space

Returns:

  • (Numeric)

    Y coordinate in SVG space



60
61
62
# File 'lib/fontisan/svg/view_box_calculator.rb', line 60

def transform_y(font_y)
  ascent - font_y
end