-
Notifications
You must be signed in to change notification settings - Fork 543
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #292 from ct-martin/heatmap
Basic heatmap example
- Loading branch information
Showing
5 changed files
with
147 additions
and
13 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<!DOCTYPE html> | ||
<meta charset="utf-8"> | ||
<head> | ||
<title>Webgazer.js + heatmap.js demo</title> | ||
<style> | ||
/* Make sure everything in body can go to the edge of the page */ | ||
/* Particularly, Chrome's default styles have an 8px margin for the body */ | ||
html, body { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
/* Make body take up entire page */ | ||
body, #content { | ||
width: 100vw; | ||
height: 100vh; | ||
} | ||
/* Make the image autoscale to the page */ | ||
#content { | ||
object-fit: contain; | ||
} | ||
/* Put the heatmap on top of the image */ | ||
#heatmapContainer { | ||
/* The heatmap will set its own size to the window's via JS */ | ||
z-index: 10; | ||
position: fixed !important; | ||
top: 0; | ||
left: 0; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<img id="content" src="media/example/starrynight.jpg" /> | ||
<div id="heatmapContainer"></div> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/localforage/1.8.1/localforage.js"></script> | ||
<script src="./webgazer.js"></script> | ||
<script src="./node_modules/heatmap.js/build/heatmap.min.js"></script> | ||
<script src="js/heatmap-demo.js"></script> | ||
</body> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// Set to true if you want to save the data even if you reload the page. | ||
window.saveDataAcrossSessions = false; | ||
|
||
// heatmap configuration | ||
const config = { | ||
radius: 25, | ||
maxOpacity: .5, | ||
minOpacity: 0, | ||
blur: .75 | ||
}; | ||
|
||
// Global variables | ||
let heatmapInstance; | ||
|
||
window.addEventListener('load', async function() { | ||
// Init webgazer | ||
if (!window.saveDataAcrossSessions) { | ||
var localstorageDataLabel = 'webgazerGlobalData'; | ||
localforage.setItem(localstorageDataLabel, null); | ||
var localstorageSettingsLabel = 'webgazerGlobalSettings'; | ||
localforage.setItem(localstorageSettingsLabel, null); | ||
} | ||
const webgazerInstance = await webgazer.setRegression('ridge') /* currently must set regression and tracker */ | ||
.setTracker('TFFacemesh') | ||
.begin(); | ||
|
||
// Turn off video | ||
webgazerInstance.showVideoPreview(false) /* shows all video previews */ | ||
.showPredictionPoints(false); /* shows a square every 100 milliseconds where current prediction is */ | ||
|
||
// Enable smoothing | ||
webgazerInstance.applyKalmanFilter(true); // Kalman Filter defaults to on. | ||
|
||
// Set up heatmap parts | ||
setupHeatmap(); | ||
webgazer.setGazeListener( eyeListener ); | ||
}); | ||
|
||
window.addEventListener('beforeunload', function() { | ||
if (window.saveDataAcrossSessions) { | ||
webgazer.end(); | ||
} else { | ||
localforage.clear(); | ||
} | ||
}); | ||
|
||
// Trimmed down version of webgazer's click listener since the built-in one isn't exported | ||
// Needed so we can have just the click listener without the move listener | ||
// (The move listener was creating a lot of drift) | ||
async function clickListener(event) { | ||
webgazer.recordScreenPosition(event.clientX, event.clientY, 'click'); // eventType[0] === 'click' | ||
} | ||
|
||
function setupHeatmap() { | ||
// Don't use mousemove listener | ||
webgazer.removeMouseEventListeners(); | ||
document.addEventListener('click', clickListener); | ||
|
||
// Get the window size | ||
let height = window.innerHeight; | ||
let width = window.innerWidth; | ||
|
||
// Set up the container | ||
let container = document.getElementById('heatmapContainer'); | ||
container.style.height = `${height}px`; | ||
container.style.width = `${width}px`; | ||
config.container = container; | ||
|
||
// create heatmap | ||
heatmapInstance = h337.create(config); | ||
} | ||
|
||
// Heatmap buffer | ||
let lastTime; | ||
let lastGaze; | ||
|
||
async function eyeListener(data, clock) { | ||
// data is the gaze data, clock is the time since webgazer.begin() | ||
|
||
// Init if lastTime not set | ||
if(!lastTime) { | ||
lastTime = clock; | ||
} | ||
|
||
// In this we want to track how long a point was being looked at, | ||
// so we need to buffer where the gaze moves to and then on next move | ||
// we calculate how long the gaze stayed there. | ||
if(!!lastGaze) { | ||
if(!!lastGaze.x && !!lastGaze.y) { | ||
let duration = clock-lastTime; | ||
let point = { | ||
x: Math.floor(lastGaze.x), | ||
y: Math.floor(lastGaze.y), | ||
value: duration | ||
} | ||
heatmapInstance.addData(point); | ||
} | ||
} | ||
|
||
lastGaze = data; | ||
lastTime = clock; | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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