73 lines
2.2 KiB
JavaScript
73 lines
2.2 KiB
JavaScript
/**
|
|
* ViewportTracker — dual IntersectionObserver for page visibility detection.
|
|
*
|
|
* - visibleSet: pages currently on screen (rootMargin "0px")
|
|
* - bufferSet: pages within ~2 viewport heights above/below (rootMargin "200% 0px")
|
|
*
|
|
* Calls onVisibilityChange(bufferSet, visibleSet) whenever either set changes.
|
|
*/
|
|
export class ViewportTracker {
|
|
/**
|
|
* @param {HTMLElement} root - scroll container (#canvas-container)
|
|
* @param {HTMLElement[]} pageWrappers - array of .page-wrapper elements
|
|
* @param {Function} onVisibilityChange - (bufferSet: Set<number>, visibleSet: Set<number>) => void
|
|
*/
|
|
constructor(root, pageWrappers, onVisibilityChange) {
|
|
this._onVisibilityChange = onVisibilityChange;
|
|
this._visibleSet = new Set();
|
|
this._bufferSet = new Set();
|
|
this._visibleObserver = null;
|
|
this._bufferObserver = null;
|
|
|
|
this._observe(root, pageWrappers);
|
|
}
|
|
|
|
_observe(root, pageWrappers) {
|
|
const notify = () => {
|
|
this._onVisibilityChange(new Set(this._bufferSet), new Set(this._visibleSet));
|
|
};
|
|
|
|
this._visibleObserver = new IntersectionObserver(
|
|
entries => {
|
|
for (const e of entries) {
|
|
const page = parseInt(e.target.dataset.page, 10);
|
|
if (e.isIntersecting) this._visibleSet.add(page);
|
|
else this._visibleSet.delete(page);
|
|
}
|
|
notify();
|
|
},
|
|
{ root, rootMargin: "0px", threshold: 0 }
|
|
);
|
|
|
|
this._bufferObserver = new IntersectionObserver(
|
|
entries => {
|
|
for (const e of entries) {
|
|
const page = parseInt(e.target.dataset.page, 10);
|
|
if (e.isIntersecting) this._bufferSet.add(page);
|
|
else this._bufferSet.delete(page);
|
|
}
|
|
notify();
|
|
},
|
|
{ root, rootMargin: "200% 0px", threshold: 0 }
|
|
);
|
|
|
|
for (const wrap of pageWrappers) {
|
|
this._visibleObserver.observe(wrap);
|
|
this._bufferObserver.observe(wrap);
|
|
}
|
|
}
|
|
|
|
/** Observe a newly-added page wrapper. */
|
|
observe(wrap) {
|
|
this._visibleObserver?.observe(wrap);
|
|
this._bufferObserver?.observe(wrap);
|
|
}
|
|
|
|
disconnect() {
|
|
this._visibleObserver?.disconnect();
|
|
this._bufferObserver?.disconnect();
|
|
this._visibleSet.clear();
|
|
this._bufferSet.clear();
|
|
}
|
|
}
|