UNPKG

analytics-scroll-depth

Version:
152 lines (139 loc) 4.42 kB
import throttle from './lib/throttle' export default function (settings = {}) { settings = Object.assign({ throttle : 250, minHeight : 0, scrollElement : document.documentElement, percentages : [0.25, 0.5, 0.75, 0.9, 0.95, 0.99], pixelDepthInterval : 500, elements : [], dataLayer : window.dataLayer, trackerName : '', eventName : 'CustomEvent', eventCategory : 'Scroll Depth', percentageDepthAction : 'Percentage Depth', pixelDepthAction : 'Pixel Depth', elementAction : 'Element Depth', nonInteraction : true, }, settings) let greatestScrollTop = 0 if (settings.trackerName) { settings.trackerName += '.' } /** * Send event dataLayer and/or analytics object * @param {object} o Object to send to dataLayer * @return {void} */ function send(o) { if (settings.dataLayer) { settings.dataLayer.push(o) } else if (window[window.GoogleAnalyticsObject]) { window[window.GoogleAnalyticsObject](`${settings.trackerName}send`, 'event', o.eventCategory, o.eventAction, o.eventLabel, o.eventValue, { nonInteraction: o.nonInteraction }) } } /** * Push an event when the user has scrolled past each percentage in settings.percentages * @return {void} */ function percentageDepth() { const scrollRatio = settings.scrollElement.scrollTop / (settings.scrollElement.scrollHeight - settings.scrollElement.clientHeight) // eslint-disable-line max-len settings.percentages.forEach((point, index) => { if (scrollRatio >= point) { settings.percentages.splice(index, 1) send({ event : settings.eventName, eventCategory : settings.eventCategory, eventAction : settings.percentageDepthAction, eventLabel : point, eventValue : null, nonInteraction : settings.nonInteraction, }) } }) } /** * Push an event when the user has scrolled past each pixelDepthInterval * @return {void} */ function pixelDepth() { const scrollTop = settings.scrollElement.scrollTop while (scrollTop >= greatestScrollTop + settings.pixelDepthInterval) { greatestScrollTop += settings.pixelDepthInterval send({ event : settings.eventName, eventCategory : settings.eventCategory, eventAction : settings.pixelDepthAction, eventLabel : greatestScrollTop + settings.pixelDepthInterval, eventValue : null, nonInteraction : settings.nonInteraction, }) } } /** * Return the event label * @param {node} element * @return {string} */ function formatElementLabel(element) { let label = element.localName if (element.id) { label += `#${element.id}` } if (element.className) { label += `.${element.className.replace(/ /g, '.')}` } return label } /** * Push an event when the given element scrolls into view, if it exists * @return {void} */ function elements() { settings.elements.forEach((element, index) => { if ( element && element.offsetTop && element.clientHeight && element.offsetTop + element.clientHeight < settings.scrollElement.clientHeight + settings.scrollElement.scrollTop ) { settings.elements.splice(index, 1) send({ event : settings.eventName, eventCategory : settings.eventCategory, eventAction : settings.elementAction, eventLabel : formatElementLabel(element), eventValue : null, nonInteraction : settings.nonInteraction, }) } }) } /** * Scroll watcher * @return {void} */ function onScroll() { if (settings.percentages) { percentageDepth() } if (settings.pixelDepthInterval) { pixelDepth() } if (settings.elements.length) { elements() } } /** * Set scrollw atcher * @return {void} */ function watch() { window.addEventListener('scroll', throttle(onScroll, settings.throttle), true) } if ( settings.scrollElement.scrollHeight > settings.scrollElement.clientHeight && settings.scrollElement.scrollHeight > settings.minHeight ) { watch() } }