Created
September 6, 2017 09:10
-
-
Save alasdairham/90debd8b325ba310dc67695815ac650b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * | |
| * Eg. SEND_INTERVAL = 3000; CAPTURE_INTERVAL = 50 | |
| * | |
| * - Capture mousemove & mousedown event after every 50 ms | |
| * - For each captured mouse event, save it into a local cache object | |
| * - After every 3 seconds, sends the cached mouse event history to server, | |
| * then clear cache. Exceptions are: | |
| * 1. A click event triggers data submission to server (as described above) immediately | |
| * 2. Pause sending data to server when there is no new movement, | |
| * e.g, when the last mouse event happens earlier than 3s ago (if data submission interval is 3s) | |
| */ | |
| (function() { | |
| var SEND_INTERVAL = 3000; // interval of data upload to server | |
| var CAPTURE_INTERVAL = 50; // interval of capturing a mouse event | |
| var MAX_SAVED = (1000/CAPTURE_INTERVAL) * (SEND_INTERVAL/1000); // max size of data cache | |
| var MouseCache = { | |
| saved: [], | |
| add: function(mouse) { | |
| if (this.saved.length >= MAX_SAVED) | |
| this.saved.shift(); | |
| this.saved.push(mouse); | |
| }, | |
| clear: function() { | |
| this.saved = []; | |
| } | |
| }; | |
| var MouseTracker = { | |
| dom: null, | |
| user_agent: navigator.userAgent, | |
| ip: undefined, | |
| last_mouse: {x: 0, y:0, ts: 0}, | |
| track_document: function () { | |
| this.dom = document.scrollingElement; | |
| this.dom.onmousedown = this.handle_mouse_event.bind(this); | |
| this.dom.onmousemove = this.handle_mouse_event.bind(this); | |
| }, | |
| handle_mouse_event: function(evt) { | |
| getType = function() { | |
| switch(tagName) { | |
| case 'INPUT': return evt.target.type; | |
| case 'BUTTON': return 'button'; | |
| case 'A': return 'hyperlink'; | |
| } | |
| }; | |
| var tagName = evt.target.tagName; | |
| if (Date.now() - this.last_mouse.ts >= CAPTURE_INTERVAL) { | |
| if (evt.type === 'mousedown') { | |
| this.last_mouse = this.parse_evt(evt, { | |
| isClick: true, | |
| type: getType(), | |
| target: tagName === 'A' ? evt.target.href : '', | |
| text: evt.target.innerText.length > 100 ? "": evt.target.innerText || evt.target.value// possibly clicked the background if target text is too long | |
| }); | |
| send_to_server(); // don't miss out any click event | |
| } else if (evt.type == 'mousemove'){ | |
| this.last_mouse = this.parse_evt(evt, {isClick: false}); | |
| } | |
| MouseCache.add(this.last_mouse); | |
| } | |
| }, | |
| parse_evt: function(evt, additional) { | |
| var parsed = { | |
| x: evt.clientX, | |
| y: evt.clientY + this.dom.scrollTop, | |
| ts: Date.now(), | |
| w: this.dom.scrollWidth, | |
| h: this.dom.scrollHeight, | |
| url: window.location.href | |
| }; | |
| for (var add in additional) if (additional.hasOwnProperty(add)) parsed[add] = additional[add]; | |
| return parsed; | |
| }, | |
| to_json: function() { | |
| return { | |
| ip: this.ip, | |
| user_agent: this.user_agent, | |
| data: MouseCache.saved | |
| } | |
| }, | |
| has_moved: function () { | |
| return (Date.now() - this.last_mouse.ts)/1000 <= SEND_INTERVAL/1000; | |
| } | |
| }; | |
| function find_user_ip(callback) { | |
| var url = location.protocol === 'https:' ? 'https://api.ipify.org?format=json' : 'http://myexternalip.com/json'; | |
| var http = new XMLHttpRequest(); | |
| http.onreadystatechange = function() { | |
| if (this.readyState == 4 && this.status == 200) { | |
| MouseTracker.ip = JSON.parse(http.responseText)['ip']; | |
| callback(true); | |
| } else { | |
| callback(false); | |
| } | |
| }; | |
| http.open('GET', url); | |
| http.send(); | |
| } | |
| function send_to_server(){ | |
| if (!MouseTracker.has_moved()) return; | |
| var url = 'https://example_php_url.php'; | |
| var payload = MouseTracker.to_json(); | |
| var http = new XMLHttpRequest(); | |
| http.onreadystatechange = function() { | |
| if (this.readyState == 4 && this.status == 200) { | |
| // pass | |
| } | |
| }; | |
| http.open('POST', url, true); | |
| http.send(JSON.stringify(payload)); | |
| MouseCache.clear(); | |
| } | |
| function check_cache() { | |
| if (MouseCache.saved.length !== 0) { | |
| send_to_server() | |
| } | |
| } | |
| /***************** BEGIN *****************/ | |
| document.addEventListener("DOMContentLoaded", function(event) { | |
| find_user_ip(function(succ) { | |
| if (succ) { | |
| MouseTracker.track_document(); | |
| setInterval(send_to_server, SEND_INTERVAL); | |
| } | |
| }); | |
| }); | |
| window.addEventListener('beforeunload', check_cache) | |
| })() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment