Skip to content

Instantly share code, notes, and snippets.

@dewdad
Created June 19, 2019 10:57
Show Gist options
  • Save dewdad/8e7f9a1db79cee4b9b3b6e882eb97ba5 to your computer and use it in GitHub Desktop.
Save dewdad/8e7f9a1db79cee4b9b3b6e882eb97ba5 to your computer and use it in GitHub Desktop.
Finding element intersection and position in DOM
/**
* This function is useful for getting first and last elements inside a container given a y offset such as top and bottom of visible area.
* One way to mark the top and bottom of a container is to add 2 markers divs like so
* <section class="container">
* <div class="fixed-top-marker" style="position: fixed; top: 0" />
* ...
* <div class="fixed-bottom-marker" style="position: fixed; bottom: 0" />
* </section>
*
* then to query bottom use:
* document.querySelector('#meeting-scroll-container .fixed-bottom-marker').getBoundingClientRect().bottom
*
* @param {number} yCoord - The y coord you want search proximity to, e.g: top/bottom of scroll container of elements collection
* @param {string | NodeList} elements - The elements you want to search for proximity to yCoord
* @param {('top'|'bottom')} yEdgeCompare - Compare yCoord to top or bottom of element collection
* @param {('top'|'bottom'|'')} [searchFrom=''] - Start the search from bottom or top of element collection
* @param {boolean} [stopSearchAfterDistanceGrows] - If the collection is sorted and direction is set the function will execute faster given
*/
function getElEdgeNearestToY (yCoord, elements, yEdgeCompare, searchFrom='', stopSearchAfterDistanceGrows = searchFrom? true : false) {
let items = typeof(elements) === 'string'? document.querySelector(elements) : elements;
if(!items) return null;
let isSearchFromBottom = searchFrom === 'bottom';
// search from top or bottom by given searchDirection
if(isSearchFromBottom) items = Array.from(items).reverse();
let nearestToYItem = null;
let nearestToYCoord = Infinity;
for (let len = items.length, i = 0; i < len; i++) {
const itemOffsetFromY = Math.abs(
items[i].getBoundingClientRect()[yEdgeCompare] - yCoord
);
if (itemOffsetFromY < nearestToYCoord) {
nearestToYCoord = itemOffsetFromY;
nearestToYItem = items[i];
} else if(stopSearchAfterDistanceGrows){
break;
}
}
return nearestToYItem
}
/**
* This function is useful for getting first and last elements inside a container given a y offset such as top and bottom of visible area.
* One way to mark the top and bottom of a container is to add 2 markers divs like so
* <section class="container">
* <div class="fixed-top-marker" style="position: fixed; top: 0" />
* ...
* <div class="fixed-bottom-marker" style="position: fixed; bottom: 0" />
* </section>
*
* then to query bottom use:
* document.querySelector('#meeting-scroll-container .fixed-bottom-marker').getBoundingClientRect().bottom
*
* @param {number} yCoord - The y coord you want search intesection with, e.g: top/bottom of scroll container of elements collection
* @param {string | NodeList} elements - The elements you want to search for which intersects yCoord
* @param {('top'|'bottom')} [searchFrom='top'] - Start the search from bottom or top of element collection
* @return {HTMLElement} The Element on yCoord
*/
window.getElOnY = function getElOnY(yCoord, elements, searchFrom = 'top', yCoordOffset = 0, margin = 0) {
let items = typeof (elements) === 'string' ? document.querySelectorAll(elements) : elements;
if (!items) return null;
let isSearchFromBottom = searchFrom === 'bottom';
// search from top or bottom by given searchDirection
if (isSearchFromBottom) items = Array.from(items).reverse();
yCoord += isSearchFromBottom ? -yCoordOffset : yCoordOffset;
let onYItem = null;
for (let len = items.length, i = 0; i < len; i++) {
const elRect = items[i].getBoundingClientRect();
if (elRect.top - margin <= yCoord && yCoord <= elRect.bottom + margin) {
onYItem = items[i];
break;
}
}
return onYItem
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment