blinker / firefox.plugin / data / scripts / myscript.js @ 76dd22bd
History | View | Annotate | Download (28.319 KB)
1 |
/*
|
---|---|
2 |
* Copyright 2015 Thies Pfeiffer and Dimitri Heil and Kevin Taron
|
3 |
* Blinker is distributed under the terms of the GNU General Public License
|
4 |
*
|
5 |
* This file is part of Blinker.
|
6 |
*
|
7 |
* Blinker is free software: you can redistribute it and/or modify
|
8 |
* it under the terms of the GNU General Public License as published by
|
9 |
* the Free Software Foundation, either version 3 of the License, or
|
10 |
* (at your option) any later version.
|
11 |
*
|
12 |
* Blinker is distributed in the hope that it will be useful,
|
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
* GNU General Public License for more details.
|
16 |
*
|
17 |
* You should have received a copy of the GNU General Public License
|
18 |
* along with Blinker. If not, see <http://www.gnu.org/licenses/>.
|
19 |
*/
|
20 |
|
21 |
//do not execute pagemod in iframes
|
22 |
if (window.location == window.parent.location) {
|
23 |
|
24 |
|
25 |
/*
|
26 |
* Append the DOM Observer to listen for new elements that are being attached
|
27 |
*/
|
28 |
var observer = new MutationObserver(function (mutations) { |
29 |
|
30 |
mutations.forEach(function (mutation) {
|
31 |
|
32 |
if (mutation.type == "childList"){ |
33 |
for (var c = 0;c< mutation.addedNodes.length;c++){ |
34 |
if ($(mutation.addedNodes.item(c)).data("gaze") !== undefined){ |
35 |
|
36 |
/*
|
37 |
* if a dom change is observed and the change is of type 'childlist'
|
38 |
* send all the new nodes to the gazeEvent appender
|
39 |
*/
|
40 |
appendGazeEvents(mutation.addedNodes.item(c)); |
41 |
} |
42 |
} |
43 |
} |
44 |
//console.log("MutationType: "+mutation.type);
|
45 |
}); |
46 |
}); |
47 |
|
48 |
/*
|
49 |
* Set some observer options
|
50 |
*/
|
51 |
observer.observe(document.body, { |
52 |
attributes: true, |
53 |
childList:true, |
54 |
characterData: true, |
55 |
characterDataOldValue: true, |
56 |
subtree: true |
57 |
}); |
58 |
|
59 |
|
60 |
|
61 |
|
62 |
/*
|
63 |
* Append gaze-gesture divs to the body (4 point gaze)
|
64 |
*/
|
65 |
var gesturedata = "{\"gazeEnter\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureTopLeft\\\").css(\\\"backgroundColor\\\",\\\"#053e46\\\"); gestureTimer = Date.now(); if (lastGesture != \\\"1\\\" ) {gestureString += \\\"1\\\"; lastGesture=\\\"1\\\"; } \"},\"gazeLeave\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureTopLeft\\\").css(\\\"backgroundColor\\\",\\\"#13D1EB\\\"); \"}}"; |
66 |
$("body").prepend("<div data-gaze='" + gesturedata + "' id='gestureTopLeft' class='gazeGestures'></div>"); |
67 |
gesturedata = "{\"gazeEnter\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureTopRight\\\").css(\\\"backgroundColor\\\",\\\"#053e46\\\"); gestureTimer = Date.now(); if (lastGesture != \\\"2\\\" ) {gestureString += \\\"2\\\"; lastGesture=\\\"2\\\";} \"},\"gazeLeave\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureTopRight\\\").css(\\\"backgroundColor\\\",\\\"#13D1EB\\\"); \"}}";
|
68 |
$("body").prepend("<div data-gaze='" + gesturedata + "' id='gestureTopRight' class='gazeGestures'></div>"); |
69 |
gesturedata = "{\"gazeEnter\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureBottomLeft\\\").css(\\\"backgroundColor\\\",\\\"#053e46\\\"); gestureTimer = Date.now(); if (lastGesture != \\\"3\\\" ) {gestureString += \\\"3\\\"; lastGesture=\\\"3\\\";} \"},\"gazeLeave\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureBottomLeft\\\").css(\\\"backgroundColor\\\",\\\"#13D1EB\\\"); \"}}";
|
70 |
$("body").prepend("<div data-gaze='" + gesturedata + "' id='gestureBottomLeft' class='gazeGestures'></div>"); |
71 |
gesturedata = "{\"gazeEnter\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureBottomRight\\\").css(\\\"backgroundColor\\\",\\\"#053e46\\\"); gestureTimer = Date.now(); if (lastGesture != \\\"4\\\" ) {gestureString += \\\"4\\\"; lastGesture=\\\"4\\\";} \"},\"gazeLeave\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#gestureBottomRight\\\").css(\\\"backgroundColor\\\",\\\"#13D1EB\\\"); \"}}";
|
72 |
$("body").prepend("<div data-gaze='" + gesturedata + "' id='gestureBottomRight' class='gazeGestures'></div>"); |
73 |
|
74 |
|
75 |
|
76 |
/*
|
77 |
* Append gazeLinks Div to the body links that are found by a linkFinding algorithm are put into this div
|
78 |
*/
|
79 |
$("body").prepend("<div id='gazeLinks'></div>"); |
80 |
|
81 |
/*
|
82 |
* Append the wheelselector to the body
|
83 |
*/
|
84 |
$("body").prepend("<div id='wheelSelector'></div>"); |
85 |
|
86 |
/*
|
87 |
* Append the calibration_blackout div to the body to darken the background in calibration mode
|
88 |
*/
|
89 |
$("body").prepend("<div id='calibration_blackout'></div>"); |
90 |
|
91 |
/*
|
92 |
* Needed for calibration checking when adjusting gaze position offset
|
93 |
*/
|
94 |
$("body").prepend("<div id='calibration_check'></div>"); |
95 |
|
96 |
|
97 |
/*
|
98 |
* Needed for BlickBrowser's own Notification
|
99 |
*/
|
100 |
var dstr = "{\"gazeEnter\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#notification\\\").stop();$(\\\"#notification\\\").fadeIn(10); \"},\"gazeLeave\": {\"funcType\":\"dynamic\",\"func\":\" $(\\\"#notification\\\").fadeOut(3000); \"}}"; |
101 |
$("body").prepend("<div id='notification' data-gaze='" + dstr + "' ></div>"); |
102 |
|
103 |
|
104 |
/*
|
105 |
* Needed for the progress circle
|
106 |
*/
|
107 |
$("body").prepend('<div id="gazeProgress"><input type="text" class="dial"></div>'); |
108 |
|
109 |
|
110 |
$("body").prepend("<div id='status'></div>"); |
111 |
//$("body").prepend("<div id='fixatedA'></div>");
|
112 |
$("body").prepend("<div id='controlBar' class='controlBar'></div>"); |
113 |
|
114 |
|
115 |
|
116 |
$("body").prepend("<canvas id='findLinkArea'>Your browser does not support the HTML5 canvas tag.</canvas>"); |
117 |
|
118 |
|
119 |
/*
|
120 |
* Needed for the crosshair
|
121 |
*/
|
122 |
$("body").prepend("<canvas id='crosshairTop' width='1' height='15'>Your browser does not support the HTML5 canvas tag.</canvas>"); |
123 |
$("body").prepend("<canvas id='crosshairBottom' width='1' height='15'>Your browser does not support the HTML5 canvas tag.</canvas>"); |
124 |
$("body").prepend("<canvas id='crosshairLeft' width='15' height='1'>Your browser does not support the HTML5 canvas tag.</canvas>"); |
125 |
$("body").prepend("<canvas id='crosshairRight' width='15' height='1'>Your browser does not support the HTML5 canvas tag.</canvas>"); |
126 |
|
127 |
/*
|
128 |
* Hide browser screen when it's not active
|
129 |
*/
|
130 |
$("body").prepend("<div id='noFocusHider' ></div>"); |
131 |
|
132 |
|
133 |
/*
|
134 |
* Styling the newly appended elements
|
135 |
*/
|
136 |
$("#fixatedA").css("backgroundColor", "#FFFFFF"); |
137 |
$("#fixatedA").css("display", "none"); |
138 |
$("#fixatedA").css("position", "fixed"); |
139 |
$("#fixatedA").css("padding", "10"); |
140 |
$("#fixatedA").css("border", "2px solid"); |
141 |
$("#fixatedA").css("border-bottom-color", "#000000"); |
142 |
$("#fixatedA").css("border-top-color", "#000000"); |
143 |
$("#fixatedA").css("border-left-color", "#000000"); |
144 |
$("#fixatedA").css("border-right-color", "#000000"); |
145 |
$("#fixatedA").css("border-radius", "10px"); |
146 |
$("#fixatedA").css("box-shadow", "5px 5px 2px"); |
147 |
$("#fixatedA").css("zIndex", 100000); |
148 |
|
149 |
$("#wheelSelector").css("display", "none"); |
150 |
$("#wheelSelector").css("backgroundColor", "#13D1EB"); |
151 |
$("#wheelSelector").css("position", "absolute"); |
152 |
$("#wheelSelector").css("left", ((window.innerWidth / 2) - 250) + "px"); |
153 |
$("#wheelSelector").css("zIndex", 120000); |
154 |
$("#wheelSelector").css("width", "500px"); |
155 |
$("#wheelSelector").css("height", "500px"); |
156 |
$("#wheelSelector").css("top", "10%"); |
157 |
$("#wheelSelector").css("border", "2px solid #FFFFFF"); |
158 |
$("#wheelSelector").css("border-radius", "250px"); |
159 |
|
160 |
$("#gazeLinks").css("display", "none"); |
161 |
$("#gazeLinks").css("position", "absolute"); |
162 |
$("#gazeLinks").css("zIndex", 100000); |
163 |
|
164 |
$("#noFocusHider").css("display", "none"); |
165 |
|
166 |
$("#controlBar").css("display", "none"); |
167 |
|
168 |
$("#status").css("position", "absolute"); |
169 |
$("#status").css("left", "0px"); |
170 |
$("#status").css("top", "0px"); |
171 |
$("#status").css("zIndex", 16777269); |
172 |
|
173 |
$("#calibration_blackout").css("backgroundColor", "#000000"); |
174 |
$("#calibration_blackout").css("width", "100%"); |
175 |
$("#calibration_blackout").css("height", "100%"); |
176 |
$("#calibration_blackout").css("overflow", "hidden"); |
177 |
$("#calibration_blackout").css("zIndex", 2147483640); |
178 |
$("#calibration_blackout").css("display", "none"); |
179 |
$("#calibration_blackout").css("position", "fixed"); |
180 |
$("#calibration_blackout").css("left", "0px"); |
181 |
$("#calibration_blackout").css("top", "0px"); |
182 |
|
183 |
$("#calibration_check").css("backgroundColor", "#000000"); |
184 |
$("#calibration_check").css("width", "100%"); |
185 |
$("#calibration_check").css("height", "100%"); |
186 |
$("#calibration_check").css("overflow", "hidden"); |
187 |
$("#calibration_check").css("zIndex", 2147483646); |
188 |
$("#calibration_check").css("display", "none"); |
189 |
$("#calibration_check").css("position", "fixed"); |
190 |
$("#calibration_check").css("left", "0px"); |
191 |
$("#calibration_check").css("top", "0px"); |
192 |
|
193 |
|
194 |
//activate indicator
|
195 |
$("#gazeProgress").css("position", "absolute"); |
196 |
$("#gazeProgress").css("display", "none"); |
197 |
$("#gazeProgress").css("zIndex", 2147483645); |
198 |
|
199 |
$("#findLinkArea").css("width", "300px"); |
200 |
$("#findLinkArea").css("height", "300px"); |
201 |
$("#findLinkArea").css("display", "none"); |
202 |
$("#findLinkArea").css("position", "absolute"); |
203 |
$("#findLinkArea").css("zIndex", 160000); |
204 |
|
205 |
|
206 |
/*
|
207 |
* Creating and positioning the crosshair
|
208 |
*/
|
209 |
var ctx = $("#crosshairTop")[0].getContext('2d'); |
210 |
ctx.rect(0, 0, 1, 15); |
211 |
ctx.fillStyle = "black";
|
212 |
ctx.fill(); |
213 |
|
214 |
ctx = $("#crosshairBottom")[0].getContext('2d'); |
215 |
ctx.rect(0, 0, 1, 15); |
216 |
ctx.fillStyle = "black";
|
217 |
ctx.fill(); |
218 |
|
219 |
ctx = $("#crosshairLeft")[0].getContext('2d'); |
220 |
ctx.rect(0, 0, 15, 1); |
221 |
ctx.fillStyle = "black";
|
222 |
ctx.fill(); |
223 |
|
224 |
ctx = $("#crosshairRight")[0].getContext('2d'); |
225 |
ctx.rect(0, 0, 15, 1); |
226 |
ctx.fillStyle = "black";
|
227 |
ctx.fill(); |
228 |
|
229 |
|
230 |
$("#crosshairTop").css("left", (100) + "px"); |
231 |
$("#crosshairTop").css("top", (100 - 16) + "px"); |
232 |
$("#crosshairTop").css("position", "absolute"); |
233 |
$("#crosshairTop").css("zIndex", 2000000140); |
234 |
|
235 |
$("#crosshairBottom").css("left", (100) + "px"); |
236 |
$("#crosshairBottom").css("top", (100 + 1) + "px"); |
237 |
$("#crosshairBottom").css("position", "absolute"); |
238 |
$("#crosshairBottom").css("zIndex", 2000000140); |
239 |
|
240 |
$("#crosshairLeft").css("left", (100 - 16) + "px"); |
241 |
$("#crosshairLeft").css("top", (100) + "px"); |
242 |
$("#crosshairLeft").css("position", "absolute"); |
243 |
$("#crosshairLeft").css("zIndex", 2000000140); |
244 |
|
245 |
$("#crosshairRight").css("left", (100 + 1) + "px"); |
246 |
$("#crosshairRight").css("top", (100) + "px"); |
247 |
$("#crosshairRight").css("position", "absolute"); |
248 |
$("#crosshairRight").css("zIndex", 2000000140); |
249 |
|
250 |
ctx = $("#findLinkArea")[0].getContext('2d'); |
251 |
ctx.rect(0, 0, 300, 300); |
252 |
ctx.strokeStyle = "red";
|
253 |
ctx.lineWidth = "2";
|
254 |
ctx.stroke(); |
255 |
|
256 |
|
257 |
//################################## VARIABLES #################################
|
258 |
|
259 |
//JQNOTIFY settings
|
260 |
$.notify.defaults({position: "top center"}); |
261 |
|
262 |
|
263 |
var blickBrowserSettings;
|
264 |
|
265 |
/*
|
266 |
* Needed for gazeCorrection offset
|
267 |
*/
|
268 |
var recordGazeData = false; |
269 |
var recordedGazeData = [];
|
270 |
|
271 |
var gazeCorrectionMode = false; |
272 |
var gazeCorrectionData = [];
|
273 |
var gazeCorrection = { x: 0, y: 0 }; |
274 |
var gazeCorrectionTimerStart;
|
275 |
var gazeCorrectionDuration = 1000; |
276 |
var gazeCorrectionValues = [];
|
277 |
var gazeCorrectionPointNr = 0; |
278 |
var gazeCorrectionQuantity = 4; |
279 |
var gazeCorrectionPoints = [];
|
280 |
var gazeCorrectionX = 0; |
281 |
var gazeCorrectionY = 0; |
282 |
var gc_left, gc_right, gc_top, gc_bottom = 0; |
283 |
|
284 |
|
285 |
/*
|
286 |
* Notify the user, that the browser has to be in full screen mode to start calibrating
|
287 |
*/
|
288 |
var showFullscreenMessageForCalibration = true; |
289 |
|
290 |
/*
|
291 |
* Prevent sending multiple calibration requests when waiting for the first one
|
292 |
*/
|
293 |
var calibrationRequestSent = false; |
294 |
|
295 |
/*
|
296 |
* The calibration results are saved here when requesting the EYETRIBE status on page load / activate
|
297 |
*/
|
298 |
var calibrationResult;
|
299 |
|
300 |
|
301 |
/*
|
302 |
* point counter in calibration array
|
303 |
*/
|
304 |
var calibrationStart = 0; |
305 |
|
306 |
|
307 |
/*
|
308 |
* 4 point gaze gesture variables
|
309 |
*/
|
310 |
var gestureTimer = Date.now();
|
311 |
var gestureString = ""; |
312 |
var gestureMode = false; |
313 |
var lastGesture = ""; |
314 |
|
315 |
|
316 |
/*
|
317 |
* prevents toggling reading / browsing mode more than 1 time per second
|
318 |
*/
|
319 |
var modeToggleCounter = 0; |
320 |
|
321 |
//wheter gazeLinks are showing
|
322 |
var gazeLinksShowing = false; |
323 |
var gazeLinkOptionsShowing = false; |
324 |
|
325 |
//wheter controlBar is showing
|
326 |
var controlBarShowing = false; |
327 |
|
328 |
//wheter wheelselector is showing
|
329 |
var wheelSelectorShowing = false; |
330 |
|
331 |
//whether eyetracker has been set up while initializing - False if it's set up.
|
332 |
var firstRun = true; |
333 |
|
334 |
//if a message has been sent to the tracker and a request is awaited
|
335 |
var waitingForResponse = false; |
336 |
|
337 |
//show the follow me message when calibration is run and the crosshair is shown
|
338 |
var showFollowMeMessageAtCalibration = true; |
339 |
|
340 |
//take average values from EYETRIBE eyetracking data?
|
341 |
var average = true; |
342 |
|
343 |
|
344 |
//####################### INSIDE WINDOW OFFSET CALCULATION #####################
|
345 |
|
346 |
var xOffset = 0; |
347 |
var yOffset = 0; |
348 |
|
349 |
var browserDecorationThickness = (window.outerWidth - window.innerWidth) / 2; |
350 |
console.log("browserDecorationThickness: "+browserDecorationThickness);
|
351 |
var browserTopBarsHeight = window.outerHeight - browserDecorationThickness - window.innerHeight;
|
352 |
console.log("browserTopBarsHeight: "+browserTopBarsHeight);
|
353 |
//################################# SMI #####################################
|
354 |
var iViewXAPI = null; |
355 |
|
356 |
//##################### CALIBRATION VARIABLES #####################
|
357 |
//the array where the recalibration points will be put
|
358 |
var calibrationArray = [];
|
359 |
|
360 |
var overflowXBeforeCalibration;
|
361 |
var overflowYBeforeCalibration;
|
362 |
//32 is half of calibrationImage
|
363 |
var calibrationIconSizeHalf = 32; |
364 |
|
365 |
//distance of calibrationImage from borders (in pixel)
|
366 |
var distanceFromBorder = 100; |
367 |
|
368 |
//the calibration grid for 3 x 3 calibration
|
369 |
var topRow, midRow, bottomRow = 0; |
370 |
var leftCol, midCol, rightCol = 0; |
371 |
var recalibrationArray = [];
|
372 |
var calibrationPointNumber = 1; |
373 |
|
374 |
|
375 |
var gazeTimer = 0; |
376 |
var linkCheckRunning = false; |
377 |
eyeTribe.setCalibrationParameters(); |
378 |
|
379 |
//initiate calibration timer
|
380 |
var calibrationTimer = "null"; |
381 |
|
382 |
//variable for checking what should be parsed from the eyetracking frame data
|
383 |
var calibrationRunning = false; |
384 |
var eyeTrackerIsCalibrated = false; |
385 |
var eyeTrackerIsCalibrating = false; |
386 |
var pushMode = "notSet"; |
387 |
|
388 |
/*
|
389 |
* Asynchronous toggling of the linkFinding algorithms every 1000ms
|
390 |
* (or more if algorithm is still running after 1000ms)
|
391 |
*/
|
392 |
var checkForLinksInterval;
|
393 |
checkForLinksInterval = setInterval(function() {
|
394 |
if (document.hasFocus()) {
|
395 |
gazeFunctions.checkForLinks(); |
396 |
} |
397 |
}, 1000);
|
398 |
|
399 |
//move the status div with the mouse
|
400 |
window.onmousemove = mousemoved; |
401 |
|
402 |
//needed for collecting gazePositions for smoothing
|
403 |
var gazeCollection = [];
|
404 |
|
405 |
//###################### GAZE INFORMATION JSON VARIABLE ###################
|
406 |
|
407 |
var gazeInformation = {
|
408 |
"x": 0, //the actual x value |
409 |
"y": 0, //the actual y value |
410 |
"previousX": 0, //last x value |
411 |
"previousY": 0, //last y value |
412 |
"isFixation": false, //eyetribe built in fixation algorithm |
413 |
"fixationStart": 0, //unix time when actual fixation started |
414 |
"fixationPositionAtStart": {
|
415 |
x: 0, |
416 |
y: 0 |
417 |
}, // x|y of gaze position when fixation started
|
418 |
"elementBelow": null, //actual element under gaze at x/y |
419 |
"fixatedElement": null, //actually fixated object |
420 |
"lastElementBelow": null, //last fixated object |
421 |
"currentElementFixatedAt": Date.now(), //unix time when fixation started |
422 |
"fixatedOptionsDialogPosition": {
|
423 |
x: 0, |
424 |
y: 0 |
425 |
}, //for calculating the distance of mouse - optionsDiv
|
426 |
"gazeLinksPosition": {
|
427 |
x: 0, |
428 |
y: 0 |
429 |
}, //position of link list
|
430 |
"gazeLinks": [], //array of all links |
431 |
"gazeLinkName": null, |
432 |
"gazeLinkSource": null, |
433 |
"selectedGazeLink": null, |
434 |
"gazeMoveStartPoint": {"x": 0,"y":0}, // auto readingmode reference point |
435 |
"gazeMoveStartTime": Date.now(), // auto readingmode duration |
436 |
}; |
437 |
|
438 |
|
439 |
|
440 |
//##################### EVENT CREATION AND APPENDING #####################
|
441 |
|
442 |
var gazeEnter = new Event('gazeEnter'); |
443 |
var gazeLeave = new Event('gazeLeave'); |
444 |
var gazeOver = new Event('gazeOver'); |
445 |
var isFixated = new Event('isFixated'); |
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
//################### COMMUNICATION WITH ADDON ###################
|
455 |
|
456 |
|
457 |
/*
|
458 |
* Listen for the calibrationImage being transmitted
|
459 |
*/
|
460 |
self.port.on("calibrationImage", function(imgurl) { |
461 |
$("body").prepend("<img id='calibrationImage' src='" + imgurl + "' />"); |
462 |
$("#calibrationImage").css("position", "absolute"); |
463 |
$("#calibrationImage").css("left", "50%"); |
464 |
$("#calibrationImage").css("top", "50%"); |
465 |
$("#calibrationImage").css("display", "none"); |
466 |
$("#calibrationImage").css("zIndex", 2147483647); //1 level above calibration_blackout |
467 |
|
468 |
}); |
469 |
|
470 |
|
471 |
/*
|
472 |
* Listen for the privateMode image being transmitted
|
473 |
*/
|
474 |
self.port.on("holeImage", function(imgurl) { |
475 |
$("body").prepend("<img id='holeImageFile' src='" + imgurl + "' />"); |
476 |
$("#holeImageFile").hide(); |
477 |
$("body").prepend("<div id='holeImage'></div>"); |
478 |
$("#holeImage").css("display", "none"); |
479 |
$("#holeImage").css("background-image", "url(" + $("#holeImageFile").attr('src') + ")"); |
480 |
$("#holeImage").css("position", "fixed"); |
481 |
$("#holeImage").css("width", "100%"); |
482 |
$("#holeImage").css("height", "100%"); |
483 |
$("#holeImage").css("zIndex", 16777272); //2 level above calibration_blackout |
484 |
|
485 |
}); |
486 |
|
487 |
/*
|
488 |
* Listen for external calibration initialization
|
489 |
*/
|
490 |
self.port.on("startCalibration", function(message) { |
491 |
//console.log("initiate calibration");
|
492 |
eyeTribe.initiateCalibration(); |
493 |
|
494 |
}); |
495 |
|
496 |
|
497 |
/*
|
498 |
* Listen for external gaze offset calibration initialization
|
499 |
*/
|
500 |
self.port.on("checkCalibration", function(message) { |
501 |
//console.log("initiate calibration");
|
502 |
checkCalibration(); |
503 |
|
504 |
}); |
505 |
|
506 |
|
507 |
/*
|
508 |
* initialize eyetribe calibration parameters
|
509 |
*/
|
510 |
self.port.on("initializeEyeTribe", function(message) { |
511 |
//console.log("abort running calibration");
|
512 |
//abortRunningCalibration();
|
513 |
//console.log("get tracker status");
|
514 |
//initializeEyeTracker();
|
515 |
eyeTribe.getTrackerStatus(); |
516 |
|
517 |
}); |
518 |
|
519 |
|
520 |
/*
|
521 |
* ##########################################################################################
|
522 |
* Listen for gazeData Messages and call the proper handler accordingly to current eyetracker
|
523 |
* ##########################################################################################
|
524 |
*/
|
525 |
|
526 |
|
527 |
/*
|
528 |
* If eyetracker is eyetribe - send gazeData to eyetribe handler
|
529 |
*/
|
530 |
self.port.on("eyeTrackerData", function(message) { |
531 |
|
532 |
var messages;
|
533 |
|
534 |
// for debugging the gaze history can be set to 12345 to stop listening to the gazedata and stop
|
535 |
if (blickBrowserSettings.gazeSmoothingHistory !== 12345) { |
536 |
if (message.search(/}\n{/) > -1) { |
537 |
//split multiple messages from eyetribe server and send them on by one at a time
|
538 |
messages = message.split(/\n/);
|
539 |
|
540 |
for (var v = 0; v < messages.length; v++) { |
541 |
|
542 |
if (messages[v].length > 5) { |
543 |
|
544 |
eyeTribe.parseMessage(messages[v]); |
545 |
|
546 |
|
547 |
} |
548 |
} |
549 |
|
550 |
} else {
|
551 |
|
552 |
eyeTribe.parseMessage(message); |
553 |
|
554 |
} |
555 |
} |
556 |
|
557 |
|
558 |
if (!document.hasFocus()) {
|
559 |
//console.log("no focus.");
|
560 |
if (blickBrowserSettings.hideOnFocusLost === true) { |
561 |
$("#noFocusHider").css("display", "block"); |
562 |
} |
563 |
} else {
|
564 |
$("#noFocusHider").css("display", "none"); |
565 |
} |
566 |
|
567 |
}); |
568 |
|
569 |
|
570 |
/*
|
571 |
* if message comes from REDm, route it directly to gazeCalculation
|
572 |
*/
|
573 |
self.port.on("smiData", function(message) { |
574 |
calcGazePosition(message); |
575 |
}); |
576 |
|
577 |
/*
|
578 |
* if message comes from MyGaze, route it directly to gazeCalculation
|
579 |
*/
|
580 |
self.port.on("myGazeData", function(message) { |
581 |
calcGazePosition(message); |
582 |
}); |
583 |
|
584 |
|
585 |
/*
|
586 |
* Listen for external settings changes
|
587 |
*/
|
588 |
self.port.on("blickBrowserSettings", function(settings) { |
589 |
blickBrowserSettings = eval(settings); |
590 |
$(function() { |
591 |
$(".dial").knob({ |
592 |
'min': 0, |
593 |
'max': blickBrowserSettings.fixationThreshold,
|
594 |
'readOnly': true, |
595 |
'displayInput': false, |
596 |
'fgColor': '#13D1EB', |
597 |
'bgColor': '#000000', |
598 |
'width': 30 |
599 |
}); |
600 |
}); |
601 |
$.notify("Settings updated","success"); |
602 |
|
603 |
if (blickBrowserSettings.eyeTracker === "eyetribe"){ |
604 |
window.onresize = eyeTribe.setCalibrationParameters(); |
605 |
} |
606 |
//show all settings in console
|
607 |
console.log(JSON.stringify(blickBrowserSettings, undefined, 4)); |
608 |
}); |
609 |
|
610 |
|
611 |
|
612 |
/*
|
613 |
* Put all '<a>' Elements into an array to parse it
|
614 |
*/
|
615 |
var aArray = [];
|
616 |
var allAs = document.getElementsByTagName("a"); |
617 |
//console.log("Found "+ allAs.length +" Links");
|
618 |
|
619 |
for (var b = 0; b < allAs.length; b++) { |
620 |
var pos = getPosition(allAs[b]);
|
621 |
|
622 |
aArray[b] = []; |
623 |
aArray[b].url = allAs[b].getAttribute("href");
|
624 |
aArray[b].text = allAs[b].innerHTML; |
625 |
aArray[b].x = $(allAs[b]).offset().left;
|
626 |
aArray[b].y = $(allAs[b]).offset().top;
|
627 |
|
628 |
} |
629 |
|
630 |
|
631 |
|
632 |
|
633 |
/*
|
634 |
* Calculate the size of the linkparsing grid
|
635 |
*/
|
636 |
|
637 |
|
638 |
/*
|
639 |
DOCUMENT Grid:
|
640 |
__ __ __ __
|
641 |
|__|__|__|__|
|
642 |
|__|__|__|__|
|
643 |
|__|__|__|__|
|
644 |
|__|__|__|__|
|
645 |
|__|__|__|__|
|
646 |
|__|__|__|__|
|
647 |
|__|__|__|__|
|
648 |
|
649 |
*/
|
650 |
|
651 |
|
652 |
var documentHeight = $(document).height(); |
653 |
var documentWidth = $(document).height(); |
654 |
|
655 |
var colCount = 4; |
656 |
var fieldWidth = documentWidth / colCount;
|
657 |
var fieldHeight = fieldWidth;
|
658 |
var rowCount = Math.ceil(documentHeight / fieldHeight);
|
659 |
/*console.log("colcount: "+colCount);
|
660 |
console.log("fieldWidth: "+fieldWidth);
|
661 |
console.log("fieldHeight: "+fieldHeight);
|
662 |
console.log("rowCount: "+rowCount);*/
|
663 |
|
664 |
|
665 |
|
666 |
var fields = [];
|
667 |
|
668 |
//console.log("Found "+ allAs.length +" Links");
|
669 |
for (var b = 0; b < allAs.length; b++) { |
670 |
var foundPoint = [];
|
671 |
foundPoint.url = allAs[b].getAttribute("href");
|
672 |
foundPoint.text = allAs[b].innerHTML; |
673 |
foundPoint.x = $(allAs[b]).offset().left;
|
674 |
//console.log("FIRSTX: "+foundPoint.x);
|
675 |
foundPoint.y = $(allAs[b]).offset().top;
|
676 |
|
677 |
|
678 |
var fieldX = Math.floor(foundPoint.x / fieldWidth);
|
679 |
//console.log("1_FieldX: "+fieldX);
|
680 |
var fieldY = Math.floor(foundPoint.y / fieldHeight);
|
681 |
//console.log("1_FieldY: "+fieldY);
|
682 |
if (fields[fieldX] !== undefined) { |
683 |
if (fields[fieldX][fieldY] !== undefined) { |
684 |
fields[fieldX][fieldY].push(foundPoint); |
685 |
//console.log("addpoint_1");
|
686 |
} else {
|
687 |
fields[fieldX][fieldY] = []; |
688 |
fields[fieldX][fieldY].push(foundPoint); |
689 |
//console.log("addpoint_2");
|
690 |
} |
691 |
} else {
|
692 |
fields[fieldX] = []; |
693 |
if (fields[fieldX][fieldY] !== undefined) { |
694 |
fields[fieldX][fieldY].push(foundPoint); |
695 |
//console.log("addpoint_3");
|
696 |
} else {
|
697 |
fields[fieldX][fieldY] = []; |
698 |
fields[fieldX][fieldY].push(foundPoint); |
699 |
//console.log("addpoint_4");
|
700 |
} |
701 |
} |
702 |
} |
703 |
|
704 |
|
705 |
|
706 |
} |
707 |
|
708 |
/*
|
709 |
* Run appendGazeEvents over all elements on page load
|
710 |
*/
|
711 |
var allGazeObjects = document.querySelectorAll('[data-gaze]'); |
712 |
for (var g = 0; g < allGazeObjects.length; g++) { |
713 |
appendGazeEvents(allGazeObjects[g]); |
714 |
} |
715 |
|
716 |
|
717 |
|
718 |
/*
|
719 |
* Append gazeEvents to a given element (if it has any appended)
|
720 |
*
|
721 |
* @sourceElement : HTML Node Element to parse for gazeEvents
|
722 |
*/
|
723 |
function appendGazeEvents(sourceElement) { |
724 |
//console.log("myscript.js :: " + "appendGazeEvents()" );
|
725 |
return;
|
726 |
|
727 |
var gazeObject = $(sourceElement); |
728 |
var jsonob = gazeObject.data("gaze"); |
729 |
|
730 |
/*
|
731 |
* if element has an event bound to it, first check for function type,
|
732 |
* then append the event with that function to the 'sourceElement'
|
733 |
*
|
734 |
*/
|
735 |
|
736 |
|
737 |
|
738 |
//if element has 'isFixated' event bound to it
|
739 |
if (jsonob.hasOwnProperty("isFixated")) { |
740 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: found isFixated data-gaze field in JSON: "+ JSON.stringify(jsonob));
|
741 |
|
742 |
if (jsonob.isFixated.funcType == "dynamic") { |
743 |
if (jsonob.isFixated.hasOwnProperty("func")) { |
744 |
gazeObject.off("isFixated");
|
745 |
gazeObject.on("isFixated", new Function(jsonob.isFixated.func)); |
746 |
} else {
|
747 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function code is missing in JSON: " + JSON.stringify(jsonob));
|
748 |
//console.log("function code is missing");
|
749 |
} |
750 |
} else if (jsonob.isFixated.funcType == "fixed") { |
751 |
if (jsonob.isFixated.hasOwnProperty("func")) { |
752 |
gazeObject.off("isFixated");
|
753 |
gazeObject.on("isFixated", gazeFunctions[jsonob.isFixated.func]);
|
754 |
} else {
|
755 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function name is missing in JSON: " + JSON.stringify(jsonob));
|
756 |
//console.log("function is missing");
|
757 |
} |
758 |
} |
759 |
} |
760 |
|
761 |
//if element has 'isFixated' event bound to it
|
762 |
if (jsonob.hasOwnProperty("gazeEnter")) { |
763 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: found gazeEnter data-gaze field in JSON: "+ JSON.stringify(jsonob));
|
764 |
if (jsonob.gazeEnter.funcType == "dynamic") { |
765 |
if (jsonob.gazeEnter.hasOwnProperty("func")) { |
766 |
|
767 |
gazeObject.off("gazeEnter");
|
768 |
gazeObject.on("gazeEnter", new Function(jsonob.gazeEnter.func)); |
769 |
} else {
|
770 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function code is missing in JSON: " + JSON.stringify(jsonob));
|
771 |
//console.log("function code is missing");
|
772 |
} |
773 |
} else if (jsonob.gazeEnter.funcType == "fixed") { |
774 |
if (jsonob.gazeEnter.hasOwnProperty("func")) { |
775 |
gazeObject.off("gazeEnter");
|
776 |
gazeObject.on("gazeEnter", gazeFunctions[jsonob.gazeEnter.func]);
|
777 |
} else {
|
778 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function name is missing in JSON: " + JSON.stringify(jsonob));
|
779 |
//console.log("function is missing");
|
780 |
} |
781 |
} |
782 |
} |
783 |
|
784 |
//if element has 'isFixated' event bound to it
|
785 |
if (jsonob.hasOwnProperty("gazeOver")) { |
786 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: found gazeOver data-gaze field in JSON: "+ JSON.stringify(jsonob));
|
787 |
if (jsonob.gazeOver.funcType == "dynamic") { |
788 |
if (jsonob.gazeOver.hasOwnProperty("func")) { |
789 |
|
790 |
gazeObject.off("gazeOver");
|
791 |
gazeObject.on("gazeOver", new Function(jsonob.gazeOver.func)); |
792 |
} else {
|
793 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function code is missing in JSON: " + JSON.stringify(jsonob));
|
794 |
//console.log("function code is missing");
|
795 |
} |
796 |
} else if (jsonob.gazeOver.funcType == "fixed") { |
797 |
if (jsonob.gazeOver.hasOwnProperty("func")) { |
798 |
gazeObject.off("gazeOver");
|
799 |
gazeObject.on("gazeOver", gazeFunctions[jsonob.gazeOver.func]);
|
800 |
} else {
|
801 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function name is missing in JSON: " + JSON.stringify(jsonob));
|
802 |
//console.log("function is missing");
|
803 |
} |
804 |
} |
805 |
} |
806 |
|
807 |
|
808 |
//if element has 'isFixated' event bound to it
|
809 |
if (jsonob.hasOwnProperty("gazeLeave")) { |
810 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: found gazeLeave data-gaze field in JSON: "+ JSON.stringify(jsonob));
|
811 |
if (jsonob.gazeLeave.funcType == "dynamic") { |
812 |
if (jsonob.gazeLeave.hasOwnProperty("func")) { |
813 |
gazeObject.off("gazeLeave");
|
814 |
gazeObject.on("gazeLeave", new Function(jsonob.gazeLeave.func)); |
815 |
} else {
|
816 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function code is missing in JSON: " + JSON.stringify(jsonob));
|
817 |
} |
818 |
} else if (jsonob.gazeLeave.funcType == "fixed") { |
819 |
if (jsonob.gazeLeave.hasOwnProperty("func")) { |
820 |
gazeObject.off("gazeLeave");
|
821 |
gazeObject.on("gazeLeave", gazeFunctions[jsonob.gazeLeave.func]);
|
822 |
} else {
|
823 |
//console.log("myscript.js :: " + "appendGazeEvents()" + " :: function name is missing in JSON: " + JSON.stringify(jsonob));
|
824 |
//console.log("function is missing");
|
825 |
} |
826 |
} |
827 |
} |
828 |
|
829 |
|
830 |
} |
831 |
|
832 |
/*
|
833 |
* Send changed blickBrowserSettings to addon
|
834 |
*/
|
835 |
function writeSettings(){ |
836 |
console.log("myscript.js :: " + "writeSettings()"); |
837 |
self.port.emit('writeSettings',blickBrowserSettings);
|
838 |
} |
839 |
|
840 |
/*
|
841 |
* Request blickBrowserSettings from addon
|
842 |
*/
|
843 |
function loadSettings() { |
844 |
self.port.emit("getAllSettings", "null"); |
845 |
} |
846 |
|
847 |
/*
|
848 |
* retrieve absolute position of element
|
849 |
* @element: the element to get the position of
|
850 |
*/
|
851 |
function getPosition(element) { |
852 |
//console.log("myscript.js :: "+"getPosition()" + ", element: "+ typeof element);
|
853 |
var xPosition = 0; |
854 |
var yPosition = 0; |
855 |
|
856 |
while (element) {
|
857 |
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft); |
858 |
yPosition += (element.offsetTop - element.scrollTop + element.clientTop); |
859 |
element = element.offsetParent; |
860 |
} |
861 |
return {
|
862 |
x: xPosition,
|
863 |
y: yPosition
|
864 |
}; |
865 |
} |