index.mjs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { clamp } from '../../../../utils/clamp.mjs';
  2. import { interpolate } from '../../../../utils/interpolate.mjs';
  3. import { defaultOffset } from '../../../../utils/offsets/default.mjs';
  4. import { calcInset } from './inset.mjs';
  5. import { resolveOffset } from './offset.mjs';
  6. import { ScrollOffset } from './presets.mjs';
  7. const point = { x: 0, y: 0 };
  8. function getTargetSize(target) {
  9. return "getBBox" in target && target.tagName !== "svg"
  10. ? target.getBBox()
  11. : { width: target.clientWidth, height: target.clientHeight };
  12. }
  13. function resolveOffsets(container, info, options) {
  14. const { offset: offsetDefinition = ScrollOffset.All } = options;
  15. const { target = container, axis = "y" } = options;
  16. const lengthLabel = axis === "y" ? "height" : "width";
  17. const inset = target !== container ? calcInset(target, container) : point;
  18. /**
  19. * Measure the target and container. If they're the same thing then we
  20. * use the container's scrollWidth/Height as the target, from there
  21. * all other calculations can remain the same.
  22. */
  23. const targetSize = target === container
  24. ? { width: container.scrollWidth, height: container.scrollHeight }
  25. : getTargetSize(target);
  26. const containerSize = {
  27. width: container.clientWidth,
  28. height: container.clientHeight,
  29. };
  30. /**
  31. * Reset the length of the resolved offset array rather than creating a new one.
  32. * TODO: More reusable data structures for targetSize/containerSize would also be good.
  33. */
  34. info[axis].offset.length = 0;
  35. /**
  36. * Populate the offset array by resolving the user's offset definition into
  37. * a list of pixel scroll offets.
  38. */
  39. let hasChanged = !info[axis].interpolate;
  40. const numOffsets = offsetDefinition.length;
  41. for (let i = 0; i < numOffsets; i++) {
  42. const offset = resolveOffset(offsetDefinition[i], containerSize[lengthLabel], targetSize[lengthLabel], inset[axis]);
  43. if (!hasChanged && offset !== info[axis].interpolatorOffsets[i]) {
  44. hasChanged = true;
  45. }
  46. info[axis].offset[i] = offset;
  47. }
  48. /**
  49. * If the pixel scroll offsets have changed, create a new interpolator function
  50. * to map scroll value into a progress.
  51. */
  52. if (hasChanged) {
  53. info[axis].interpolate = interpolate(info[axis].offset, defaultOffset(offsetDefinition), { clamp: false });
  54. info[axis].interpolatorOffsets = [...info[axis].offset];
  55. }
  56. info[axis].progress = clamp(0, 1, info[axis].interpolate(info[axis].current));
  57. }
  58. export { resolveOffsets };