{ "version": 3, "sources": ["src/app/shared/scroll/intersection-observer.service.ts"], "sourcesContent": ["import { Injectable, NgZone, ElementRef } from '@angular/core';\r\nimport { ScrollBarService } from '@shared/scroll/scrollbar.service';\r\nimport { NgScrollbar } from 'ngx-scrollbar';\r\n\r\n\r\nexport interface IntersectionTarget {\r\n elRef: ElementRef;\r\n updateVisibility?: (isVisible: boolean, ratio: number) => void;\r\n}\r\n\r\n@Injectable()\r\nexport class IntersectionObserverService {\r\n\r\n private observer: IntersectionObserver;\r\n private targets: Map;\r\n\r\n // I initialize the lazy-viewport service.\r\n constructor(\r\n private zone: NgZone,\r\n private scrollBarService: ScrollBarService\r\n ) {\r\n\r\n this.observer = null;\r\n\r\n // The IntersectionObserver watches Elements. However, when an element visibility\r\n // changes, we have to alert an Angular Directive instance. As such, we're going\r\n // to keep a map of Elements-to-Directives. This way, when our observer callback\r\n // is invoked, we'll be able to extract the appropriate Directive from the\r\n // Element-based observer entries collection.\r\n this.targets = new Map();\r\n\r\n }\r\n\r\n // ---\r\n // PUBLIC METHODS.\r\n // ---\r\n\r\n // I add the given IntersectionTarget implementation to the collection of objects being\r\n // tracked by the IntersectionObserver.\r\n public addTarget(target: IntersectionTarget): void {\r\n\r\n if (this.observer) {\r\n const el = target.elRef.nativeElement;\r\n if (el instanceof Element === false) {\r\n throw new Error('Intersection Observer service: Invalid target element');\r\n }\r\n\r\n this.targets.set(el, target);\r\n this.observer.observe(el);\r\n\r\n // provvedere polyfill https://github.com/w3c/IntersectionObserver/tree/master/polyfill\r\n // If we don't actually have an observer (lacking browser support), then we're\r\n // going to punt on the feature for now and just immediately tell the target\r\n // that it is visible on the page.\r\n } else {\r\n\r\n target.updateVisibility(true, 1.0);\r\n\r\n }\r\n\r\n }\r\n\r\n\r\n // I setup the IntersectionObserver with the given element as the root.\r\n public setup(scrollbar: NgScrollbar | string = null, rootMargin?: string, threshold?: number): void {\r\n\r\n // While the IntersectionObserver is supported in the modern browsers, it will\r\n // never be added to Internet Explorer (IE) and is not in my version of Safari\r\n // (at the time of this post). As such, we'll only use it if it's available.\r\n // And, if it's not, we'll fall-back to non-lazy behaviors.\r\n let sb: NgScrollbar;\r\n if (!global['IntersectionObserver']) {\r\n\r\n return;\r\n\r\n }\r\n if (scrollbar) {\r\n sb = typeof scrollbar === 'string' ? this.scrollBarService.getById(scrollbar) : scrollbar;\r\n } else {\r\n sb = this.scrollBarService.mainScrollbar;\r\n }\r\n\r\n\r\n this.zone.runOutsideAngular(\r\n () => {\r\n this.observer = new IntersectionObserver(\r\n this.handleIntersectionUpdate,\r\n {\r\n root: sb.viewport.nativeElement,\r\n rootMargin: rootMargin ? rootMargin : '0px 0px 0px 0px',\r\n threshold: threshold ? threshold : 0\r\n }\r\n );\r\n });\r\n\r\n }\r\n\r\n\r\n // I remove the given LazyTarget implementation from the collection of objects being\r\n // tracked by the IntersectionObserver.\r\n public removeTarget(target: ElementRef): void {\r\n\r\n // If the IntersectionObserver isn't supported, we never started tracking the\r\n // given target in the first place.\r\n if (this.observer) {\r\n const el = target.nativeElement;\r\n this.targets.delete(el);\r\n this.observer.unobserve(el);\r\n }\r\n\r\n }\r\n\r\n\r\n // I teardown this service instance.\r\n public teardown(): void {\r\n\r\n if (this.observer) {\r\n\r\n this.observer.disconnect();\r\n this.observer = null;\r\n\r\n }\r\n\r\n this.targets.clear();\r\n this.targets = null;\r\n\r\n }\r\n\r\n // ---\r\n // PRIVATE METHODS.\r\n // ---\r\n\r\n // I handle changes in the visibility for elements being tracked by the intersection\r\n // observer.\r\n // --\r\n // CAUTION: Using fat-arrow binding for method.\r\n private handleIntersectionUpdate = (entries: IntersectionObserverEntry[]): void => {\r\n\r\n for (const entry of entries) {\r\n\r\n const intersectionTarget = this.targets.get(entry.target);\r\n\r\n if (intersectionTarget) {\r\n intersectionTarget.updateVisibility(\r\n entry.isIntersecting,\r\n entry.intersectionRatio\r\n );\r\n }\r\n }\r\n\r\n }\r\n\r\n}\r\n"], "mappings": "iGAWA,IAAaA,GAA2B,IAAA,CAAlC,IAAOA,EAAP,MAAOA,CAA2B,CAMtCC,YACUC,EACAC,EAAkC,CADlC,KAAAD,KAAAA,EACA,KAAAC,iBAAAA,EAqHF,KAAAC,yBAA4BC,GAA8C,CAEhF,QAAWC,KAASD,EAAS,CAE3B,IAAME,EAAqB,KAAKC,QAAQC,IAAIH,EAAMI,MAAM,EAEpDH,GACFA,EAAmBI,iBACjBL,EAAMM,eACNN,EAAMO,iBAAiB,CAG7B,CAEF,EAhIE,KAAKC,SAAW,KAOhB,KAAKN,QAAU,IAAIO,GAErB,CAQOC,UAAUN,EAA0B,CAEzC,GAAI,KAAKI,SAAU,CACjB,IAAMG,EAAKP,EAAOQ,MAAMC,cACxB,GAAIF,EAAAA,aAAcG,SAChB,MAAM,IAAIC,MAAM,uDAAuD,EAGzE,KAAKb,QAAQc,IAAIL,EAAIP,CAAM,EAC3B,KAAKI,SAASS,QAAQN,CAAE,CAM1B,MAEEP,EAAOC,iBAAiB,GAAM,CAAG,CAIrC,CAIOa,MAAMC,EAAkC,KAAMC,EAAqBC,EAAkB,CAM1F,IAAIC,EACCC,OAAO,uBAKRJ,EACFG,EAAK,OAAOH,GAAc,SAAW,KAAKtB,iBAAiB2B,QAAQL,CAAS,EAAIA,EAEhFG,EAAK,KAAKzB,iBAAiB4B,cAI7B,KAAK7B,KAAK8B,kBACR,IAAK,CACH,KAAKlB,SAAW,IAAImB,qBAClB,KAAK7B,yBACL,CACE8B,KAAMN,EAAGO,SAAShB,cAClBO,WAAYA,GAA0B,kBACtCC,UAAWA,GAAwB,EACpC,CAEL,CAAC,EAEL,CAKOS,aAAa1B,EAAkB,CAIpC,GAAI,KAAKI,SAAU,CACjB,IAAMG,EAAKP,EAAOS,cAClB,KAAKX,QAAQ6B,OAAOpB,CAAE,EACtB,KAAKH,SAASwB,UAAUrB,CAAE,CAC5B,CAEF,CAIOsB,UAAQ,CAET,KAAKzB,WAEP,KAAKA,SAAS0B,WAAU,EACxB,KAAK1B,SAAW,MAIlB,KAAKN,QAAQiC,MAAK,EAClB,KAAKjC,QAAU,IAEjB,yCAnHWR,GAA2B0C,EAAAC,CAAA,EAAAD,EAAAE,CAAA,CAAA,CAAA,wBAA3B5C,EAA2B6C,QAA3B7C,EAA2B8C,SAAA,CAAA,EAAlC,IAAO9C,EAAP+C,SAAO/C,CAA2B,GAAA", "names": ["IntersectionObserverService", "constructor", "zone", "scrollBarService", "handleIntersectionUpdate", "entries", "entry", "intersectionTarget", "targets", "get", "target", "updateVisibility", "isIntersecting", "intersectionRatio", "observer", "Map", "addTarget", "el", "elRef", "nativeElement", "Element", "Error", "set", "observe", "setup", "scrollbar", "rootMargin", "threshold", "sb", "global", "getById", "mainScrollbar", "runOutsideAngular", "IntersectionObserver", "root", "viewport", "removeTarget", "delete", "unobserve", "teardown", "disconnect", "clear", "\u0275\u0275inject", "NgZone", "ScrollBarService", "factory", "\u0275fac", "_IntersectionObserverService"] }