Skip to content

Instantly share code, notes, and snippets.

@OSUblake
Last active September 7, 2023 03:50
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save OSUblake/4d9f0caf980f4ee492ef to your computer and use it in GitHub Desktop.
Save OSUblake/4d9f0caf980f4ee492ef to your computer and use it in GitHub Desktop.
/*!
* The MIT License (MIT)
*
* Copyright (c) 2016 by Blake Bowen (http://codepen.io/osublake/pen/OyPGEo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
**/
var CubicBezier = (function () {
function CubicBezier(p1x, p1y, p2x, p2y) {
if (p1x === void 0) { p1x = 0; }
if (p1y === void 0) { p1y = 0; }
if (p2x === void 0) { p2x = 1; }
if (p2y === void 0) { p2y = 1; }
this.p1x = p1x;
this.p1y = p1y;
this.p2x = p2x;
this.p2y = p2y;
this.cx = 3.0 * this.p1x;
this.cy = 3.0 * this.p1y;
this.bx = 3.0 * (this.p2x - this.p1x) - this.cx;
this.by = 3.0 * (this.p2y - this.p1y) - this.cy;
this.ax = 1.0 - this.cx - this.bx;
this.ay = 1.0 - this.cy - this.by;
this.ease = this.ease.bind(this);
}
CubicBezier.create = function (name, p1x, p1y, p2x, p2y) {
if (p1x === void 0) { p1x = 0; }
if (p1y === void 0) { p1y = 0; }
if (p2x === void 0) { p2x = 1; }
if (p2y === void 0) { p2y = 1; }
var easing = new CubicBezier(p1x, p1y, p2x, p2y);
if (typeof name === "string")
CubicBezier.easings[name] = easing;
return easing.ease;
};
CubicBezier.config = function (p1x, p1y, p2x, p2y) {
if (p1x === void 0) { p1x = 0; }
if (p1y === void 0) { p1y = 0; }
if (p2x === void 0) { p2x = 1; }
if (p2y === void 0) { p2y = 1; }
return new CubicBezier(p1x, p1y, p2x, p2y).ease;
};
CubicBezier.get = function (name) {
return CubicBezier.easings[name].ease;
};
CubicBezier.prototype.getEpsilon = function (duration) {
if (duration === void 0) { duration = 400; }
return 1 / (200 * duration);
};
CubicBezier.prototype.ease = function (time, start, change, duration) {
return this.solve(time, this.getEpsilon(duration));
};
CubicBezier.prototype.solve = function (x, epsilon) {
return this.sampleCurveY(this.solveCurveX(x, epsilon));
};
CubicBezier.prototype.sampleCurveX = function (t) {
return ((this.ax * t + this.bx) * t + this.cx) * t;
};
CubicBezier.prototype.sampleCurveY = function (t) {
return ((this.ay * t + this.by) * t + this.cy) * t;
};
CubicBezier.prototype.sampleDerivX = function (t) {
return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
};
CubicBezier.prototype.solveCurveX = function (x, epsilon) {
var t0;
var t1;
var t2;
var x2;
var d2;
for (var i = 0, t2 = x; i < 8; i++) {
x2 = this.sampleCurveX(t2) - x;
if (Math.abs(x2) < epsilon)
return t2;
d2 = this.sampleDerivX(t2);
if (Math.abs(d2) < epsilon)
break;
t2 = t2 - x2 / d2;
}
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon)
return t2;
if (x > x2)
t0 = t2;
else
t1 = t2;
t2 = (t1 - t0) * 0.5 + t0;
}
return t2;
};
CubicBezier.easings = {};
return CubicBezier;
})();
/*!
* The MIT License (MIT)
*
* Copyright (c) 2016 by Blake Bowen (http://codepen.io/osublake/pen/OyPGEo)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
**/
interface Dictionary<T> {
[index: string]: T;
}
class CubicBezier {
static easings: Dictionary<CubicBezier> = {};
name: string;
cx: number = 3.0 * this.p1x;
cy: number = 3.0 * this.p1y;
bx: number = 3.0 * (this.p2x - this.p1x) - this.cx;
by: number = 3.0 * (this.p2y - this.p1y) - this.cy;
ax: number = 1.0 - this.cx - this.bx;
ay: number = 1.0 - this.cy - this.by;
constructor(
public p1x: number = 0,
public p1y: number = 0,
public p2x: number = 1,
public p2y: number = 1
) {
this.ease = this.ease.bind(this);
}
static create(name: string, p1x: number = 0, p1y: number = 0, p2x: number = 1, p2y: number = 1): Function {
var easing = new CubicBezier(p1x, p1y, p2x, p2y);
if (typeof name === "string") CubicBezier.easings[name] = easing;
return easing.ease;
}
static config(p1x: number = 0, p1y: number = 0, p2x: number = 1, p2y: number = 1): Function {
return new CubicBezier(p1x, p1y, p2x, p2y).ease;
}
static get(name: string): Function {
return CubicBezier.easings[name].ease;
}
getEpsilon(duration: number = 400): number {
return 1 / (200 * duration);
}
ease(time: number, start: number, change: number, duration: number): number {
return this.solve(time, this.getEpsilon(duration));
}
solve(x: number, epsilon: number): number {
return this.sampleCurveY(this.solveCurveX(x, epsilon));
}
sampleCurveX(t: number): number {
return ((this.ax * t + this.bx) * t + this.cx) * t;
}
sampleCurveY(t: number): number {
return ((this.ay * t + this.by) * t + this.cy) * t;
}
sampleDerivX(t: number): number {
return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
}
solveCurveX(x: number, epsilon: number): number {
var t0: number;
var t1: number;
var t2: number;
var x2: number;
var d2: number;
for (var i = 0, t2 = x; i < 8; i++) {
x2 = this.sampleCurveX(t2) - x;
if (Math.abs (x2) < epsilon) return t2;
d2 = this.sampleDerivX(t2);
if (Math.abs(d2) < epsilon) break;
t2 = t2 - x2 / d2;
}
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0) return t0;
if (t2 > t1) return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon) return t2;
if (x > x2) t0 = t2;
else t1 = t2;
t2 = (t1 - t0) * 0.5 + t0;
}
return t2;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment