Skip to content

Instantly share code, notes, and snippets.

@benrobygreene
Created November 12, 2019 18:27
Show Gist options
  • Save benrobygreene/26df915a93ef9274ceb3f42a14b79bde to your computer and use it in GitHub Desktop.
Save benrobygreene/26df915a93ef9274ceb3f42a14b79bde to your computer and use it in GitHub Desktop.
Marquee
import { debounce } from 'common/Helpers';
const dom = {
marquee: 'data-marquee-wrapper',
marqueeText: 'data-marquee-text',
};
/**
* Build an animation for a marquee wrapper
*
* @param {String} text: the text to display in the marquee
* @param {Node} marqueeWrapper: the node to append the marquee text element to
* @param {int} index: the current marquee being built
*/
const addMarqueeStyles = (itemWidth, marqueeWrapper, index) => {
const styleElement = document.createElement('style');
styleElement.innerHTML = `@keyframes marquee-${index} {
0% { margin-left: 0px; }
100% { margin-left: -${itemWidth}px; }
}`;
marqueeWrapper.appendChild(styleElement);
marqueeWrapper.style.animation = `marquee-${index} 5s linear infinite`;
};
/**
* Build a marquee text element to add to the marquee wrapper
*
* @param {String} text: the text to display in the marquee
* @param {Node} marqueeWrapper: the node to append the marquee text element to
*
* @return {Node}: the new node to add to the marquee wrapper
*/
const buildMarqueeItem = (text, marqueeWrapper) => {
const newElement = document.createElement('span');
newElement.classList.add('marquee-item');
newElement.innerHTML = `${text} `;
marqueeWrapper.appendChild(newElement);
return newElement;
};
/**
* Add the marquee items to the wrapper
*
* @param {Node} marqueeWrapper: the node to append the marquee text element to
* @param {int} index: the current marquee being built
*/
const addMarqueeItems = (marqueeWrapper, index) => {
const text = marqueeWrapper.getAttribute(dom.marquee);
// Get a test element to check and see how many text elements to add to the marquee wrapper
const newMarqueeText = buildMarqueeItem(text, marqueeWrapper);
const itemWidth = newMarqueeText.getBoundingClientRect().width;
// Need to +1 to ensure that the marquee doesn't ever have blank space at the far end of the wrapper
// (would occur at the end of the animation)
const numToBuild = Math.floor(window.innerWidth / itemWidth + 1);
for (let i = 0; i < numToBuild; i++) {
buildMarqueeItem(text, marqueeWrapper);
}
// need to add the animation styles for the marquee now
addMarqueeStyles(itemWidth, marqueeWrapper, index);
};
/**
* Loops through and sets up the individual marquee wrappers
*/
const setupMarquees = () => {
const marqueeWrappers = document.querySelectorAll(`[${dom.marquee}]`);
marqueeWrappers.forEach((marqueeWrapper, index) => {
marqueeWrapper.innerHTML = '';
addMarqueeItems(marqueeWrapper, index);
});
};
/**
* Reset all marquee wrappers to contain enough elements for new window size.
*/
const resetMarquee = debounce(() => {
setupMarquees();
}, 500);
/**
* Setup all marquee elements & debouncer for resetting on window resize.
*/
const setup = () => {
setupMarquees();
window.addEventListener('resize', resetMarquee);
};
export default {
setup,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment