blinker / firefox.plugin / data / scripts / myscript.js @ master
History | View | Annotate | Download (28.319 KB)
1 | 76dd22bd | KevinTaron | /*
|
---|---|---|---|
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 | a03cd52e | Thies Pfeiffer | } |