Created
February 17, 2021 11:05
-
-
Save russellsamora/08cc59443c0e5a02c6d0062ef793dcbf to your computer and use it in GitHub Desktop.
resolves intersection observer multiple visible conflict
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 action triggers a custom event on node entering/exiting the viewport. | |
* example: | |
* <p | |
* use:inView | |
* on:enter={() => console.log("enter")} | |
* on:exit={() => console.log("exit")} | |
* on:change={() => console.log("change")} | |
* > | |
* | |
* if you want to keep track of which section is visible, | |
* you can use the scrollSectionResolver function at the bottom of this script | |
* | |
* import inView, { scrollSectionResolver } from "./../inView.js"; | |
* | |
* in your component, first create a new scrollResolver | |
* | |
* let currentSectionId = writable(0); | |
* const scrollResolver = scrollSectionResolver("app", currentSectionId); | |
* | |
* then trigger the updates in each section | |
* | |
* <div | |
* on:change="{({ detail }) => scrollResolver.update("section-id", detail.percent)}" | |
* > | |
* | |
*/ | |
export default function inView(node, params = {}) { | |
let observer; | |
const handleIntersect = (e) => { | |
const v = e[0].isIntersecting ? "enter" : "exit"; | |
node.dispatchEvent(new CustomEvent(v)); | |
node.dispatchEvent( | |
new CustomEvent("change", { | |
detail: { | |
value: e[0].isIntersecting, | |
percent: e[0].intersectionRatio, | |
}, | |
}) | |
); | |
}; | |
const setObserver = ({ root }) => { | |
const options = { | |
threshold: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1], | |
root, | |
}; | |
if (observer) observer.disconnect(); | |
observer = new IntersectionObserver(handleIntersect, options); | |
observer.observe(node); | |
}; | |
setObserver(params); | |
return { | |
update(params) { | |
setObserver(params); | |
}, | |
destroy() { | |
if (observer) observer.disconnect(); | |
}, | |
}; | |
} | |
let ssrStates = {}; | |
export function scrollSectionResolver(globalId, currentState, threshold = 0.3) { | |
// create global state | |
if (!ssrStates[globalId]) ssrStates[globalId] = {}; | |
let globalState = ssrStates[globalId]; | |
return { | |
update(id, percent) { | |
// when a section updates, update the global percent & choose the winner | |
const isEntering = percent > globalState[id]; | |
const isNew = globalState[id] === undefined; | |
globalState[id] = percent; | |
if (isNew) { | |
let idWithMaxViewing = id; | |
let maxViewingValue = 0; | |
Object.keys(globalState).forEach((key) => { | |
const value = globalState[key]; | |
if (value < maxViewingValue) return; | |
maxViewingValue = value; | |
idWithMaxViewing = key; | |
}); | |
currentState.set(idWithMaxViewing); | |
} else { | |
if (isEntering && percent > threshold) { | |
currentState.set(id); | |
} | |
} | |
}, | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment