50 lines
1.3 KiB
Elixir
50 lines
1.3 KiB
Elixir
|
defmodule DancingDots.Animation do
|
||
|
@type dot :: DancingDots.Dot.t()
|
||
|
@type opts :: keyword
|
||
|
@type error :: any
|
||
|
@type frame_number :: pos_integer
|
||
|
|
||
|
@callback init(opts) :: {:ok, opts} | {:error, error}
|
||
|
@callback handle_frame(dot, frame_number, opts) :: dot
|
||
|
|
||
|
defmacro __using__(_) do
|
||
|
quote do
|
||
|
@behaviour DancingDots.Animation
|
||
|
def init(opts), do: {:ok, opts}
|
||
|
defoverridable init: 1
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
defmodule DancingDots.Flicker do
|
||
|
use DancingDots.Animation
|
||
|
|
||
|
@impl DancingDots.Animation
|
||
|
def handle_frame(%DancingDots.Dot{opacity: opacity} = dot, frame_number, _opts)
|
||
|
when rem(frame_number, 4) == 0,
|
||
|
do: %{dot | opacity: opacity / 2}
|
||
|
|
||
|
@impl DancingDots.Animation
|
||
|
def handle_frame(dot, _frame_number, _opts), do: dot
|
||
|
end
|
||
|
|
||
|
defmodule DancingDots.Zoom do
|
||
|
use DancingDots.Animation
|
||
|
|
||
|
@impl DancingDots.Animation
|
||
|
def init(opts) do
|
||
|
case Keyword.get(opts, :velocity) do
|
||
|
velocity when is_number(velocity) ->
|
||
|
{:ok, opts}
|
||
|
|
||
|
velocity ->
|
||
|
{:error,
|
||
|
"The :velocity option is required, and its value must be a number. Got: #{inspect(velocity)}"}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
@impl DancingDots.Animation
|
||
|
def handle_frame(%DancingDots.Dot{radius: radius} = dot, frame_number, opts),
|
||
|
do: %{dot | radius: radius + (frame_number - 1) * Keyword.get(opts, :velocity)}
|
||
|
end
|