/easing

Primary LanguageElixirMIT LicenseMIT

Easing

Easing function calculations

Easing functions visualizations created by Andrey Sitnik and Ivan Solovev

Credits

This library implements all of the easing functions as provided on https://easings.net written by Andrey Sitnik and Ivan Solovev with slight modifications to the mathematical implementations to account for Elixir's immutability.

Description

Calculates the easing value of a given function and progress of an timing represented by a range between 0..1. The following easings are availalbe with in, out, and in_out varients:

Note: If you'd like to see visualizations of the easing calculations visit https://easings.net

Installation

If available in Hex, the package can be installed by adding ease to your list of dependencies in mix.exs:

def deps do
  [
    {:easing, "~> 0.3.1"}
  ]
end

Usage

Calculating a single point

You can calculate a single point for a function along the progress of a timing:

iex> Easing.sine_in(0.4)
0.19098300562505255

Calculating a list of timing frame values

However you likely want to calculate the list of values for a given timing. Easing.to_list/2 will take a Easing.Range struct and the easing as either a function reference or a tuple.

iex> Easing.to_list(%Easing.Range{first: 0, last: 0.5, step: 0.1}, &Easing.bounce_in_out(&1))
[0.0, 0.030000000000000027, 0.11375000000000002, 0.04499999999999993, 0.3487500000000001, 0.5]
iex> Easing.to_list(%Easing.Range{first: 0, last: 0.5, step: 0.1}, {:bounce, :in_out})
[0.0, 0.030000000000000027, 0.11375000000000002, 0.04499999999999993, 0.3487500000000001, 0.5]

Calculating timing frames from a Stream

In many cases you will generate many timing frame values and it may be most performant to calculate those values lazily. We can easily do this with Elixir Streams

iex> Easing.stream(%Easing.Range{first: 0, last: 1, step: 0.0001}, &Easing.sine_in/1) |> Enum.take(3)
[0.0, 1.2337005528273437e-8, 4.9348021557982236e-8]

Easing.stream/2 also take a tuple similar to Easing.to_list/2

Custom easing functions

There is no need for you to limit to the included easing functions. A custom easing function takes a single value and returns the approximation.

iex> custom_easing = fn(progress) ->
  if progress < 0.5 do
    Easing.sine_in(progress) / 2
  else
    1 - Easing.sine_in(progress) / 2
  end
end

iex> Easing.to_list(Easing.Range.new(0, 1, 0.1), custom_easing)
[0.0, 0.006155829702431115, 0.024471741852423234, 0.054496737905816106,
 0.09549150281252627, 0.8535533905932737, 0.7938926261462367,
 0.7269952498697734, 0.6545084971874737, 0.5782172325201156, 0.5]

Easing.Range

Easing.Range is a reimplementation of Elixir's Range struct but will allow for ranges to be built across and between fractional values rather than limited to Integer values. You can create a new Easing.Range struct with either form:

# struct form
iex> %Easing.Range{first: 0.5, last: 1, step: 0.1}
%Easing.Range{first: 0.5, last: 1, step: 0.1}

# function form
iex> Easing.Range(0, 0.5, 0.1)
%Easing.Range{first: 0, last: 0.5, step: 0.1}

There is also a convenience function:

iex> Easing.Range.new(0, 1, 0.1)
%Easing.Range{first: 0, last: 1, step: 0.1}

You can also calculate the steps from a target frame rate

iex> duration_in_ms = 1000
iex> fps = 60
iex> Easing.Range.calculate(duaration_in_ms, fps)
%Easing.Range{first: 0, last: 1, step: 1.6666666666666667e-5}

Authors

We are very thankful for the many contributors

Versioning

This library follows Semantic Versioning

Looking for help with your Elixir project?

At DockYard we are ready to help you build your next Elixir project. We have a unique expertise in Elixir and Phoenix development that is unmatched. Get in touch!

At DockYard we love Elixir! You can read our Elixir blog posts

Legal

DockYard, Inc. © 2022

@DockYard

Licensed under the MIT license