var govScroll = { measurements: { initial: {}, current: {}, max: {}, }, config: { hasMilestoneOccurred: { 25: false, // false indicates it has not fired, but should; true indicates it already has (or shouldn't) 50: false, 60: false, 75: false, 100: false } }, // Calculate content height (docHeight), viewport height (winHeight), and trackLength getMeasurements: function () { var retval = {}; // external dimensions of window/browser retval.outerHeight = window.outerHeight; // internal dimensions (viewport) retval.innerHeight = (document.documentElement || document.body).clientHeight || window.innerHeight; retval.innerHeight = (window.pageYOffset || window.document.documentElement.scrollTop || window.document.body.scrollTop) + retval.innerHeight; // actual page dimensions (account for margins, scrollbars, etc) retval.pageHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); retval.pctFromTop = Math.round((retval.innerHeight / retval.pageHeight) * 100); return retval; }, getMaxMeasurements: function (payload) { var retval = {}; for (key in payload) { retval[key] = (payload[key] > this.measurements.max[key]) ? payload[key] : this.measurements.max[key]; } return retval; }, getCurrentStatus: function () { this.measurements.current = this.getMeasurements(); this.measurements.max = this.getMaxMeasurements(this.measurements.current); this.getMilestoneProgress(this.measurements.current.pctFromTop); }, getMilestoneProgress: function (currentPctViewed) { for (milestone in this.config.hasMilestoneOccurred) { if ((currentPctViewed >= milestone) && !this.config.hasMilestoneOccurred[milestone]) { this.trackMilestone(milestone); } } }, setMilestoneProgress: function (milestone) { if (milestone) { this.config.hasMilestoneOccurred[milestone] = true; } else { for (key in this.config.hasMilestoneOccurred) { if (this.measurements.initial.pctFromTop >= key) { this.config.hasMilestoneOccurred[key] = true; } } } }, trackMilestone: function (milestone) { console.log("TRACKING MILESTONE:", milestone, this.measurements.current); // consider a launch direct call rule here: _satellite.trackScroll({milestone: milestone}); this.setMilestoneProgress(milestone); }, init: function () { this.measurements.initial = this.measurements.current = this.measurements.max = this.getMeasurements(); this.setMilestoneProgress(); console.log(this.config, this.measurements); } } govScroll.init(); var scrollTimer = setTimeout(function () { if (govScroll.config.hasMilestoneOccurred[60]) { console.log("TRACKING TIME+MILESTONE GOAL"); // consider a launch direct call rule here } else { console.log("TIME PASSED, BUT NO MILESTONE"); } }, 5000); window.addEventListener("scroll", function () { clearTimeout(throttleScroll); // throttle code inside scroll to once every 50 milliseconds var throttleScroll = setTimeout(function () { govScroll.getCurrentStatus(); }, 50); }, false);