@v4fire/client
Version:
V4Fire client core library
122 lines (104 loc) • 2.79 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
import type { ElementRect } from 'core/dom/in-view/interface';
// tslint:disable-next-line strict-type-predicates
export const hasMutationObserver = typeof MutationObserver === 'function';
/**
* Returns the top offset relative to the root
*
* @param root
* @param el
*/
export function getOffsetTop({scrollTop}: RootRect, {top}: DOMRect | ClientRect): number {
return top + scrollTop;
}
/**
* Returns the left offset relative to the root
*
* @param root
* @param el
*/
export function getOffsetLeft({scrollLeft}: RootRect, {left}: DOMRect | ClientRect): number {
return left + scrollLeft;
}
/**
* Returns true if an element is visible
* @param rect
*/
export function isElementVisible(rect: {width: number; height: number}): boolean {
return rect.width > 0 && rect.height > 0;
}
/**
* Returns an element geometry relative to the root
*
* @param root
* @param el
*/
export function getElementRect(root: RootRect, el: Element): ElementRect {
const
rect = el.getBoundingClientRect(),
{width, height} = rect;
const
top = getOffsetTop(root, rect),
left = getOffsetLeft(root, rect);
return {
bottom: top + height,
right: left + width,
top,
left,
width,
height
};
}
/**
* Returns the page root
*/
export function getRoot(): Element {
return document.documentElement;
}
/**
* Returns the root element geometry
*/
export function getRootRect(): RootRect {
const
r = getRoot(),
s = <Element>document.scrollingElement;
return {
width: r.clientWidth,
height: r.clientHeight,
scrollLeft: s.scrollLeft,
scrollTop: s.scrollTop
};
}
interface RootRect {
width: number;
height: number;
scrollTop: number;
scrollLeft: number;
}
/**
* Returns true if the specified element is in view
*
* @param elRect
* @param rootRect
* @param threshold
*/
export function isElementInView(elRect: ElementRect, rootRect: RootRect, threshold: number): boolean {
if (elRect.width === 0 || elRect.height === 0) {
return false;
}
const
isBoxInRootY = rootRect.scrollTop + rootRect.height >= elRect.top + elRect.height * threshold,
isBoxInRootX = rootRect.scrollLeft + rootRect.width >= elRect.left + elRect.width * threshold,
isVisibleYTop = elRect.top + elRect.height * threshold >= rootRect.scrollTop,
isVisibleYBottom = elRect.bottom - elRect.height * threshold < rootRect.scrollTop,
isVisibleX = elRect.left > 0 ?
elRect.left - elRect.width * threshold <= rootRect.scrollLeft + rootRect.width :
elRect.left + elRect.width * threshold >= rootRect.scrollLeft;
return isBoxInRootY && isBoxInRootX && isVisibleYTop && isVisibleX && !isVisibleYBottom;
}