Created
May 28, 2020 19:25
-
-
Save dimfeld/723aff37ce45cdbf47d0dee8ea9aa1bf to your computer and use it in GitHub Desktop.
Svelte IntersectionObserver action example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This is intended to be used with the svelte `use` syntax. It examines all | |
* child elements of the element that match `selector`, and calls the callback | |
* when the child element with the highest percentage overlap with the visible | |
* part of the container changes. | |
* <div use:mostVisibleElement={{ cb: setActive }}><section><section></div> | |
*/ | |
export default function mostVisibleElement( | |
container: Element, | |
{ selector, cb } | |
) { | |
if (typeof IntersectionObserver === 'undefined') { | |
return {}; | |
} | |
selector = selector || 'section'; | |
let intersections = new Map(); | |
let activeElement; | |
let intObserver = new IntersectionObserver( | |
(entries) => { | |
for (let entry of entries) { | |
intersections.set(entry.target, entry.intersectionRatio); | |
} | |
let maxIntersectedChild; | |
let maxRatio = 0; | |
for (let child of children) { | |
let ratio = intersections.get(child); | |
if (ratio > maxRatio + 0.1) { | |
maxRatio = ratio; | |
maxIntersectedChild = child; | |
if (ratio === 1) { | |
break; | |
} | |
} | |
} | |
if (maxIntersectedChild && maxIntersectedChild !== activeElement) { | |
activeElement = maxIntersectedChild; | |
cb(maxIntersectedChild); | |
} | |
}, | |
{ | |
root: container, | |
threshold: [1, 0.75, 0.5, 0.25, 0.1, 0], | |
} | |
); | |
let mutObserver = new MutationObserver(() => update); | |
mutObserver.observe(container, { childList: true }); | |
let children = []; | |
var update = () => { | |
intObserver.disconnect(); | |
intersections.clear(); | |
children = []; | |
activeElement = null; | |
container.querySelectorAll(selector).forEach((child) => { | |
children.push(child); | |
intObserver.observe(child); | |
}); | |
}; | |
update(); | |
return { | |
destroy() { | |
intObserver.disconnect(); | |
mutObserver.disconnect(); | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment