easing.ts

  1. import { EasingFunction } from "./types";
  2. function cubic(y1: number, y2: number, t: number) {
  3. const t2 = 1 - t;
  4. // Bezier Curve Formula
  5. return t * t * t + 3 * t * t * t2 * y2 + 3 * t * t2 * t2 * y1;
  6. }
  7. function solveFromX(x1: number, x2: number, x: number) {
  8. // x 0 ~ 1
  9. // t 0 ~ 1
  10. let t = x;
  11. let solveX = x;
  12. let dx = 1;
  13. while (Math.abs(dx) > 1 / 1000) {
  14. // 예상 t초에 의한 _x값
  15. solveX = cubic(x1, x2, t);
  16. dx = solveX - x;
  17. // 차이가 미세하면 그 값을 t로 지정
  18. if (Math.abs(dx) < 1 / 1000) {
  19. return t;
  20. }
  21. t -= dx / 2;
  22. }
  23. return t;
  24. }
  25. /**
  26. * @namespace easing
  27. */
  28. /**
  29. * Cubic Bezier curve.
  30. * @memberof easing
  31. * @func bezier
  32. * @param {number} [x1] - point1's x
  33. * @param {number} [y1] - point1's y
  34. * @param {number} [x2] - point2's x
  35. * @param {number} [y2] - point2's y
  36. * @return {function} the curve function
  37. * @example
  38. import {bezier} from "scenejs";
  39. Scene.bezier(0, 0, 1, 1) // LINEAR
  40. Scene.bezier(0.25, 0.1, 0.25, 1) // EASE
  41. */
  42. export function bezier(x1: number, y1: number, x2: number, y2: number) {
  43. /*
  44. x = f(t)
  45. calculate inverse function by x
  46. t = f-1(x)
  47. */
  48. const func: EasingFunction = (x: number) => {
  49. const t = solveFromX(x1, x2, Math.max(Math.min(1, x), 0));
  50. return cubic(y1, y2, t);
  51. };
  52. func.easingName = `cubic-bezier(${x1},${y1},${x2},${y2})`;
  53. return func;
  54. }
  55. /**
  56. * Specifies a stepping function
  57. * @see {@link https://www.w3schools.com/cssref/css3_pr_animation-timing-function.asp|CSS3 Timing Function}
  58. * @memberof easing
  59. * @func steps
  60. * @param {number} count - point1's x
  61. * @param {"start" | "end"} postion - point1's y
  62. * @return {function} the curve function
  63. * @example
  64. import {steps} from "scenejs";
  65. Scene.steps(1, "start") // Scene.STEP_START
  66. Scene.steps(1, "end") // Scene.STEP_END
  67. */
  68. export function steps(count: number, position: "start" | "end") {
  69. const func: EasingFunction = (time: number) => {
  70. const level = 1 / count;
  71. if (time >= 1) {
  72. return 1;
  73. }
  74. return (position === "start" ? level : 0) + Math.floor(time / level) * level;
  75. };
  76. func.easingName = `steps(${count}, ${position})`;
  77. return func;
  78. }
  79. /**
  80. * Equivalent to steps(1, start)
  81. * @memberof easing
  82. * @name STEP_START
  83. * @static
  84. * @type {function}
  85. * @example
  86. import {STEP_START} from "scenejs";
  87. Scene.STEP_START // steps(1, start)
  88. */
  89. export const STEP_START = /*#__PURE__#*/steps(1, "start");
  90. /**
  91. * Equivalent to steps(1, end)
  92. * @memberof easing
  93. * @name STEP_END
  94. * @static
  95. * @type {function}
  96. * @example
  97. import {STEP_END} from "scenejs";
  98. Scene.STEP_END // steps(1, end)
  99. */
  100. export const STEP_END = /*#__PURE__#*/steps(1, "end");
  101. /**
  102. * Linear Speed (0, 0, 1, 1)
  103. * @memberof easing
  104. * @name LINEAR
  105. * @static
  106. * @type {function}
  107. * @example
  108. import {LINEAR} from "scenejs";
  109. Scene.LINEAR
  110. */
  111. export const LINEAR = /*#__PURE__#*/bezier(0, 0, 1, 1);
  112. /**
  113. * Ease Speed (0.25, 0.1, 0.25, 1)
  114. * @memberof easing
  115. * @name EASE
  116. * @static
  117. * @type {function}
  118. * @example
  119. import {EASE} from "scenejs";
  120. Scene.EASE
  121. */
  122. export const EASE = /*#__PURE__#*/bezier(0.25, 0.1, 0.25, 1);
  123. /**
  124. * Ease In Speed (0.42, 0, 1, 1)
  125. * @memberof easing
  126. * @name EASE_IN
  127. * @static
  128. * @type {function}
  129. * @example
  130. import {EASE_IN} from "scenejs";
  131. Scene.EASE_IN
  132. */
  133. export const EASE_IN = /*#__PURE__#*/bezier(0.42, 0, 1, 1);
  134. /**
  135. * Ease Out Speed (0, 0, 0.58, 1)
  136. * @memberof easing
  137. * @name EASE_OUT
  138. * @static
  139. * @type {function}
  140. * @example
  141. import {EASE_OUT} from "scenejs";
  142. Scene.EASE_OUT
  143. */
  144. export const EASE_OUT = /*#__PURE__#*/bezier(0, 0, 0.58, 1);
  145. /**
  146. * Ease In Out Speed (0.42, 0, 0.58, 1)
  147. * @memberof easing
  148. * @name EASE_IN_OUT
  149. * @static
  150. * @type {function}
  151. * @example
  152. import {EASE_IN_OUT} from "scenejs";
  153. Scene.EASE_IN_OUT
  154. */
  155. export const EASE_IN_OUT = /*#__PURE__#*/bezier(0.42, 0, 0.58, 1);