delta-apply.mjs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { mixNumber } from '../../utils/mix/number.mjs';
  2. import { hasTransform } from '../utils/has-transform.mjs';
  3. /**
  4. * Scales a point based on a factor and an originPoint
  5. */
  6. function scalePoint(point, scale, originPoint) {
  7. const distanceFromOrigin = point - originPoint;
  8. const scaled = scale * distanceFromOrigin;
  9. return originPoint + scaled;
  10. }
  11. /**
  12. * Applies a translate/scale delta to a point
  13. */
  14. function applyPointDelta(point, translate, scale, originPoint, boxScale) {
  15. if (boxScale !== undefined) {
  16. point = scalePoint(point, boxScale, originPoint);
  17. }
  18. return scalePoint(point, scale, originPoint) + translate;
  19. }
  20. /**
  21. * Applies a translate/scale delta to an axis
  22. */
  23. function applyAxisDelta(axis, translate = 0, scale = 1, originPoint, boxScale) {
  24. axis.min = applyPointDelta(axis.min, translate, scale, originPoint, boxScale);
  25. axis.max = applyPointDelta(axis.max, translate, scale, originPoint, boxScale);
  26. }
  27. /**
  28. * Applies a translate/scale delta to a box
  29. */
  30. function applyBoxDelta(box, { x, y }) {
  31. applyAxisDelta(box.x, x.translate, x.scale, x.originPoint);
  32. applyAxisDelta(box.y, y.translate, y.scale, y.originPoint);
  33. }
  34. const TREE_SCALE_SNAP_MIN = 0.999999999999;
  35. const TREE_SCALE_SNAP_MAX = 1.0000000000001;
  36. /**
  37. * Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms
  38. * in a tree upon our box before then calculating how to project it into our desired viewport-relative box
  39. *
  40. * This is the final nested loop within updateLayoutDelta for future refactoring
  41. */
  42. function applyTreeDeltas(box, treeScale, treePath, isSharedTransition = false) {
  43. const treeLength = treePath.length;
  44. if (!treeLength)
  45. return;
  46. // Reset the treeScale
  47. treeScale.x = treeScale.y = 1;
  48. let node;
  49. let delta;
  50. for (let i = 0; i < treeLength; i++) {
  51. node = treePath[i];
  52. delta = node.projectionDelta;
  53. /**
  54. * TODO: Prefer to remove this, but currently we have motion components with
  55. * display: contents in Framer.
  56. */
  57. const { visualElement } = node.options;
  58. if (visualElement &&
  59. visualElement.props.style &&
  60. visualElement.props.style.display === "contents") {
  61. continue;
  62. }
  63. if (isSharedTransition &&
  64. node.options.layoutScroll &&
  65. node.scroll &&
  66. node !== node.root) {
  67. transformBox(box, {
  68. x: -node.scroll.offset.x,
  69. y: -node.scroll.offset.y,
  70. });
  71. }
  72. if (delta) {
  73. // Incoporate each ancestor's scale into a culmulative treeScale for this component
  74. treeScale.x *= delta.x.scale;
  75. treeScale.y *= delta.y.scale;
  76. // Apply each ancestor's calculated delta into this component's recorded layout box
  77. applyBoxDelta(box, delta);
  78. }
  79. if (isSharedTransition && hasTransform(node.latestValues)) {
  80. transformBox(box, node.latestValues);
  81. }
  82. }
  83. /**
  84. * Snap tree scale back to 1 if it's within a non-perceivable threshold.
  85. * This will help reduce useless scales getting rendered.
  86. */
  87. if (treeScale.x < TREE_SCALE_SNAP_MAX &&
  88. treeScale.x > TREE_SCALE_SNAP_MIN) {
  89. treeScale.x = 1.0;
  90. }
  91. if (treeScale.y < TREE_SCALE_SNAP_MAX &&
  92. treeScale.y > TREE_SCALE_SNAP_MIN) {
  93. treeScale.y = 1.0;
  94. }
  95. }
  96. function translateAxis(axis, distance) {
  97. axis.min = axis.min + distance;
  98. axis.max = axis.max + distance;
  99. }
  100. /**
  101. * Apply a transform to an axis from the latest resolved motion values.
  102. * This function basically acts as a bridge between a flat motion value map
  103. * and applyAxisDelta
  104. */
  105. function transformAxis(axis, axisTranslate, axisScale, boxScale, axisOrigin = 0.5) {
  106. const originPoint = mixNumber(axis.min, axis.max, axisOrigin);
  107. // Apply the axis delta to the final axis
  108. applyAxisDelta(axis, axisTranslate, axisScale, originPoint, boxScale);
  109. }
  110. /**
  111. * Apply a transform to a box from the latest resolved motion values.
  112. */
  113. function transformBox(box, transform) {
  114. transformAxis(box.x, transform.x, transform.scaleX, transform.scale, transform.originX);
  115. transformAxis(box.y, transform.y, transform.scaleY, transform.scale, transform.originY);
  116. }
  117. export { applyAxisDelta, applyBoxDelta, applyPointDelta, applyTreeDeltas, scalePoint, transformAxis, transformBox, translateAxis };