cubic-bezier-f2dccc53.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*!
  2. * (C) Ionic http://ionicframework.com - MIT License
  3. */
  4. 'use strict';
  5. /**
  6. * Based on:
  7. * https://stackoverflow.com/questions/7348009/y-coordinate-for-a-given-x-cubic-bezier
  8. * https://math.stackexchange.com/questions/26846/is-there-an-explicit-form-for-cubic-b%C3%A9zier-curves
  9. */
  10. /**
  11. * EXPERIMENTAL
  12. * Given a cubic-bezier curve, get the x value (time) given
  13. * the y value (progression).
  14. * Ex: cubic-bezier(0.32, 0.72, 0, 1);
  15. * P0: (0, 0)
  16. * P1: (0.32, 0.72)
  17. * P2: (0, 1)
  18. * P3: (1, 1)
  19. *
  20. * If you give a cubic bezier curve that never reaches the
  21. * provided progression, this function will return an empty array.
  22. */
  23. const getTimeGivenProgression = (p0, p1, p2, p3, progression) => {
  24. return solveCubicBezier(p0[1], p1[1], p2[1], p3[1], progression).map((tValue) => {
  25. return solveCubicParametricEquation(p0[0], p1[0], p2[0], p3[0], tValue);
  26. });
  27. };
  28. /**
  29. * Solve a cubic equation in one dimension (time)
  30. */
  31. const solveCubicParametricEquation = (p0, p1, p2, p3, t) => {
  32. const partA = 3 * p1 * Math.pow(t - 1, 2);
  33. const partB = -3 * p2 * t + 3 * p2 + p3 * t;
  34. const partC = p0 * Math.pow(t - 1, 3);
  35. return t * (partA + t * partB) - partC;
  36. };
  37. /**
  38. * Find the `t` value for a cubic bezier using Cardano's formula
  39. */
  40. const solveCubicBezier = (p0, p1, p2, p3, refPoint) => {
  41. p0 -= refPoint;
  42. p1 -= refPoint;
  43. p2 -= refPoint;
  44. p3 -= refPoint;
  45. const roots = solveCubicEquation(p3 - 3 * p2 + 3 * p1 - p0, 3 * p2 - 6 * p1 + 3 * p0, 3 * p1 - 3 * p0, p0);
  46. return roots.filter((root) => root >= 0 && root <= 1);
  47. };
  48. const solveQuadraticEquation = (a, b, c) => {
  49. const discriminant = b * b - 4 * a * c;
  50. if (discriminant < 0) {
  51. return [];
  52. }
  53. else {
  54. return [(-b + Math.sqrt(discriminant)) / (2 * a), (-b - Math.sqrt(discriminant)) / (2 * a)];
  55. }
  56. };
  57. const solveCubicEquation = (a, b, c, d) => {
  58. if (a === 0) {
  59. return solveQuadraticEquation(b, c, d);
  60. }
  61. b /= a;
  62. c /= a;
  63. d /= a;
  64. const p = (3 * c - b * b) / 3;
  65. const q = (2 * b * b * b - 9 * b * c + 27 * d) / 27;
  66. if (p === 0) {
  67. return [Math.pow(-q, 1 / 3)];
  68. }
  69. else if (q === 0) {
  70. return [Math.sqrt(-p), -Math.sqrt(-p)];
  71. }
  72. const discriminant = Math.pow(q / 2, 2) + Math.pow(p / 3, 3);
  73. if (discriminant === 0) {
  74. return [Math.pow(q / 2, 1 / 2) - b / 3];
  75. }
  76. else if (discriminant > 0) {
  77. return [
  78. Math.pow(-(q / 2) + Math.sqrt(discriminant), 1 / 3) - Math.pow(q / 2 + Math.sqrt(discriminant), 1 / 3) - b / 3,
  79. ];
  80. }
  81. const r = Math.sqrt(Math.pow(-(p / 3), 3));
  82. const phi = Math.acos(-(q / (2 * Math.sqrt(Math.pow(-(p / 3), 3)))));
  83. const s = 2 * Math.pow(r, 1 / 3);
  84. return [
  85. s * Math.cos(phi / 3) - b / 3,
  86. s * Math.cos((phi + 2 * Math.PI) / 3) - b / 3,
  87. s * Math.cos((phi + 4 * Math.PI) / 3) - b / 3,
  88. ];
  89. };
  90. exports.getTimeGivenProgression = getTimeGivenProgression;