/* * https://github.com/morethanwords/tweb * Copyright (C) 2019-2021 Eduard Kuzmenko * https://github.com/morethanwords/tweb/blob/master/LICENSE */ type TargetType = HTMLElement; export type OnVisibilityChangeItem = {target: TargetType, visible: boolean, entry: IntersectionObserverEntry, index: number}; export type OnVisibilityChange = (item: OnVisibilityChangeItem) => void; export default class VisibilityIntersector { private observer: IntersectionObserver; private items: Map = new Map(); private locked = false; constructor(onVisibilityChange: OnVisibilityChange, options?: IntersectionObserverInit) { this.observer = new IntersectionObserver((entries) => { if(this.locked) { return; } const changed: OnVisibilityChangeItem[] = []; entries.forEach((entry, index) => { const target = entry.target as TargetType; if(this.items.get(target) === entry.isIntersecting) { return; } else { this.items.set(target, entry.isIntersecting); } /* if(entry.isIntersecting) { console.log('ooo', entry); } */ /* if(this.locked) { return; } */ const change: typeof changed[0] = {target, visible: entry.isIntersecting, entry, index}; // ! order will be incorrect so can't use it // changed[entry.isIntersecting ? 'unshift' : 'push'](change); changed.push(change); // onVisibilityChange(target, entry.isIntersecting); }); changed.forEach((item) => { onVisibilityChange(item); }); }, options); } public getVisible() { const items: TargetType[] = []; this.items.forEach((value, key) => { if(value) { items.push(key); } }); return items; } public clearVisible() { const visible = this.getVisible(); for(const target of visible) { this.items.set(target, false); } } public isVisible(target: TargetType) { return this.items.get(target); } public disconnect() { this.observer.disconnect(); this.items.clear(); } public refresh() { this.observer.disconnect(); // window.requestAnimationFrame(() => { const targets = [...this.items.keys()]; for(const target of targets) { // this.items.set(target, false); this.observer.observe(target); } // }); } public refreshVisible() { const visible = this.getVisible(); for(const target of visible) { this.observer.unobserve(target); } for(const target of visible) { this.observer.observe(target); } } public observe(target: TargetType) { this.items.set(target, false); this.observer.observe(target); } public unobserve(target: TargetType) { this.observer.unobserve(target); this.items.delete(target); } public unlock() { this.locked = false; } public unlockAndRefresh() { this.unlock(); this.refresh(); } public lock() { this.locked = true; } }