index.js 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. function $parcel$export(e, n, v, s) {
  2. Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
  3. }
  4. $parcel$export(module.exports, "observeElementRect", () => $f98399f7d3345a24$export$5a50ff2cde8c3802);
  5. /**
  6. * Observes an element's rectangle on screen (getBoundingClientRect)
  7. * This is useful to track elements on the screen and attach other elements
  8. * that might be in different layers, etc.
  9. */ function $f98399f7d3345a24$export$5a50ff2cde8c3802(/** The element whose rect to observe */ elementToObserve, /** The callback which will be called when the rect changes */ callback) {
  10. const observedData1 = $f98399f7d3345a24$var$observedElements.get(elementToObserve);
  11. if (observedData1 === undefined) {
  12. // add the element to the map of observed elements with its first callback
  13. // because this is the first time this element is observed
  14. $f98399f7d3345a24$var$observedElements.set(elementToObserve, {
  15. rect: {},
  16. callbacks: [
  17. callback
  18. ]
  19. });
  20. if ($f98399f7d3345a24$var$observedElements.size === 1) // start the internal loop once at least 1 element is observed
  21. $f98399f7d3345a24$var$rafId = requestAnimationFrame($f98399f7d3345a24$var$runLoop);
  22. } else {
  23. // only add a callback for this element as it's already observed
  24. observedData1.callbacks.push(callback);
  25. callback(elementToObserve.getBoundingClientRect());
  26. }
  27. return ()=>{
  28. const observedData = $f98399f7d3345a24$var$observedElements.get(elementToObserve);
  29. if (observedData === undefined) return; // start by removing the callback
  30. const index = observedData.callbacks.indexOf(callback);
  31. if (index > -1) observedData.callbacks.splice(index, 1);
  32. if (observedData.callbacks.length === 0) {
  33. // stop observing this element because there are no
  34. // callbacks registered for it anymore
  35. $f98399f7d3345a24$var$observedElements.delete(elementToObserve);
  36. if ($f98399f7d3345a24$var$observedElements.size === 0) // stop the internal loop once no elements are observed anymore
  37. cancelAnimationFrame($f98399f7d3345a24$var$rafId);
  38. }
  39. };
  40. } // ========================================================================
  41. // module internals
  42. let $f98399f7d3345a24$var$rafId;
  43. const $f98399f7d3345a24$var$observedElements = new Map();
  44. function $f98399f7d3345a24$var$runLoop() {
  45. const changedRectsData = []; // process all DOM reads first (getBoundingClientRect)
  46. $f98399f7d3345a24$var$observedElements.forEach((data, element)=>{
  47. const newRect = element.getBoundingClientRect(); // gather all the data for elements whose rects have changed
  48. if (!$f98399f7d3345a24$var$rectEquals(data.rect, newRect)) {
  49. data.rect = newRect;
  50. changedRectsData.push(data);
  51. }
  52. }); // group DOM writes here after the DOM reads (getBoundingClientRect)
  53. // as DOM writes will most likely happen with the callbacks
  54. changedRectsData.forEach((data)=>{
  55. data.callbacks.forEach((callback)=>callback(data.rect)
  56. );
  57. });
  58. $f98399f7d3345a24$var$rafId = requestAnimationFrame($f98399f7d3345a24$var$runLoop);
  59. } // ========================================================================
  60. /**
  61. * Returns whether 2 rects are equal in values
  62. */ function $f98399f7d3345a24$var$rectEquals(rect1, rect2) {
  63. return rect1.width === rect2.width && rect1.height === rect2.height && rect1.top === rect2.top && rect1.right === rect2.right && rect1.bottom === rect2.bottom && rect1.left === rect2.left;
  64. }
  65. //# sourceMappingURL=index.js.map