Move easing functions to separate file and add typing.

This commit is contained in:
Rodrigo Girão Serrão
2021-09-04 15:20:41 +01:00
parent 71f9749a11
commit e778d48d10
2 changed files with 133 additions and 128 deletions

View File

@@ -2,13 +2,13 @@ from __future__ import annotations
import asyncio
import sys
from math import pi, cos, sin, sqrt
from time import time
from tracemalloc import start
from typing import Callable, TypeVar
from dataclasses import dataclass
from ._easing import DEFAULT_EASING, EASING
from ._timer import Timer
from ._types import MessageTarget
@@ -28,133 +28,6 @@ class Animatable(Protocol):
...
def _in_out_expo(x):
"""https://easings.net/#easeInOutExpo"""
if 0 < x < 0.5:
return pow(2, 20 * x - 10) / 2
elif 0.5 <= x < 1:
return (2 - pow(2, -20 * x + 10)) / 2
else:
return x # x in (0, 1)
def _in_out_circ(x):
"""https://easings.net/#easeInOutCirc"""
if x < 0.5:
return (1 - sqrt(1 - pow(2 * x, 2))) / 2
else:
return (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2
def _in_out_back(x):
"""https://easings.net/#easeInOutBack"""
c = 1.70158 * 1.525
if x < 0.5:
return (pow(2 * x, 2) * ((c + 1) * 2 * x - c)) / 2
else:
return (pow(2 * x - 2, 2) * ((c + 1) * (x * 2 - 2) + c) + 2) / 2
def _in_elastic(x):
"""https://easings.net/#easeInElastic"""
c = 2 * pi / 3;
if 0 < x < 1:
return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c)
else:
return x # x in (0, 1)
def _in_out_elastic(x):
"""https://easings.net/#easeInOutElastic"""
c = 2 * pi / 4.5
if 0 < x < 0.5:
return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c)) / 2
elif 0.5 <= x < 1:
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c)) / 2 + 1
else:
return x # x in (0, 1)
def _out_elastic(x):
"""https://easings.net/#easeInOutElastic"""
c = 2 * pi / 4.5
if 0 < x < 0.5:
return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c)) / 2
elif 0.5 <= x < 1:
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c)) / 2 + 1
else:
return x # x in (0, 1)
def _out_bounce(x):
"""https://easings.net/#easeOutBounce"""
n, d = 7.5625, 2.75
if x < 1/d:
return n * x * x
elif x < 2/d:
x_ = x - 1.5/d
return n * x_ * x_ + 0.75
elif x < 2.5/d:
x_ = x - 2.25/d
return n * x_ * x_ + 0.9375
else:
x_ = x - 2.625/d
return n * x_ * x_ + 0.984375
def _in_bounce(x):
"""https://easings.net/#easeInBounce"""
return 1 - _out_bounce(x)
def _in_out_bounce(x):
"""https://easings.net/#easeInOutBounce"""
if x < 0.5:
return (1 - _out_bounce(1 - 2 * x)) / 2
else:
return (1 + _out_bounce(2 * x - 1)) / 2
# https://easings.net/
EASING = {
"none": lambda x: 1.0,
"round": lambda x: 0.0 if x < 0.5 else 1.0,
"linear": lambda x: x,
"in_sine": lambda x: 1 - cos((x * pi) / 2),
"in_out_sine": lambda x: -(cos(x * pi) - 1) / 2,
"out_sine": lambda x: sin((x * pi) / 2),
"in_quad": lambda x: x * x,
"in_out_quad": lambda x: 2 * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 2) / 2,
"out_quad": lambda x: 1 - pow(1 - x, 2),
"in_cubic": lambda x: x * x * x,
"in_out_cubic": lambda x: 4 * x * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 3) / 2,
"out_cubic": lambda x: 1 - pow(1 - x, 3),
"in_quart": lambda x: pow(x, 4),
"in_out_quart": lambda x: 8 * pow(x, 4) if x < 0.5 else 1 - pow(-2 * x + 2, 4) / 2,
"out_quart": lambda x: 1 - pow(1 - x, 4),
"in_quint": lambda x: pow(x, 5),
"in_out_quint": lambda x: 16 * pow(x, 5) if x < 0.5 else 1 - pow(-2 * x + 2, 5) / 2,
"out_quint": lambda x: 1 - pow(1 - x, 5),
"in_expo": lambda x: pow(2, 10 * x - 10) if x else 0,
"in_out_expo": _in_out_expo,
"out_expo": lambda x: 1 - pow(2, -10 * x) if x != 1 else 1,
"in_circ": lambda x: 1 - sqrt(1 - pow(x, 2)),
"in_out_circ": _in_out_circ,
"out_circ": lambda x: sqrt(1 - pow(x - 1, 2)),
"in_back": lambda x: 2.70158 * pow(x, 3) - 1.70158 * pow(x, 2),
"in_out_back": _in_out_back,
"out_back": lambda x: 1 + 2.70158 * pow(x - 1, 3) + 1.70158 * pow(x - 1, 2),
"in_elastic": _in_elastic,
"in_out_elastic": _in_out_elastic,
"out_elastic": _out_elastic,
"in_bounce": _in_bounce,
"in_out_bounce": _in_out_bounce,
"out_bounce": _out_bounce,
}
DEFAULT_EASING = "in_out_cubic"
@dataclass
class Animation:
obj: object

132
src/textual/_easing.py Normal file
View File

@@ -0,0 +1,132 @@
"""
Define a series of easing functions for more natural-looking animations.
Taken from https://easings.net/ and translated from JavaScript.
"""
from math import pi, cos, sin, sqrt
def _in_out_expo(x: float) -> float:
"""https://easings.net/#easeInOutExpo"""
if 0 < x < 0.5:
return pow(2, 20 * x - 10) / 2
elif 0.5 <= x < 1:
return (2 - pow(2, -20 * x + 10)) / 2
else:
return x # x in (0, 1)
def _in_out_circ(x: float) -> float:
"""https://easings.net/#easeInOutCirc"""
if x < 0.5:
return (1 - sqrt(1 - pow(2 * x, 2))) / 2
else:
return (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2
def _in_out_back(x: float) -> float:
"""https://easings.net/#easeInOutBack"""
c = 1.70158 * 1.525
if x < 0.5:
return (pow(2 * x, 2) * ((c + 1) * 2 * x - c)) / 2
else:
return (pow(2 * x - 2, 2) * ((c + 1) * (x * 2 - 2) + c) + 2) / 2
def _in_elastic(x: float) -> float:
"""https://easings.net/#easeInElastic"""
c = 2 * pi / 3
if 0 < x < 1:
return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c)
else:
return x # x in (0, 1)
def _in_out_elastic(x: float) -> float:
"""https://easings.net/#easeInOutElastic"""
c = 2 * pi / 4.5
if 0 < x < 0.5:
return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c)) / 2
elif 0.5 <= x < 1:
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c)) / 2 + 1
else:
return x # x in (0, 1)
def _out_elastic(x: float) -> float:
"""https://easings.net/#easeInOutElastic"""
c = 2 * pi / 4.5
if 0 < x < 0.5:
return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c)) / 2
elif 0.5 <= x < 1:
return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c)) / 2 + 1
else:
return x # x in (0, 1)
def _out_bounce(x: float) -> float:
"""https://easings.net/#easeOutBounce"""
n, d = 7.5625, 2.75
if x < 1 / d:
return n * x * x
elif x < 2 / d:
x_ = x - 1.5 / d
return n * x_ * x_ + 0.75
elif x < 2.5 / d:
x_ = x - 2.25 / d
return n * x_ * x_ + 0.9375
else:
x_ = x - 2.625 / d
return n * x_ * x_ + 0.984375
def _in_bounce(x: float) -> float:
"""https://easings.net/#easeInBounce"""
return 1 - _out_bounce(x)
def _in_out_bounce(x: float) -> float:
"""https://easings.net/#easeInOutBounce"""
if x < 0.5:
return (1 - _out_bounce(1 - 2 * x)) / 2
else:
return (1 + _out_bounce(2 * x - 1)) / 2
EASING = {
"none": lambda x: 1.0,
"round": lambda x: 0.0 if x < 0.5 else 1.0,
"linear": lambda x: x,
"in_sine": lambda x: 1 - cos((x * pi) / 2),
"in_out_sine": lambda x: -(cos(x * pi) - 1) / 2,
"out_sine": lambda x: sin((x * pi) / 2),
"in_quad": lambda x: x * x,
"in_out_quad": lambda x: 2 * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 2) / 2,
"out_quad": lambda x: 1 - pow(1 - x, 2),
"in_cubic": lambda x: x * x * x,
"in_out_cubic": lambda x: 4 * x * x * x if x < 0.5 else 1 - pow(-2 * x + 2, 3) / 2,
"out_cubic": lambda x: 1 - pow(1 - x, 3),
"in_quart": lambda x: pow(x, 4),
"in_out_quart": lambda x: 8 * pow(x, 4) if x < 0.5 else 1 - pow(-2 * x + 2, 4) / 2,
"out_quart": lambda x: 1 - pow(1 - x, 4),
"in_quint": lambda x: pow(x, 5),
"in_out_quint": lambda x: 16 * pow(x, 5) if x < 0.5 else 1 - pow(-2 * x + 2, 5) / 2,
"out_quint": lambda x: 1 - pow(1 - x, 5),
"in_expo": lambda x: pow(2, 10 * x - 10) if x else 0,
"in_out_expo": _in_out_expo,
"out_expo": lambda x: 1 - pow(2, -10 * x) if x != 1 else 1,
"in_circ": lambda x: 1 - sqrt(1 - pow(x, 2)),
"in_out_circ": _in_out_circ,
"out_circ": lambda x: sqrt(1 - pow(x - 1, 2)),
"in_back": lambda x: 2.70158 * pow(x, 3) - 1.70158 * pow(x, 2),
"in_out_back": _in_out_back,
"out_back": lambda x: 1 + 2.70158 * pow(x - 1, 3) + 1.70158 * pow(x - 1, 2),
"in_elastic": _in_elastic,
"in_out_elastic": _in_out_elastic,
"out_elastic": _out_elastic,
"in_bounce": _in_bounce,
"in_out_bounce": _in_out_bounce,
"out_bounce": _out_bounce,
}
DEFAULT_EASING = "in_out_cubic"