Module: AnimateIt::Timing

Defined in:
lib/animate_it/timing.rb

Class Method Summary collapse

Class Method Details

.interpolate(input, input_range, output_range, easing: :linear, extrapolate_left: :extend, extrapolate_right: :extend) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/animate_it/timing.rb', line 5

def interpolate(input, input_range, output_range, easing: :linear, extrapolate_left: :extend,
                extrapolate_right: :extend)
  unless input_range.size == output_range.size
    raise ArgumentError,
          "input_range and output_range must have the same size"
  end
  raise ArgumentError, "interpolation needs at least two points" if input_range.size < 2

  validate_extrapolation!(extrapolate_left)
  validate_extrapolation!(extrapolate_right)

  left_index = segment_index(input, input_range)
  right_index = left_index + 1
  input_start = input_range[left_index]
  input_end = input_range[right_index]

  if input < input_range.first
    return output_range.first if extrapolate_left == :clamp
    return input if extrapolate_left == :identity
  end

  if input > input_range.last
    return output_range.last if extrapolate_right == :clamp
    return input if extrapolate_right == :identity
  end
  return output_range[left_index] if input_end == input_start

  progress = (input - input_start).to_f / (input_end - input_start)
  eased = Easing.resolve(easing).call(progress)

  output_start = output_range[left_index]
  output_end = output_range[right_index]

  output_start + ((output_end - output_start) * eased)
end

.segment_index(input, input_range) ⇒ Object



50
51
52
53
54
55
# File 'lib/animate_it/timing.rb', line 50

def segment_index(input, input_range)
  return 0 if input <= input_range.first

  index = input_range.each_cons(2).find_index { |left, right| input.between?(left, right) }
  index || (input_range.size - 2)
end

.spring(frame:, fps:, from: 0.0, to: 1.0, stiffness: 100.0, damping: 10.0, mass: 1.0) ⇒ Object



41
42
43
44
45
46
47
48
# File 'lib/animate_it/timing.rb', line 41

def spring(frame:, fps:, from: 0.0, to: 1.0, stiffness: 100.0, damping: 10.0, mass: 1.0)
  seconds = [frame.to_f / fps, 0].max
  angular_frequency = Math.sqrt(stiffness / mass)
  decay = Math.exp((-damping / (2 * mass)) * seconds)
  progress = 1 - (decay * Math.cos(angular_frequency * seconds))

  from + ((to - from) * progress)
end

.validate_extrapolation!(mode) ⇒ Object

Raises:

  • (ArgumentError)


57
58
59
60
61
# File 'lib/animate_it/timing.rb', line 57

def validate_extrapolation!(mode)
  return if %i[clamp extend identity].include?(mode)

  raise ArgumentError, "Unsupported extrapolation mode: #{mode.inspect}"
end