README.md

# Easing

Easing function calculations

![Easing functions visualizations created by Andrey Sitnik and Ivan Solovev](assets/images/easings.png "Easing functions visulizations 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](https://sitnik.ru/) and [Ivan Solovev](https://solovev.one/) 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 animation 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

* [Linear](https://en.wikipedia.org/wiki/Linear_function)
* [Sine](https://en.wikipedia.org/wiki/Sine_and_cosine)
* [Quadratic](https://en.wikipedia.org/wiki/Quadratic_function)
* [Cubic](https://en.wikipedia.org/wiki/Cubic_function)
* [Quartic](https://en.wikipedia.org/wiki/Quartic_function)
* [Quintic](https://en.wikipedia.org/wiki/Quintic_function)
* [Exponential](https://en.wikipedia.org/wiki/Exponential_function)
* [Circular](https://en.wikipedia.org/wiki/Trigonometric_functions)
* [Back](https://easings.net/#easeInOutBack)
* [Elastic](https://easings.net/#easeInOutElastic)
* [Bounce](https://easings.net/#easeInOutBounce)

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `ease` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:easing, "~> 0.2.1"}
  ]
end
```

## Usage

### Calculating a single point

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

```elixir
iex> Easing.sine_in(0.4)
0.19098300562505255
```

### Calculating a list of animation frame values

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

```elixir
iex> Easing.to_list(%Easing.AnimationRange{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.AnimationRange{first: 0, last: 0.5, step: 0.1}, {:bounce, :in_out})
[0.0, 0.030000000000000027, 0.11375000000000002, 0.04499999999999993, 0.3487500000000001, 0.5]
```

### Calculating animation frames from a Stream

In many cases you will generate many animation frame values and it may be most performant to calculate those values lazily. We can easily do this with [Elixir Streams](https://elixir-lang.org/getting-started/enumerables-and-streams.html#streams)

```elixir
iex> Easing.stream(%Easing.AnimationRange{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.

```elixir
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.AnimationRange.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.AnimationRange`

`Easing.AnimationRange` 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.AnimationRange` struct with either form:

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

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

There is also a convenience function:

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

You can also calculate the steps from a target frame rate

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

## Authors ##

* [Brian Cardarella](https://twitter.com/bcardarella)

[We are very thankful for the many contributors](https://github.com/dockyard/easing/graphs/contributors)

## Versioning ##

This library follows [Semantic Versioning](https://semver.org)

## Looking for help with your Elixir project? ##

[At DockYard we are ready to help you build your next Elixir project](https://dockyard.com/phoenix-consulting). We have a unique expertise
in Elixir and Phoenix development that is unmatched. [Get in touch!](https://dockyard.com/contact/hire-us)

At DockYard we love Elixir! You can [read our Elixir blog posts](https://dockyard.com/blog/categories/elixir)

## Legal ##

[DockYard](https://dockyard.com/), Inc. © 2022

[@DockYard](https://twitter.com/DockYard)

[Licensed under the MIT license](https://www.opensource.org/licenses/mit-license.php)