bezier-easing.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. (function(f) {
  2. if (typeof exports === 'object' && typeof module !== 'undefined') {
  3. module.exports = f();
  4. } else if (typeof define === 'function' && define.amd) {
  5. define([], f);
  6. } else {
  7. var g;
  8. if (typeof window !== 'undefined') {
  9. g = window;
  10. } else if (typeof global !== 'undefined') {
  11. g = global;
  12. } else if (typeof self !== 'undefined') {
  13. g = self;
  14. } else {
  15. g = this;
  16. }
  17. g.BezierEasing = f();
  18. }
  19. })(function() {
  20. var define, module, exports;
  21. return (function() {
  22. function r(e, n, t) {
  23. function o(i, f) {
  24. if (!n[i]) {
  25. if (!e[i]) {
  26. var c = 'function' == typeof require && require;
  27. if (!f && c) return c(i, !0);
  28. if (u) return u(i, !0);
  29. var a = new Error("Cannot find module '" + i + "'");
  30. throw ((a.code = 'MODULE_NOT_FOUND'), a);
  31. }
  32. var p = (n[i] = { exports: {} });
  33. e[i][0].call(
  34. p.exports,
  35. function(r) {
  36. var n = e[i][1][r];
  37. return o(n || r);
  38. },
  39. p,
  40. p.exports,
  41. r,
  42. e,
  43. n,
  44. t
  45. );
  46. }
  47. return n[i].exports;
  48. }
  49. for (var u = 'function' == typeof require && require, i = 0; i < t.length; i++) o(t[i]);
  50. return o;
  51. }
  52. return r;
  53. })()(
  54. {
  55. 1: [
  56. function(require, module, exports) {
  57. /**
  58. * https://github.com/gre/bezier-easing
  59. * BezierEasing - use bezier curve for transition easing function
  60. * by Gaëtan Renaudeau 2014 - 2015 – MIT License
  61. */
  62. // These values are established by empiricism with tests (tradeoff: performance VS precision)
  63. var NEWTON_ITERATIONS = 4;
  64. var NEWTON_MIN_SLOPE = 0.001;
  65. var SUBDIVISION_PRECISION = 0.0000001;
  66. var SUBDIVISION_MAX_ITERATIONS = 10;
  67. var kSplineTableSize = 11;
  68. var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
  69. var float32ArraySupported = typeof Float32Array === 'function';
  70. function A(aA1, aA2) {
  71. return 1.0 - 3.0 * aA2 + 3.0 * aA1;
  72. }
  73. function B(aA1, aA2) {
  74. return 3.0 * aA2 - 6.0 * aA1;
  75. }
  76. function C(aA1) {
  77. return 3.0 * aA1;
  78. }
  79. // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
  80. function calcBezier(aT, aA1, aA2) {
  81. return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT;
  82. }
  83. // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
  84. function getSlope(aT, aA1, aA2) {
  85. return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
  86. }
  87. function binarySubdivide(aX, aA, aB, mX1, mX2) {
  88. var currentX,
  89. currentT,
  90. i = 0;
  91. do {
  92. currentT = aA + (aB - aA) / 2.0;
  93. currentX = calcBezier(currentT, mX1, mX2) - aX;
  94. if (currentX > 0.0) {
  95. aB = currentT;
  96. } else {
  97. aA = currentT;
  98. }
  99. } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
  100. return currentT;
  101. }
  102. function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
  103. for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
  104. var currentSlope = getSlope(aGuessT, mX1, mX2);
  105. if (currentSlope === 0.0) {
  106. return aGuessT;
  107. }
  108. var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
  109. aGuessT -= currentX / currentSlope;
  110. }
  111. return aGuessT;
  112. }
  113. function LinearEasing(x) {
  114. return x;
  115. }
  116. module.exports = function bezier(mX1, mY1, mX2, mY2) {
  117. if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) {
  118. throw new Error('bezier x values must be in [0, 1] range');
  119. }
  120. if (mX1 === mY1 && mX2 === mY2) {
  121. return LinearEasing;
  122. }
  123. // Precompute samples table
  124. var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
  125. for (var i = 0; i < kSplineTableSize; ++i) {
  126. sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
  127. }
  128. function getTForX(aX) {
  129. var intervalStart = 0.0;
  130. var currentSample = 1;
  131. var lastSample = kSplineTableSize - 1;
  132. for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
  133. intervalStart += kSampleStepSize;
  134. }
  135. --currentSample;
  136. // Interpolate to provide an initial guess for t
  137. var dist =
  138. (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
  139. var guessForT = intervalStart + dist * kSampleStepSize;
  140. var initialSlope = getSlope(guessForT, mX1, mX2);
  141. if (initialSlope >= NEWTON_MIN_SLOPE) {
  142. return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
  143. } else if (initialSlope === 0.0) {
  144. return guessForT;
  145. } else {
  146. return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
  147. }
  148. }
  149. return function BezierEasing(x) {
  150. // Because JavaScript number are imprecise, we should guarantee the extremes are right.
  151. if (x === 0) {
  152. return 0;
  153. }
  154. if (x === 1) {
  155. return 1;
  156. }
  157. return calcBezier(getTForX(x), mY1, mY2);
  158. };
  159. };
  160. },
  161. {}
  162. ]
  163. },
  164. {},
  165. [1]
  166. )(1);
  167. });