Commit 293999ec by James Ooi

Implement scroll depth tracking

parent 47371880
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
<script src="build/foresight.js"></script> <script src="build/foresight.js"></script>
<script> <script>
new Foresight().start(); new Foresight();
</script> </script>
</html> </html>
\ No newline at end of file
/*! /**!
* Foresight * Foresight
* *
* @author James Ooi <james.ooi@forefront.com.my> * @author James Ooi <james.ooi@forefront.com.my>
...@@ -39,6 +39,7 @@ interface EventData { ...@@ -39,6 +39,7 @@ interface EventData {
action: string action: string
label: string label: string
interaction: boolean interaction: boolean
value?: string | number | null | undefined,
metrics?: { [key: string]: any } metrics?: { [key: string]: any }
dimensions?: { [key: string]: any } dimensions?: { [key: string]: any }
} }
...@@ -49,10 +50,6 @@ interface EventData { ...@@ -49,10 +50,6 @@ interface EventData {
*/ */
class Foresight { class Foresight {
/**
* Default Options
* @static
*/
static defaultOptions: Partial<ForesightConfig> = { static defaultOptions: Partial<ForesightConfig> = {
defer: false, defer: false,
observerOptions: {}, observerOptions: {},
...@@ -68,8 +65,8 @@ class Foresight { ...@@ -68,8 +65,8 @@ class Foresight {
options: ForesightConfig; options: ForesightConfig;
/** /**
* Stores a mapping of elements with is respective functions to de-register * Stores a mapping of elements with its respective functions to de-register
* listeners. * the listeners.
* @private * @private
*/ */
private _untrackFns: Map<Element, { click: Function, view: Function }> = new Map(); private _untrackFns: Map<Element, { click: Function, view: Function }> = new Map();
...@@ -81,6 +78,18 @@ class Foresight { ...@@ -81,6 +78,18 @@ class Foresight {
private _observer: IntersectionObserver = null; private _observer: IntersectionObserver = null;
/** /**
* Store the current maximum page scroll amount.
* @private
*/
private _maxScrollY: number = 0;
/**
* Indicates that the scroll tracker has already been initialised
* @private
*/
private _scrollTrackerInitialised: boolean = false;
/**
* @constructor * @constructor
*/ */
constructor(config: ForesightConfig = {}) { constructor(config: ForesightConfig = {}) {
...@@ -115,6 +124,15 @@ class Foresight { ...@@ -115,6 +124,15 @@ class Foresight {
Utils Utils
.toArray<Element>(root.querySelectorAll('[data-track], [data-track-view]')) .toArray<Element>(root.querySelectorAll('[data-track], [data-track-view]'))
.map(element => this.track(element)); .map(element => this.track(element));
if (!this._scrollTrackerInitialised) {
const maxScrollListener = Utils.debounce(() => this._onScroll());
window.addEventListener('scroll', maxScrollListener, { passive: true });
this._onScroll(); // call once
this._scrollTrackerInitialised = true;
}
window.addEventListener('beforeunload', (e) => this._onUnload(e));
} }
/** /**
...@@ -221,7 +239,7 @@ class Foresight { ...@@ -221,7 +239,7 @@ class Foresight {
* @private * @private
*/ */
private _trackClicks(element: Element): Function { private _trackClicks(element: Element): Function {
// Define listen fucntion // Define listen function
const listener = (e) => this._onTrackedClick(element, e); const listener = (e) => this._onTrackedClick(element, e);
element.addEventListener('click', listener); element.addEventListener('click', listener);
...@@ -335,6 +353,28 @@ class Foresight { ...@@ -335,6 +353,28 @@ class Foresight {
this.send(<EventData> data); this.send(<EventData> data);
} }
/**
* Handles a scroll event
*/
private _onScroll(root = document.documentElement) {
const vh = Math.max(root.clientHeight, window.innerHeight || 0);
const scrollY = root.scrollTop + vh;
if (scrollY > this._maxScrollY) {
this._maxScrollY = scrollY;
}
}
private _onUnload(e: Event) {
const scrollData: EventData = {
category: 'general',
action: 'scroll y',
label: window.location.pathname,
interaction: false,
value: Math.floor((this._maxScrollY / document.body.clientHeight) * 100)
}
this.send(scrollData);
}
} }
export = Foresight; export = Foresight;
/**
* Returns a debounced function that as long as it continues to be invoked,
* will not be triggered until it stops being called for N milliseconds.
*/
function debounce(func: Function, wait = 300) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
}
export default debounce;
export { debounce };
export { default as toArray } from './toArray'; export { default as toArray } from './toArray';
\ No newline at end of file export { default as debounce } from './debounce';
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment