Coding soon
Easing
easing js
+
const PI = Math.PI,
c1 = 1.70158,
c2 = c1 * 1.525,
c3 = c1 + 1,
c4 = (2 * PI) / 3,
c5 = (2 * PI) / 4.5;
const create = (tag, ns = "") =>
ns ? document.createElementNS(ns,
tag) : document.createElement(tag);
const attr = (el, attrs) =>
Object.entries(attrs)
.forEach(([k, v]) =>
el.setAttribute(k,
v));
const svg = tag =>
create(tag,
"http://www.w3.org/2000/svg");
const bounce = x => {
const n1 = 7.5625,
d1 = 2.75;
if(x < 1 / d1)
return n1 * x * x;
if(x < 2 / d1)
return n1 * (x -= 1.5 / d1) * x + 0.75;
if(x < 2.5 / d1)
return n1 * (x -= 2.25 / d1) * x + 0.9375;
return n1 * (x -= 2.625 / d1) * x + 0.984375;
};
const easings = {
"linear": x =>
x,
"swing": x =>
0.5 - Math.cos(x * PI) / 2,
"easeInQuad": x =>
x * x,
"easeOutQuad": x =>
1 - (1 - x) * (1 - x),
"easeInOutQuad": x =>
x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2,
2) / 2,
"easeInCubic": x =>
x * x * x,
"easeOutCubic": x =>
1 - Math.pow(1 - x,
3),
"easeInOutCubic": x =>
x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2,
3) / 2,
"easeInQuart": x =>
x * x * x * x,
"easeOutQuart": x =>
1 - Math.pow(1 - x,
4),
"easeInOutQuart": x =>
x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2,
4) / 2,
"easeInQuint": x =>
x * x * x * x * x,
"easeOutQuint": x =>
1 - Math.pow(1 - x,
5),
"easeInOutQuint": x =>
x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2,
5) / 2,
"easeInSine": x =>
1 - Math.cos((x * PI) / 2),
"easeOutSine": x =>
Math.sin((x * PI) / 2),
"easeInOutSine": x =>
-(Math.cos(PI * x) - 1) / 2,
"easeInExpo": x =>
(x === 0 ? 0 : Math.pow(2,
10 * x - 10)),
"easeOutExpo": x =>
(x === 1 ? 1 : 1 - Math.pow(2,
-10 * x)),
"easeInOutExpo": x =>
x === 0
? 0
: x === 1
? 1
: x < 0.5
? Math.pow(2,
20 * x - 10) / 2
: (2 - Math.pow(2,
-20 * x + 10)) / 2,
"easeInCirc": x =>
1 - Math.sqrt(1 - x * x),
"easeOutCirc": x =>
Math.sqrt(1 - Math.pow(x - 1,
2)),
"easeInOutCirc": x =>
x < 0.5
? (1 - Math.sqrt(1 - 4 * x * x)) / 2
: (Math.sqrt(1 - 4 * (x - 1) * (x - 1)) + 1) / 2,
"easeInElastic": x =>
x === 0
? 0
: x === 1
? 1
: -Math.pow(2,
10 * x - 10) * Math.sin((x * 10 - 10.75) * c4),
"easeOutElastic": x =>
x === 0
? 0
: x === 1
? 1
: Math.pow(2,
-10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1,
"easeInOutElastic": x =>
x === 0
? 0
: x === 1
? 1
: x < 0.5
? -(Math.pow(2,
20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2
: (Math.pow(2,
-20 * x + 10) * Math.sin((20 * x - 11.125) * c5))
/ 2
+ 1,
"easeInBack": x =>
c3 * x * x * x - c1 * x * x,
"easeOutBack": x =>
1 + c3 * Math.pow(x - 1,
3) + c1 * Math.pow(x - 1,
2),
"easeInOutBack": x =>
x < 0.5
? (Math.pow(2 * x,
2) * ((c2 + 1) * 2 * x - c2)) / 2
: (Math.pow(2 * x - 2,
2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2,
"easeInBounce": x =>
1 - bounce(1 - x),
"easeOutBounce": bounce,
"easeInOutBounce": x =>
x < 0.5 ? (1 - bounce(1 - 2 * x)) / 2 : (1 + bounce(2 * x - 1)) / 2
};
function createEaseViz(name, ease) {
let minY = Infinity,
maxY = -Infinity;
const points = Array.from({ length: 201 },
(_, i) => {
const x = i / 200;
const y = ease(x);
minY = Math.min(minY,
y);
maxY = Math.max(maxY,
y);
return [x, y];
});
const yRange = maxY - minY;
const normalize = yRange > 1 ? y =>
(y - minY) / yRange : y =>
y;
if(yRange > 1)
points.forEach(p =>
(p[1] = normalize(p[1])));
const el = create("article");
el.classList.add("ease");
attr(el,
{ role: "button" });
const svgEl = svg("svg");
attr(svgEl,
{ viewBox: "-0.1 -0.1 1.2 1.2" });
const background = svg("rect");
attr(background,
{
x: "0",
y: "1",
width: "1",
height: "0",
fill: "var(--back)",
opacity: "0.4"
});
const path = svg("path");
attr(path,
{
"stroke": "var(--col)",
"fill": "none",
"stroke-width": "1",
"vector-effect": "non-scaling-stroke",
"d": points
.map((p, i) =>
`${i ? "L" : "M"} ${p[0]},${1 - p[1]}`)
.join(" ")
});
const dot = svg("circle");
attr(dot,
{ r: "0.03", fill: "var(--col)" });
svgEl.append(background,
path,
dot);
const value = create("output");
value.textContent = "0.000";
const line = create("div");
const lined = create("div");
line.appendChild(lined);
let frame;
const animate = t => {
const x = Math.min(t / 1500,
1);
const y = normalize(ease(x));
attr(dot,
{ cx: x, cy: 1 - y });
attr(background,
{
height: y,
y: 1 - y
});
lined.style.width = y * 100 + "%";
value.textContent = y.toFixed(3)
.padEnd(5,
"0");
if(x < 1)
frame = requestAnimationFrame(() =>
animate(t + 16));
};
const reset = () => {
cancelAnimationFrame(frame);
const y = normalize(ease(0));
attr(dot,
{ cx: 0, cy: 1 - y });
attr(background,
{
height: 0,
y: 1
});
lined.style.width = y * 100 + "%";
value.textContent = y.toFixed(3)
.padEnd(5,
"0");
};
const run = () => {
reset();
animate(0);
};
el.addEventListener("mouseenter",
run);
el.addEventListener("click",
run);
el.addEventListener("mouseleave",
reset);
const title = create("h3");
title.textContent = name;
const graph = create("div");
graph.appendChild(svgEl);
el.append(title,
graph,
value,
line);
reset();
return el;
}
const main = document.querySelector(".easing");
main.append(
...Object.entries(easings)
.map(([n, f]) =>
createEaseViz(n,
f))
);