Skip to content

Instantly share code, notes, and snippets.

@gleb-lobastov
Last active November 13, 2016 18:20
Show Gist options
  • Save gleb-lobastov/9d19c6e006179629daa30c37a80c46bb to your computer and use it in GitHub Desktop.
Save gleb-lobastov/9d19c6e006179629daa30c37a80c46bb to your computer and use it in GitHub Desktop.
Record user activity on scroll, move and click events
/**
* Record user activity on scroll, move and click events
* Collect bunches of events and prepare then to send to server
* @author Lobastov Gleb
*/
(function captorUnit() {
var App = {
startTime: new Date().getTime(),
events: [],
/**
* Flushes all data from all captors to the server
*/
flush: function () {
var captures = {};
this.events.forEach(function (eventCaptor) {
captures[eventCaptor.eventName] = eventCaptor.collect();
});
console.log('send to server');
console.dir(captures);
}
};
/**
* EventCaptor is a constructor responsible for collecting and store events on clients before buffer
* is overflow, then it raises App.flush event which flushes all data from all captors to the server.
*
* @param options
* @param options.bunchSize
* Omitting that option means that event will never cause data flushing to server by itself.
* @param options.delay
* Omitting that option means that every event will be captured
* @param options.eventName
* @param options.fn Function that receive event and returns value characterizing event to save.
* @constructor
*/
function EventCaptor(options) {
var self = this;
App.events.push(this);
this.bunchSize = options.bunchSize;
this.captured = [];
this.enabled = true;
this.eventName = options.eventName;
this.delay = options.delay;
this.fn = options.fn;
this.lastEvent = undefined;
window.addEventListener(options.eventName, function (event) {
self.capture(event);
});
}
/**
* Handles every suitable event, and save value characterizing it to buffer, except case when delay is setup.
* In case with delay is on it handles only last event in each period, then add last value to buffer.
*
* @param event
*/
EventCaptor.prototype.capture = function (event) {
var self = this;
if (this.delay) {
this.lastEvent = event;
if (this.enabled) {
this.enabled = false;
setTimeout(function () {
self.save(self.extractData(self.lastEvent));
self.enabled = true;
}, this.delay)
}
} else {
this.save(this.extractData(event));
}
};
/**
* Calculate value chatacterizing event and append service data.
* Currently append time offset from page load.
*
* @param event
* @returns {{value: *, timeOffset: number}}
*/
EventCaptor.prototype.extractData = function (event) {
return {
value: this.fn(event),
timeOffset: new Date().getTime() - App.startTime
}
};
/**
* Save eventData to buffer and flush it to server when buffer becomes overflow
* @param eventData
*/
EventCaptor.prototype.save = function (eventData) {
this.captured.push(eventData);
if (this.bunchSize && this.captured.length >= this.bunchSize) {
App.flush();
}
};
/**
* Extract all items from buffer and leaves it clear
* @returns {Array}
*/
EventCaptor.prototype.collect = function () {
var captured = this.captured;
this.captured = [];
return captured;
};
new EventCaptor({
bunchSize: 5,
delay: 500,
eventName: 'scroll',
fn: function () {
return window.pageYOffset || document.documentElement.scrollTop
}
});
new EventCaptor({
bunchSize: 25,
delay: 200,
eventName: 'mousemove',
fn: function (event) {
return {
x: event.screenX,
y: event.screenY
}
}
});
new EventCaptor({
eventName: 'click',
fn: function (event) {
return {
x: event.screenX,
y: event.screenY
}
}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment