Skip to content

Instantly share code, notes, and snippets.

@russellsamora
Created February 17, 2021 11:05
Show Gist options
  • Save russellsamora/08cc59443c0e5a02c6d0062ef793dcbf to your computer and use it in GitHub Desktop.
Save russellsamora/08cc59443c0e5a02c6d0062ef793dcbf to your computer and use it in GitHub Desktop.
resolves intersection observer multiple visible conflict
/**
* 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