Skip to content

Instantly share code, notes, and snippets.

@audunolsen
Last active May 13, 2021 21:16
Show Gist options
  • Save audunolsen/9225aa14681a50f61c25a5049b0eb06c to your computer and use it in GitHub Desktop.
Save audunolsen/9225aa14681a50f61c25a5049b0eb06c to your computer and use it in GitHub Desktop.
Returns a detailed set of data regarding an elements position relative to the viewport
/* eslint-disable */
/*
type Directions {
top: boolean;
left: boolean;
bottom: boolean;
right: boolean;
horizontal: boolean;
vertical: boolean;
all: boolean;
}
type Percents {
horizontal: number;
vertical: number;
total: number;
}
type Return {
fully?: Directions
hidden?: Directions
intersects?: Directions
percents {
visible: Percents
occupied: Percents
}
}
*/
export default function visibility(target/* Element | DOMRect */, { relative /* Element | DOMRect */ } = {}) {
// TODO: relative parent
let rect;
if (target instanceof DOMRect) rect = target;
if (target instanceof Element) rect = target.getBoundingClientRect();
const outerArea = { width: innerWidth, height: innerHeight };
let fully = {
top: rect.top >= 0,
left: rect.left >= 0,
bottom: rect.bottom <= outerArea.height,
right: rect.right <= outerArea.width
};
fully.horizontal = fully.left && fully.right;
fully.vertical = fully.top && fully.bottom;
fully.all = fully.horizontal && fully.vertical;
let hidden = {
top: rect.top + rect.height <= 0,
left: rect.left + rect.width <= 0,
bottom: rect.bottom - rect.height >= outerArea.height,
right: rect.right - rect.width >= outerArea.width
};
hidden.horizontal = hidden.left || hidden.right;
hidden.vertical = hidden.top || hidden.bottom;
hidden.all = hidden.horizontal && hidden.vertical;
let intersects = Object.fromEntries(['top', 'left', 'bottom', 'right'].map(dir => [
dir, !fully[dir] && !hidden[dir]
]));
intersects.horizontal = intersects.left || intersects.right;
intersects.vertical = intersects.top || intersects.bottom;
intersects.all = intersects.horizontal && intersects.vertical;
const percents = {
occupied: {},
visible: {}
};
const axes = {
horizontal: ['left', 'right', 'width'],
vertical: ['top', 'bottom', 'height']
};
for (const [axis, [start, end, length]] of Object.entries(axes)) {
if (hidden[axis]) percents.visible[axis] = 0;
if (fully[axis]) percents.visible[axis] = 1;
if (intersects[start] ^ intersects[end]) {
percents.visible[axis] = intersects[start]
? (rect[start] + rect[length]) / rect[length]
: (outerArea[length] - rect[start]) / rect[length];
percents.occupied[axis] = intersects[start]
? (rect[start] + rect[length]) / outerArea[length]
: (outerArea[length] - rect[start]) / outerArea[length];
}
if (intersects[start] && intersects[end]) {
percents.occupied[axis] = 1;
percents.visible[axis] = outerArea[length] / rect[length];
}
if (fully[start] && fully[end]) percents.occupied[axis] = rect[length] / outerArea[length];
}
const
visibleWidth = rect.width * percents.visible.horizontal,
visibleHeight = rect.height * percents.visible.vertical,
visibleArea = visibleWidth * visibleHeight;
percents.occupied.total = visibleArea / (outerArea.width * outerArea.height);
percents.visible.total = visibleArea / (rect.height * rect.width);
const falsy = e => !!e === false;
if (Object.values(fully).every(falsy)) fully = false;
if (Object.values(hidden).every(falsy)) hidden = false;
if (Object.values(intersects).every(falsy)) intersects = false;
return { fully, hidden, intersects, ...percents };
}
@audunolsen
Copy link
Author

13.05.21 - In progress refactoring. Now returns a lot more useful data and is far more succinctly written

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment