129 lines
3.0 KiB
TypeScript
129 lines
3.0 KiB
TypeScript
/*
|
|
* 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<TargetType, boolean> = 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;
|
|
}
|
|
}
|