UNPKG

tween24

Version:

Tween24.js is animation library that enables fast coding using method chains.

924 lines (821 loc) 32.9 kB
export class Ease24 { /* * =============================================================================================== * * LINER EASING * * ----------------------------------------------------------------------------------------------- */ /** * Linear easing. * @static * @memberof Ease24 */ static _Linear(t:number, b:number, c:number, d:number): number { return c * t / d + b; } /* * =============================================================================================== * * SINE EASING * * ----------------------------------------------------------------------------------------------- */ /** * Sine easing-in. * @static * @memberof Ease24 */ static _1_SineIn(t:number, b:number, c:number, d:number): number { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; } /** * Sine easing-out. * @static * @memberof Ease24 */ static _1_SineOut(t:number, b:number, c:number, d:number): number { return c * Math.sin(t / d * (Math.PI / 2)) + b; } /** * Sine easing-in-out. * @static * @memberof Ease24 */ static _1_SineInOut(t:number, b:number, c:number, d:number): number { return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; } /** * Sine easing-out-in. * @static * @memberof Ease24 */ static _1_SineOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) return (c / 2) * Math.sin((t * 2) / d * (Math.PI / 2)) + b; return -(c / 2) * Math.cos((t * 2 - d) / d * (Math.PI / 2)) + (c / 2) + (b + c / 2); } /* * =============================================================================================== * * QUAD EASING * * ----------------------------------------------------------------------------------------------- */ /** * Quad easing-in. * @static * @memberof Ease24 */ static _2_QuadIn(t:number, b:number, c:number, d:number): number { return c * (t /= d) * t + b; } /** * Quad easing-out. * @static * @memberof Ease24 */ static _2_QuadOut(t:number, b:number, c:number, d:number): number { return -c * (t /= d) * (t - 2) + b; } /** * Quad easing-in-out. * @static * @memberof Ease24 */ static _2_QuadInOut(t:number, b:number, c:number, d:number): number { if ((t /= d / 2) < 1) return c / 2 * t * t + b; return -c / 2 * ((--t) * (t - 2) - 1) + b; } /** * Quad easing-out-in. * @static * @memberof Ease24 */ static _2_QuadOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) return -(c / 2) * (t = (t * 2 / d)) * (t - 2) + b; return (c / 2) * (t = (t * 2 - d) / d) * t + (b + c / 2); } /* * =============================================================================================== * * CUBIC EASING * * ----------------------------------------------------------------------------------------------- */ /** * Cubic easing-in. * @static * @memberof Ease24 */ static _3_CubicIn(t:number, b:number, c:number, d:number): number { return c * (t /= d) * t * t + b; } /** * Cubic easing-out. * @static * @memberof Ease24 */ static _3_CubicOut(t:number, b:number, c:number, d:number): number { return c * ((t = t / d - 1) * t * t + 1) + b; } /** * Cubic easing-in-out. * @static * @memberof Ease24 */ static _3_CubicInOut(t:number, b:number, c:number, d:number): number { return ((t /= d / 2) < 1) ? c / 2 * t * t * t + b: c / 2 * ((t -= 2) * t * t + 2) + b; } /** * Cubic easing-out-in. * @static * @memberof Ease24 */ static _3_CubicOutIn(t:number, b:number, c:number, d:number): number { return (t < d / 2)? c / 2 * ((t = t * 2 / d - 1) * t * t + 1) + b: c / 2 * (t = (t * 2 - d) / d) * t * t + b + c / 2; } /* * =============================================================================================== * * QUART EASING * * ----------------------------------------------------------------------------------------------- */ /** * Quart easing-in. * @static * @memberof Ease24 */ static _4_QuartIn(t:number, b:number, c:number, d:number): number { return c * (t /= d) * t * t * t + b; } /** * Quart easing-out. * @static * @memberof Ease24 */ static _4_QuartOut(t:number, b:number, c:number, d:number): number { return -c * ((t = t / d - 1) * t * t * t - 1) + b; } /** * Quart easing-in-out. * @static * @memberof Ease24 */ static _4_QuartInOut(t:number, b:number, c:number, d:number): number { if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b; return -c / 2 * ((t -= 2) * t * t * t - 2) + b; } /** * Quart easing-out-in. * @static * @memberof Ease24 */ static _4_QuartOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) return -(c / 2) * ((t = (t * 2) / d - 1) * t * t * t - 1) + b; return (c / 2) * (t = (t * 2 - d) / d) * t * t * t + (b + c / 2); } /* * =============================================================================================== * * QUINT EASING * * ----------------------------------------------------------------------------------------------- */ /** * Quint easing-in. * @static * @memberof Ease24 */ static _5_QuintIn(t:number, b:number, c:number, d:number): number { return c * (t /= d) * t * t * t * t + b; } /** * Quint easing-out. * @static * @memberof Ease24 */ static _5_QuintOut(t:number, b:number, c:number, d:number): number { return c * ((t = t / d - 1) * t * t * t * t + 1) + b; } /** * Quint easing-in-out. * @static * @memberof Ease24 */ static _5_QuintInOut(t:number, b:number, c:number, d:number): number { if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b; return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; } /** * Quint easing-out-in. * @static * @memberof Ease24 */ static _5_QuintOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) return (c / 2) * ((t = (t * 2) / d - 1) * t * t * t * t + 1) + b; return (c / 2) * (t = (t * 2 - d) / d) * t * t * t * t + (b + c / 2); } /* * =============================================================================================== * * EXPO EASING * * ----------------------------------------------------------------------------------------------- */ /** * Expo easing-in. * @static * @memberof Ease24 */ static _6_ExpoIn(t:number, b:number, c:number, d:number): number { return t == 0 ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; } /** * Expo easing-out. * @static * @memberof Ease24 */ static _6_ExpoOut(t:number, b:number, c:number, d:number): number { return t == d ? b + c : c * (1 - Math.pow(2, -10 * t / d)) + b; } /** * Expo easing-in-out. * @static * @memberof Ease24 */ static _6_ExpoInOut(t:number, b:number, c:number, d:number): number { if (t == 0) return b; if (t == d) return b + c; if ((t /= d / 2.0) < 1.0) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; return c / 2 * (2 - Math.pow(2, -10 * --t)) + b; } /** * Expo easing-out-in. * @static * @memberof Ease24 */ static _6_ExpoOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2.0) return t * 2.0 == d ? b + c / 2.0 : c / 2.0 * (1 - Math.pow(2, -10 * t * 2.0 / d)) + b; return ((t * 2.0 - d) == 0)? b + c / 2.0 : c / 2.0 * Math.pow(2, 10 * ((t * 2 - d) / d - 1)) + b + c / 2.0; } /* * =============================================================================================== * * CIRC EASING * * ----------------------------------------------------------------------------------------------- */ /** * Circ easing-in. * @static * @memberof Ease24 */ static _7_CircIn(t:number, b:number, c:number, d:number): number { return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; } /** * Circ easing-out. * @static * @memberof Ease24 */ static _7_CircOut(t:number, b:number, c:number, d:number): number { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; } /** * Circ easing-in-out. * @static * @memberof Ease24 */ static _7_CircInOut(t:number, b:number, c:number, d:number): number { if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; } /** * Circ easing-out-in. * @static * @memberof Ease24 */ static _7_CircOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) return (c / 2) * Math.sqrt(1 - (t = (t * 2) / d - 1) * t) + b; return -(c / 2) * (Math.sqrt(1 - (t = (t * 2 - d) / d) * t) - 1) + (b + c / 2); } /* * =============================================================================================== * * BACK EASING * * ----------------------------------------------------------------------------------------------- */ /** * Back easing-in with overshoot. * @static * @param {number} [overshoot=1.70158] オーバー値(デフォルト値:1.70158) * @memberof Ease24 */ static _BackInWith(overshoot:number = 1.70158): Function { return function (t:number, b:number, c:number, d:number): number { return c * (t /= d) * t * ((overshoot + 1) * t - overshoot) + b; } } /** * Back easing-out with overshoot. * @static * @param {number} [overshoot=1.70158] オーバー値(デフォルト値:1.70158) * @memberof Ease24 */ static _BackOutWith(overshoot:number = 1.70158): Function { return function (t:number, b:number, c:number, d:number): number { return c * ((t = t / d - 1) * t * ((overshoot + 1) * t + overshoot) + 1) + b; } } /** * Back easing-in-out with overshoot. * @static * @param {number} [overshoot=1.70158] オーバー値(デフォルト値:1.70158) * @memberof Ease24 */ static _BackInOutWith(overshoot:number = 1.70158): Function { return function (t:number, b:number, c:number, d:number): number { if ((t /= d / 2) < 1) return c / 2 * (t * t * (((overshoot * 1.525) + 1) * t - overshoot * 1.525)) + b; return c / 2 * ((t -= 2) * t * (((overshoot * 1.525) + 1) * t + overshoot * 1.525) + 2) + b; } } /** * Back easing-out-in with overshoot. * @static * @param {number} [overshoot=1.70158] オーバー値(デフォルト値:1.70158) * @memberof Ease24 */ static _BackOutInWith(overshoot:number = 1.70158): Function { return function (t:number, b:number, c:number, d:number): number { if (t < d / 2) return (c / 2) * ((t = (t * 2) / d - 1) * t * ((overshoot + 1) * t + overshoot) + 1) + b; return (c / 2) * (t = (t * 2 - d) / d) * t * ((overshoot + 1) * t - overshoot) + (b + c / 2); } } /** * Back easing-in. * @static * @memberof Ease24 */ static _BackIn : Function = Ease24._BackInWith(); /** * Back easing-out. * @static * @memberof Ease24 */ static _BackOut : Function = Ease24._BackOutWith(); /** * Back easing-in-out. * @static * @memberof Ease24 */ static _BackInOut: Function = Ease24._BackInOutWith(); /** * Back easing-out-in. * @static * @memberof Ease24 */ static _BackOutIn: Function = Ease24._BackOutInWith(); /* * =============================================================================================== * * BOUNCE EASING * * ----------------------------------------------------------------------------------------------- */ /** * Bounce easing-in. * @static * @memberof Ease24 */ static _BounceIn(t:number, b:number, c:number, d:number): number { if ((t = (d - t) / d) < (1 / 2.75)) return c - (c * (7.5625 * t * t)) + b; if (t < (2 / 2.75)) return c - (c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75)) + b; if (t < (2.5 / 2.75)) return c - (c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375)) + b; return c - (c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375)) + b; } /** * Bounce easing-out. * @static * @memberof Ease24 */ static _BounceOut(t:number, b:number, c:number, d:number): number { if ((t /= d) < (1 / 2.75)) return c * (7.5625 * t * t) + b; if (t < (2 / 2.75)) return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b; if (t < (2.5 / 2.75)) return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b; } /** * Bounce easing-in-out. * @static * @memberof Ease24 */ static _BounceInOut(t:number, b:number, c:number, d:number): number { if (t < d / 2) { if ((t = (d - t * 2) / d) < (1 / 2.75)) return (c - (c * (7.5625 * t * t))) * 0.5 + b; if (t < (2 / 2.75)) return (c - (c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75))) * 0.5 + b; if (t < (2.5 / 2.75)) return (c - (c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375))) * 0.5 + b; return (c - (c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375))) * 0.5 + b; } else { if ((t = (t * 2 - d) / d) < (1 / 2.75)) return (c * (7.5625 * t * t)) * 0.5 + c * 0.5 + b; if (t < (2 / 2.75)) return (c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75)) * 0.5 + c * 0.5 + b; if (t < (2.5 / 2.75)) return (c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375)) * 0.5 + c * 0.5 + b; return (c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375)) * 0.5 + c * 0.5 + b; } } /** * Bounce easing-out-in. * @static * @memberof Ease24 */ static _BounceOutIn(t:number, b:number, c:number, d:number): number { if (t < d / 2) { if ((t = (t * 2) / d) < (1 / 2.75)) return (c / 2) * (7.5625 * t * t) + b; if (t < (2 / 2.75)) return (c / 2) * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b; if (t < (2.5 / 2.75)) return (c / 2) * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; return (c / 2) * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b; } else { if ((t = (d - (t * 2 - d)) / d) < (1 / 2.75)) return (c / 2) - ((c / 2) * (7.5625 * t * t)) + (b + c / 2); if (t < (2 / 2.75)) return (c / 2) - ((c / 2) * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75)) + (b + c / 2); if (t < (2.5 / 2.75)) return (c / 2) - ((c / 2) * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375)) + (b + c / 2); return (c / 2) - ((c / 2) * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375)) + (b + c / 2); } } /* * =============================================================================================== * * ELASTIC EASING * * ----------------------------------------------------------------------------------------------- */ /** * Elastic easing-in with amplitude & period. * @static * @param {number} amplitude 振幅の大きさ(デフォルト値:0) * @param {number} period 振幅の周期(デフォルト値:0) * @memberof Ease24 */ static _ElasticInWith(amplitude:number = 0, period:number = 0): Function { return function (t:number, b:number, c:number, d:number): number { t /= 1000; d /= 1000; if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!period) period = d * 0.3; var s; if (!amplitude || amplitude < Math.abs(c)) { amplitude = c; s = period / 4; } else s = period / (2 * Math.PI) * Math.asin(c / amplitude); return -(amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / period)) + b; } } /** * Elastic easing-out with amplitude & period. * @static * @param {number} amplitude 振幅の大きさ(デフォルト値:0) * @param {number} period 振幅の周期(デフォルト値:0) * @memberof Ease24 */ static _ElasticOutWith(amplitude:number = 0, period:number = 0): Function { return function (t:number, b:number, c:number, d:number): number { t /= 1000; d /= 1000; if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!period) period = d * 0.3; var s; if (!amplitude || amplitude < Math.abs(c)) { amplitude = c; s = period / 4; } else s = period / (2 * Math.PI) * Math.asin(c / amplitude); return amplitude * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / period) + c + b; } } /** * Elastic easing-in-out with amplitude & period. * @static * @param {number} amplitude 振幅の大きさ(デフォルト値:0) * @param {number} period 振幅の周期(デフォルト値:0) * @memberof Ease24 */ static _ElasticInOutWith(amplitude:number = 0, period:number = 0): Function { return function (t:number, b:number, c:number, d:number): number { t /= 1000; d /= 1000; if (t == 0) return b; if ((t /= d / 2) == 2) return b + c; if (!period) period = d * (0.3 * 1.5); var s; if (!amplitude || amplitude < Math.abs(c)) { amplitude = c; s = period / 4; } else s = period / (2 * Math.PI) * Math.asin(c / amplitude); if (t < 1) return -0.5 * (amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / period)) + b; return amplitude * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / period) * 0.5 + c + b; } } /** * Elastic easing-out-in with amplitude & period. * @static * @param {number} amplitude 振幅の大きさ(デフォルト値:0) * @param {number} period 振幅の周期(デフォルト値:0) * @memberof Ease24 */ static _ElasticOutInWith(amplitude:number = 0, period:number = 0): Function { return function (t:number, b:number, c:number, d:number): number { t /= 1000; d /= 1000; var s; c /= 2; if (t < d / 2) { if ((t *= 2) == 0) return b; if ((t /= d) == 1) return b + c; if (!period) period = d * 0.3; if (!amplitude || amplitude < Math.abs(c)) { amplitude = c; s = period / 4; } else s = period / (2 * Math.PI) * Math.asin(c / amplitude); return amplitude * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / period) + c + b; } else { if ((t = t * 2 - d) == 0) return (b + c); if ((t /= d) == 1) return (b + c) + c; if (!period) period = d * 0.3; if (!amplitude || amplitude < Math.abs(c)) { amplitude = c; s = period / 4; } else s = period / (2 * Math.PI) * Math.asin(c / amplitude); return -(amplitude * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / period)) + (b + c); } } } /** * Elastic easing-in. * @static * @memberof Ease24 */ static _ElasticIn : Function = Ease24._ElasticInWith(); /** * Elastic easing-out. * @static * @memberof Ease24 */ static _ElasticOut : Function = Ease24._ElasticOutWith(); /** * Elastic easing-in-out. * @static * @memberof Ease24 */ static _ElasticInOut: Function = Ease24._ElasticInOutWith(); /** * Elastic easing-out-in. * @static * @memberof Ease24 */ static _ElasticOutIn: Function = Ease24._ElasticOutInWith(); /* * =============================================================================================== * * BLEND EASING * * ----------------------------------------------------------------------------------------------- */ /** * 2つのイージングをミックスして、新しいイージングを生成します。 * ※この関数は blend() に移行しました。将来的に削除される可能性があります。 * @static * @param {Function} easeA 元になるイージング * @param {Function} easeB 混合されるイージング * @param {Function} mixing 混合率を指定するイージング * @param {number} start 開始時の混合率 * @param {number} end 終点時の混合率 * @memberof Ease24 */ static _Blend(easeA:Function, easeB:Function, mixing:Function, start:number = 0, end:number = 1): Function { return function (t:number, b:number, c:number, d:number): number { let v1 = easeA (t, b, c, d); let v2 = easeB (t, b, c, d); let v3 = mixing(t, b, c, d); let rate = end - start; return v1 + (v2 - v1) * (v3 * rate + start); } } /** * 2つのイージングをミックスして、新しいイージングを生成します。 * @static * @param {Function} easeA 元になるイージング * @param {Function} easeB 混合されるイージング * @param {Function} mixing 混合率を指定するイージング * @param {number} start 開始時の混合率 * @param {number} end 終点時の混合率 * @memberof Ease24 */ static blend(easeA:Function, easeB:Function, mixing:Function, start:number = 0, end:number = 1): Function { return function (t:number, b:number, c:number, d:number): number { let v1 = easeA (t, b, c, d); let v2 = easeB (t, b, c, d); let v3 = mixing(t, b, c, d); let rate = end - start; return v1 + (v2 - v1) * (v3 * rate + start); } } /* * =============================================================================================== * * CUSTOM EASING * * ----------------------------------------------------------------------------------------------- */ private static _customEasingById: Map<string, Function>; private static _set = (id:string, easing:Function) => { Ease24._customEasingById ||= new Map<string, Function>(); Ease24._customEasingById.set(id, easing); } /** * 登録したカスタムイージングを取得します。 * @static * @param {string} id カスタムイージングのID * @memberof Ease24 */ static get = (id:string): Function|undefined => { return Ease24._customEasingById?.get(id); } /** * 登録したカスタムイージングをクリアします。 * @static * @param {string} id カスタムイージングのID * @memberof Ease24 */ static clear = (id:string) => { Ease24._customEasingById?.delete(id); } /** * カスタムイージングを作成します。 * 作成時にIDを指定すると、get()関数でイージングを呼び出せるようになります。 * 指定するパラメータのフォーマットは GreenSockの Ease Visualizer に準じています。 * Ease Visualizer: https://greensock.com/ease-visualizer/ * @static * @param {(string|null)} id 登録するカスタムイージングのID。登録しない場合は null を指定します * @param {string} svgPathData カスタムイージングのSVGパスデータ * @memberof Ease24 */ static create = (id:string|null, svgPathData:string): Function => { svgPathData = "0,0," + svgPathData.trim() + ",1,1"; const pathList = svgPathData.replace(/[CM]/g, "").replace(/ /g, ",").split(","); let points = []; if (pathList.length % 3 != 0) { console.log(`Tween24 Warning: Incorrect parameter format for custom easing.`); return Ease24._Linear; } for (let i = 0; i < pathList.length; i += 6) { points.push({ pre :[pathList[i ], pathList[i + 1]], point:[pathList[i + 2], pathList[i + 3]], post :[pathList[i + 4], pathList[i + 5]] }); } const easing = Ease24._custom(points); if (id) Ease24._set(id, easing); return easing; } private static _custom = (points:any[]): Function => { return (t:number, b:number, c:number, d:number):number => { for (let i = 0; i < points.length - 1; i++) { if (t / d >= points[i].point[0] && t / d <= points[i + 1].point[0]) { return c * Ease24._getYForX(t / d, new Point(points[i ].point[0], points[i ].point[1]), new Point(points[i ].post [0], points[i ].post[1] ), new Point(points[i + 1].pre [0], points[i + 1].pre[1] ), new Point(points[i + 1].point[0], points[i + 1].point[1])) + b; } } return NaN; }; } /* * =============================================================================================== * * Ported from fl.motion.BezierSegment.as * Copyright © 2007. Adobe Systems Incorporated. All Rights Reserved. * * ----------------------------------------------------------------------------------------------- */ private static _getYForX = (x:number, a:Point, b:Point, c:Point, d:Point): number => { if (a.x < d.x) { if (x <= a.x + 0.0000000000000001) return a.y; if (x >= d.x - 0.0000000000000001) return d.y; } else { if (x >= a.x + 0.0000000000000001) return a.y; if (x <= d.x - 0.0000000000000001) return d.y; } let coefficients = Ease24._getCubicCoefficients(a.x, b.x, c.x, d.x); // x(t) = a*t^3 + b*t^2 + c*t + d let roots = Ease24._getCubicRoots(coefficients[0], coefficients[1], coefficients[2], coefficients[3] - x); let time:number = NaN; if (roots.length == 0) time = 0; else if (roots.length == 1) time = roots[0]; else { for (const root of roots) { if (0 <= root && root <= 1) { time = root; break; } } } if (isNaN(time)) return NaN; let y = Ease24._getSingleValue(time, a.y, b.y, c.y, d.y); return y; } /** * @param a The first value of the Bezier equation. * @param b The second value of the Bezier equation. * @param c The third value of the Bezier equation. * @param d The fourth value of the Bezier equation. * @return An array containing four number values, */ private static _getCubicCoefficients = (a:number, b:number, c:number, d:number): number[] => { return [ -a + 3 * b - 3 * c + d, 3 * a - 6 * b + 3 * c, -3 * a + 3 * b, a]; } /** * @param a The first coefficient of the cubic equation, which is multiplied by the cubed variable (t^3). * @param b The second coefficient of the cubic equation, which is multiplied by the squared variable (t^2). * @param c The third coefficient of the cubic equation, which is multiplied by the linear variable (t). * @param d The fourth coefficient of the cubic equation, which is the constant. * @return An array of number values, indicating the real roots of the equation. */ private static _getCubicRoots = (a:number = 0, b:number = 0, c:number = 0, d:number = 0): number[] => { if (!a) return Ease24._getQuadraticRoots(b, c, d); if (a != 1) { b /= a; c /= a; d /= a; } let q = (b * b - 3 * c) / 9; let qCubed = q * q * q; let r = (2 * b * b * b - 9 * b * c + 27 * d) / 54; let diff = qCubed - r * r; if (diff >= 0) { if (!q) return [0]; let theta = Math.acos(r / Math.sqrt(qCubed)); let qSqrt = Math.sqrt(q); let root1 = -2 * qSqrt * Math.cos(theta / 3) - b / 3; let root2 = -2 * qSqrt * Math.cos((theta + 2 * Math.PI) / 3) - b / 3; let root3 = -2 * qSqrt * Math.cos((theta + 4 * Math.PI) / 3) - b / 3; return [root1, root2, root3]; } else { let tmp = Math.pow( Math.sqrt(-diff) + Math.abs(r), 1/3); let rSign = (r > 0) ? 1 : r < 0 ? -1 : 0; let root = -rSign * (tmp + q / tmp) - b / 3; return [root]; } } /** * @param a The first value of the Bezier equation. * @param b The second value of the Bezier equation. * @param c The third value of the Bezier equation. * @param d The fourth value of the Bezier equation. * @return The value of the Bezier equation at the specified time. */ private static _getSingleValue = (t:number, a:number = 0, b:number = 0, c:number = 0, d:number=0): number => { return (t * t * (d - a) + 3 * (1 - t) * (t * (c - a) + (1 - t) * (b - a))) * t + a; } /** * @param a The first coefficient of the quadratic equation, which is multiplied by the squared variable (t^2). * @param b The second coefficient of the quadratic equation, which is multiplied by the linear variable (t). * @param c The third coefficient of the quadratic equation, which is the constant. * @return An array of number values, indicating the real roots of the equation. */ private static _getQuadraticRoots(a:number, b:number, c:number): number[] { var roots = []; if (!a) { if (!b) return []; roots[0] = -c / b; return roots; } var q = b*b - 4*a*c; var signQ = (q > 0)? 1: q < 0 ? -1: 0; if (signQ < 0) return []; else if (!signQ) roots[0] = -b / (2 * a); else { roots[0] = roots[1] = -b / (2 * a); let tmp = Math.sqrt(q) / (2 * a); roots[0] -= tmp; roots[1] += tmp; } return roots; } } class Point { private _x:number; private _y:number; constructor(x:number = 0, y:number = 0) { this._x = Number(x); this._y = Number(y); } get x():number { return this._x; } get y():number { return this._y; } }