Statistics
| Branch: | Revision:

blinker / firefox.plugin / data / scripts / gazePosition.js @ master

History | View | Annotate | Download (19.294 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
var gazeScrollAtBorders;
22
23
/*
24
*        Check for elements at position x,y that have gazeEvents bound to them and trigger those events
25
*/
26
function gazePosition(x, y) {
27
        //console.log("functions.js :: "+"gazePosition()" +", x: " + x +", y: "+y );
28
29
        //save current position into gazeInformation Object
30
        gazeInformation.x = x;
31
        gazeInformation.y = y;
32
33
        
34
35
36
        //check if gestureMode has been initiated and needs to be shown
37
        if (gestureMode) {
38
                if (gestureString.length == 4) {
39
                        $.notify("GestureString: " + gestureString, "success");
40
                        gestureMode = false;
41
                        edgeFunctions.clearDivs();
42
43
                        var myGestures = blickBrowserSettings.gestures.split(";");
44
                        if (myGestures.length > 0) {
45
                                for (var gg = 0; gg < myGestures.length; gg++) {
46
                                        var splittedGesture = myGestures[gg].split("|");
47
                                        console.log(splittedGesture[1]);
48
                                        if (splittedGesture[0] == gestureString) {
49
                                                console.log("Calling Function: window."+splittedGesture[1]);
50
                                                window[splittedGesture[1]]();
51
                                        }
52
                                }
53
                        }
54
                }
55
56
                if (Date.now() - gestureTimer >= 5000) {
57
                        $.notify("gestureTimer ran out.", "success");
58
                        gestureMode = false;
59
                        edgeFunctions.clearDivs();
60
                }
61
62
        }
63
64
65
        //check if autoReadingMode is enabled and run the routine if needed
66
        if (blickBrowserSettings.autoReadingMode){
67
                clearTimeout(checkForLinksInterval);
68
                if (Math.abs(gazeInformation.gazeMoveStartPoint.x - gazeInformation.x) > blickBrowserSettings.autoReadingModeDistance || 
69
                        Math.abs(gazeInformation.gazeMoveStartPoint.y - gazeInformation.y) > blickBrowserSettings.autoReadingModeDistance){
70
                        
71
                        gazeInformation.gazeMoveStartTime = Date.now();
72
                        gazeInformation.gazeMoveStartPoint = {"x": gazeInformation.x,"y":gazeInformation.y};
73
74
                } 
75
76
                if (Date.now() - gazeInformation.gazeMoveStartTime >= blickBrowserSettings.autoReadingModeThreshold){
77
                        gazeInformation.gazeMoveStartTime = Date.now();
78
                        gazeInformation.gazeMoveStartPoint = {"x": gazeInformation.x,"y":gazeInformation.y};
79
                        gazeFunctions.checkForLinks();                        
80
                        
81
                }
82
                
83
        }
84
85
        // Compute gaze Correction
86
        if (gazeCorrectionMode === true) {
87
88
                var gazeValues = {
89
                        timestamp: Date.now(),
90
                        gcPoint: gazeCorrectionPointNr,
91
                        x: gazeInformation.x,
92
                        y: gazeInformation.y
93
                };        
94
95
                gazeCorrectionData.push(gazeValues);        
96
        }
97
        
98
        //scroll if scrolling is enabled
99
        if (gazeScrollAtBorders === true) {
100
101
                
102
103
                if (gazeInformation.y > (window.innerHeight + window.scrollY) - (window.innerHeight * (blickBrowserSettings.scrollThreshold/100) )) {
104
105
                        window.scroll(window.scrollX, window.scrollY + blickBrowserSettings.scrollSpeed);
106
107
                } else if ((gazeInformation.y - window.scrollY) < (window.innerHeight * (blickBrowserSettings.scrollThreshold/100))) {
108
109
                        window.scroll(window.scrollX, window.scrollY - blickBrowserSettings.scrollSpeed);
110
111
                }
112
113
                if ((gazeInformation.x - window.scrollX) < (window.innerWidth * (blickBrowserSettings.scrollThreshold/100))) {
114
                        window.scroll(window.scrollX - blickBrowserSettings.scrollSpeed, window.scrollY);
115
                } else if (gazeInformation.x > (window.innerWidth + window.scrollX) - (window.innerWidth * (blickBrowserSettings.scrollThreshold/100))) {
116
                        window.scroll(window.scrollX + blickBrowserSettings.scrollSpeed, window.scrollY);
117
                }
118
        
119
120
        }
121
122
        //position and show crosshair if enabled
123
        if (blickBrowserSettings.gazeCrosshair === true) {
124
125
                $("#crosshairTop").css("left", (gazeInformation.x) + "px");
126
                $("#crosshairTop").css("top", (gazeInformation.y - 16) + "px");
127
128
                $("#crosshairBottom").css("left", (gazeInformation.x) + "px");
129
                $("#crosshairBottom").css("top", (gazeInformation.y + 1) + "px");
130
131
132
                $("#crosshairLeft").css("left", (gazeInformation.x - 16) + "px");
133
                $("#crosshairLeft").css("top", (gazeInformation.y) + "px");
134
135
                $("#crosshairRight").css("left", (gazeInformation.x + 1) + "px");
136
                $("#crosshairRight").css("top", (gazeInformation.y) + "px");
137
138
                $("#crosshairTop").css("display", "block");
139
                $("#crosshairBottom").css("display", "block");
140
                $("#crosshairLeft").css("display", "block");
141
                $("#crosshairRight").css("display", "block");
142
                //$("#cross").css("display", "block");
143
        } else {
144
                $("#crosshairTop").css("display", "none");
145
                $("#crosshairBottom").css("display", "none");
146
                $("#crosshairLeft").css("display", "none");
147
                $("#crosshairRight").css("display", "none");
148
149
                //$("#cross").css("display", "none");
150
        }
151
152
153
        //move findLinkArea with gazePosition
154
        $("#findLinkArea").css("display", "none");
155
        $("#findLinkArea").css("left", (gazeInformation.x - $(findLinkArea).width() / 2) + "px");
156
        $("#findLinkArea").css("top", (gazeInformation.y - $(findLinkArea).height() / 2) + "px");
157
158
159
160
161
        
162
163
        /*
164
        *        Check current gazePosition for edgeGazeGestures
165
        */
166
167
        if ( (x < ((-1 * blickBrowserSettings.leftEdgeTolerance) + window.scrollX) ) && (y > ( (window.innerHeight*0.1) + window.scrollY ) ) && (y < ((window.innerHeight*0.9)) + window.scrollY) ) {
168
                //console.log("leftEdge!!!"+blickBrowserSettings['leftEdge']);
169
                edgeFunctions[blickBrowserSettings.leftEdge]();
170
        }
171
        if ( (y < ((-1 * blickBrowserSettings.topEdgeTolerance) + window.scrollY) ) && (x > ((window.innerWidth*0.1) + window.scrollX ) && (x < ((window.innerWidth*0.9)+ window.scrollX ) ) ) )  {
172
                //console.log("topEdge!!!");
173
                edgeFunctions[blickBrowserSettings.topEdge]();
174
        }
175
        if ((x > (window.innerWidth + window.scrollX + blickBrowserSettings.rightEdgeTolerance)) && (y > ( (window.innerHeight*0.1) + window.scrollY ) ) && (y < ((window.innerHeight*0.9)) + window.scrollY) ) {
176
                //console.log("rightEdge!!!");
177
                edgeFunctions[blickBrowserSettings.rightEdge]();
178
        }
179
180
        
181
182
183
        //check if privacy mode is enabled and move the holeImage according to gazeposition
184
        if (blickBrowserSettings.privacyMode === true) {
185
                //console.log("privacy mode is true!!!!!");
186
                $("#holeImage").css("display", "block");
187
188
                $("#holeImage").css('background-position', (gazeInformation.x - window.scrollX - 2500) + 'px ' + (gazeInformation.y - window.scrollY - 2500) + 'px');
189
        } else {
190
                $("#holeImage").css("display", "none");
191
        }
192
193
194
195
        //Get elementAt gazePosition
196
        var elementBelow = document.elementFromPoint(gazeInformation.x - scrollX, gazeInformation.y - scrollY);
197
198
199
        // React on GAZE Interactions
200
        if($(elementBelow).data('gaze')) {
201
                enterLeaveOver(elementBelow);
202
                initGazeType(elementBelow);
203
        }
204
205
        //document.getElementById("offsetLabel").innerHTML = "Offset: " + "x: " + (browserDecorationThickness + window.scrollX + window.screenX) + "px" + "|y: " + (browserTopBarsHeight + window.scrollY + window.screenY) + "px";
206
207
208
209
        //append debug information to mouse if enabled
210
        if (blickBrowserSettings.debugInformation === true) {
211
                $("#status").css("display", "block");
212
        } else {
213
                $("#status").css("display", "none");
214
        }
215
216
        document.getElementById("status").innerHTML = "X: " + gazeInformation.x + "<br /> Y: " + gazeInformation.y + "<br /> fix: " + gazeInformation.isFixation + "<br /> dur:" + (Date.now() - gazeInformation.currentElementFixatedAt) + "ms" + "<br /> winsize:" + window.innerWidth + "px x " + innerHeight + "px" + "<br /> xOffset:" + (window.mozInnerScreenX + window.scrollX) + "px" + "<br /> yOffset:" + (window.mozInnerScreenY + window.scrollY) + "px";
217
        if (elementBelow !== null) {
218
                document.getElementById("status").innerHTML += ("<br />type:" + elementBelow.tagName);
219
        }
220
221
222
223
        //Fixated DISPATCHER
224
        if (elementBelow !== null && false) {
225
226
                var dataGazeObject = $(elementBelow).data('gaze');
227
                if (dataGazeObject !== undefined) {
228
                        //does element below have an 'isFixated' event?
229
                        if ($(dataGazeObject)[0].hasOwnProperty("isFixated")) {
230
231
                                //if user looks at that element more than 10% of fixationThreshold-time, then show the progressCircle
232
                                if ((Date.now() - gazeInformation.currentElementFixatedAt) >= blickBrowserSettings.fixationThreshold * 0.1) {
233
234
235
                                        $('.dial').val(Date.now() - gazeInformation.currentElementFixatedAt).trigger('change');
236
                                        $("#gazeProgress").css("display", "block");
237
238
239
240
                                        if (distanceToGaze($("#gazeProgress")) < 10) {
241
                                                $("#gazeProgress").css("left", ($("#gazeProgress").offset().left + 10));
242
                                        }
243
244
245
                                }
246
247
248
                                //if user looks at that element longer that fixationThreshold-time, trigger isFixated event of that element
249
                                if ((Date.now() - gazeInformation.currentElementFixatedAt) >= blickBrowserSettings.fixationThreshold) {
250
                                        console.log("fixationTime: "+(Date.now() - gazeInformation.currentElementFixatedAt));
251
                                        gazeInformation.currentElementFixatedAt = Date.now();
252
                                        gazeInformation.fixatedElement = elementBelow;
253
                                        gazeInformation.fixatedElement.dispatchEvent(isFixated);
254
                                } 
255
256
                        } else {
257
                                gazeInformation.currentElementFixatedAt = Date.now();        
258
                                $("#gazeProgress").css("display", "none");
259
                        }
260
                } else {
261
                        gazeInformation.currentElementFixatedAt = Date.now();
262
                        $("#gazeProgress").css("display", "none");
263
264
265
                }
266
        }
267
268
        
269
270
        //GAZE ENTER, GAZE LEAVE AND GAZE OVER DISPATCHER
271
        if (elementBelow !== null && false) {
272
273
                //if current element has the gazeOver event bould to it, trigger it
274
                var dataGazeObject = $(elementBelow).data('gaze');
275
                if (dataGazeObject !== undefined) {
276
                        if ($(dataGazeObject)[0].hasOwnProperty("gazeOver")) {
277
                                $(gazeInformation.elementBelow).trigger("gazeOver");
278
                        }
279
                }
280
                
281
                
282
                //if its a new element below gaze position 
283
                if (gazeInformation.lastElementBelow != elementBelow) {
284
285
                        //if it's a new element - reset the fixated-timer 
286
                        gazeInformation.currentElementFixatedAt = Date.now();
287
                                $('#gazeProgress').css("left", ($(elementBelow).offset().left + $(elementBelow).width() + 10));
288
                                $('#gazeProgress').css("top", ($(elementBelow).offset().top));
289
                        gazeInformation.fixationPositionAtStart = {
290
                                "x": gazeInformation.x,
291
                                "y": gazeInformation.y
292
                        };
293
294
                        //if (gazeInformation.lastElementBelow != gazeInformation.elementBelow){
295
296
                                //if last element has gazeLeave event bound to it, trigger it
297
                                var dataGazeObject = $(gazeInformation.lastElementBelow).data('gaze');
298
                                if (dataGazeObject !== undefined) {
299
                                        if ($(dataGazeObject)[0].hasOwnProperty("gazeLeave")) {
300
                                                $(gazeInformation.lastElementBelow).trigger("gazeLeave");
301
                                        }
302
                                }
303
                                //$(gazeInformation.lastElementBelow).trigger("gazeLeave");
304
305
                        //}
306
                        //save the element in the JSON object
307
                        gazeInformation.lastElementBelow = gazeInformation.elementBelow;
308
309
                        //if the element was not null - dispatch event
310
                        if (gazeInformation.lastElementBelow !== null) {
311
312
                                
313
                                //unfade last gazed element
314
                                var dataGazeObject = $(gazeInformation.lastElementBelow).data('gaze');
315
                                if (dataGazeObject !== undefined) {                                        
316
                                                $(gazeInformation.lastElementBelow).stop();
317
                                                $(gazeInformation.lastElementBelow).fadeTo("fast", 1);                                        
318
                                }
319
                                                                
320
                                gazeInformation.currentElementFixatedAt = Date.now();
321
                                gazeLeaveFunc(gazeInformation.lastElementBelow);
322
323
                        }
324
325
                        //save current element to gazeInformation
326
                        gazeInformation.elementBelow = elementBelow;
327
328
329
                        //if last element has gazeEnter event bound to it, trigger it
330
                var dataGazeObject = $(elementBelow).data('gaze');
331
                if (dataGazeObject !== undefined) {
332
                        if ($(dataGazeObject)[0].hasOwnProperty("gazeEnter")) {
333
                                $(gazeInformation.elementBelow).trigger("gazeEnter");
334
                                gazeInformation.currentElementFixatedAt = Date.now();
335
                        }
336
                }
337
338
                        
339
                //if explicitMode is enabled, put the currently gazed elements name and url into the gazeLinks Array
340
                        if (blickBrowserSettings.explicitMode === true) {
341
                                if (!wheelSelectorShowing) {
342
                                        if (!controlBarShowing) {
343
                                                if (blickBrowserSettings.blickBrowserMode != 'reading') {
344
                                                        if ($(gazeInformation.elementBelow).attr('href') !== undefined) {
345
                                                                gazeInformation.gazeLinks = [];
346
                                                                //console.log("NumOfGazeLinks: " + gazeInformation.gazeLinks.length);
347
                                                                if (gazeInformation.gazeLinks.length < 1) {
348
                                                                        gazeInformation.gazeLinks.push({
349
                                                                                "object": $(gazeInformation.elementBelow),
350
                                                                                "index": 0,
351
                                                                                "name": $(gazeInformation.elementBelow).text(),
352
                                                                                "url": $(gazeInformation.elementBelow).attr('href')
353
                                                                        });
354
355
                                                                        appendGazeLinks();
356
                                                                }
357
                                                        }
358
                                                }
359
                                        }
360
                                }
361
                        }
362
                        gazeInformation.currentElementFixatedAt = Date.now();
363
                        gazeEnterFunc(gazeInformation.elementBelow);
364
365
366
                        //fade gazed elements
367
                        var dataGazeObject = $(gazeInformation.elementBelow).data('gaze');
368
                        if (dataGazeObject !== undefined) {
369
                                
370
                                        $(gazeInformation.elementBelow).stop();
371
                                        $(gazeInformation.elementBelow).fadeTo('fast', 0.3);
372
                                
373
                        }
374
375
                }
376
        }
377
378
}
379
380
381
/*
382
*        gazePosition adjusting before working with the gazePosition
383
*/
384
function calcGazePosition(message) {
385
        //console.log(window.mozInnerScreenY);
386
        //console.log("functions.js :: "+"calcGazePosition()" +", message: "+message );
387
388
389
        //stop asyncronous checking for links if readingMode is active
390
        if (blickBrowserSettings.blickBrowserMode == "reading") {
391
                clearTimeout(checkForLinksInterval);
392
        }
393
394
        
395
        eyeTrackingData = JSON.parse(message);
396
        var newX, newY;
397
398
399
400
        raw = eyeTrackingData;
401
        if (raw.x == "0.0" && raw.y == "0.0") {
402
                self.port.emit("setIconRed", "noop");
403
        } else {
404
                self.port.emit("setIconGreen", "noop");
405
        }
406
407
        //remove current screen position from gazePosition
408
        //add the current scrolling position from gazePosition
409
        //add the manual offset to the gazePosition
410
        raw.x = (raw.x / blickBrowserSettings.scaling) + window.scrollX - window.mozInnerScreenX + blickBrowserSettings.gazeOffsetX;
411
        raw.y = (raw.y / blickBrowserSettings.scaling) + window.scrollY - window.mozInnerScreenY + blickBrowserSettings.gazeOffsetY;
412
413
414
        //safe previous
415
        gazeInformation.previousX = gazeInformation.x;
416
        gazeInformation.previousY = gazeInformation.y;
417
418
419
420
        newX = raw.x;
421
        newY = raw.y;
422
423
        //do gazeSmoothing if needed
424
        if (blickBrowserSettings.gazeSmoothing === true) {
425
                
426
                
427
                //empty gazeHistory if gaze just performed a saccade
428
                //append the gazePosition to gazeHistory otherwise
429
                if (Math.abs(gazeInformation.previousX - newX) > blickBrowserSettings.saccadeLength) {                                                
430
                        gazeCollection = [];                        
431
432
                } else if (Math.abs(gazeInformation.previousY - newY) > blickBrowserSettings.saccadeLength) {
433
                        gazeCollection = [];
434
                } else {
435
436
                        //if gazeHistory is not full, append current gazePosition
437
                        if (gazeCollection.length < blickBrowserSettings.gazeSmoothingHistory) {
438
                                gazeCollection.push({
439
                                        "x": newX,
440
                                        "y": newY
441
                                });
442
                                //otherwise remove oldest element and append newest 
443
                        } else {
444
                                gazeCollection.splice(0, 1);
445
                                gazeCollection.push({
446
                                        "x": newX,
447
                                        "y": newY
448
                                });
449
                        }
450
451
                        var sumX = 0;
452
                        var sumY = 0;
453
                        //calculate the average gazePosition from all positions in gazeHistory 
454
                        for (var g = 0; g < gazeCollection.length; g++) {
455
                                sumX += gazeCollection[g].x;
456
                                sumY += gazeCollection[g].y;
457
                        }
458
                        //set newly calculated gazePosition 
459
                        newX = sumX / gazeCollection.length;
460
                        newY = sumY / gazeCollection.length;
461
462
463
464
                }
465
        }
466
467
        try{
468
                //run check for gazeEvents and options on newly calculated gazePosition 
469
                gazePosition(newX, newY);
470
        } catch (exc){
471
                console.log("ERROR MESSAGE: "+exc.message);
472
                console.log("ERROR NAME: "+exc.name);
473
                console.log("ERROR LINENUMBER: "+exc.lineNumber);
474
                console.log("ERROR LINENUMBER: "+exc.columnNumber);
475
        }
476
}
477
478
479
function isFix(elementBelow) {
480
        //if user looks at that element more than 10% of fixationThreshold-time, then show the progressCircle
481
        if ((Date.now() - gazeInformation.currentElementFixatedAt) >= blickBrowserSettings.fixationThreshold * 0.1) {
482
483
                // console.log("10% of fixation");
484
                $('.dial').val(Date.now() - gazeInformation.currentElementFixatedAt).trigger('change');
485
                $("#gazeProgress").css("display", "block");
486
487
488
489
                if (distanceToGaze($("#gazeProgress")) < 10) {
490
                        $("#gazeProgress").css("left", ($("#gazeProgress").offset().left + 10));
491
                }
492
493
494
        }
495
496
497
        //if user looks at that element longer that fixationThreshold-time, trigger isFixated event of that element
498
        if ((Date.now() - gazeInformation.currentElementFixatedAt) >= blickBrowserSettings.fixationThreshold) {
499
                console.log("fixation");
500
                console.log("fixationTime: "+(Date.now() - gazeInformation.currentElementFixatedAt));
501
                gazeInformation.currentElementFixatedAt = Date.now();
502
                gazeInformation.fixatedElement = elementBelow;
503
                gazeInformation.fixatedElement.dispatchEvent(isFixated);
504
                $('.fixatedElement').removeClass('fixatedElement');
505
                $(gazeInformation.fixatedElement).addClass('fixatedElement');
506
                $(gazeInformation.fixatedElement).trigger("isFixated");                
507
        } 
508
}
509
510
function isOver(elementBelow) {
511
        $(gazeInformation.elementBelow).trigger("gazeOver");
512
        isFix(elementBelow);
513
}
514
515
function isLeave() {
516
        $(gazeInformation.lastElementBelow).trigger("gazeLeave");
517
518
        //if the element was not null - dispatch event
519
        if (gazeInformation.lastElementBelow !== null) {                        
520
                // console.log("leave element: " + gazeInformation.lastElementBelow);
521
                //unfade last gazed element
522
                var dataGazeObject = $(gazeInformation.lastElementBelow).data('gaze');
523
                if (dataGazeObject !== undefined) {                                        
524
                                $(gazeInformation.lastElementBelow).stop();
525
                                $(gazeInformation.lastElementBelow).fadeTo("fast", 1);                                        
526
                }
527
                                                
528
                gazeInformation.currentElementFixatedAt = Date.now();
529
                gazeLeaveFunc(gazeInformation.lastElementBelow);
530
531
        }
532
}
533
534
function isEnter(elementBelow) {
535
        if($(elementBelow).data('gaze')) {
536
                //console.log("enter element: " + gazeInformation.lastElementBelow);
537
                gazeInformation.elementBelow = elementBelow;
538
                $(gazeInformation.elementBelow).trigger("gazeEnter");
539
                gazeInformation.currentElementFixatedAt = Date.now();
540
                gazeEnterFunc(gazeInformation.elementBelow);
541
                isFix(elementBelow);
542
        }
543
}
544
545
546
function enterLeaveOver(elementBelow) {
547
        //GAZE ENTER, GAZE LEAVE AND GAZE OVER DISPATCHER
548
        if (elementBelow !== null) {
549
                if($(elementBelow).data('gaze') !== undefined) {
550
                        //trigger is over element
551
                        isOver(elementBelow);
552
553
                        if(gazeInformation.lastElementBelow != elementBelow) {
554
                                //if it's a new element - reset the fixated-timer 
555
                                gazeInformation.currentElementFixatedAt = Date.now();
556
                                        $('#gazeProgress').css("left", ($(elementBelow).offset().left + $(elementBelow).width() + 10));
557
                                        $('#gazeProgress').css("top", ($(elementBelow).offset().top));
558
                                gazeInformation.fixationPositionAtStart = {
559
                                        "x": gazeInformation.x,
560
                                        "y": gazeInformation.y
561
                                };
562
563
                                isLeave();
564
                                isEnter(elementBelow);
565
                                gazeInformation.lastElementBelow = gazeInformation.elementBelow;
566
                        }
567
                }                
568
569
        } else {
570
                isLeave();
571
                gazeInformation.lastElementBelow = null;
572
        }
573
}
574
575
function setScrollAtBorder(onScroll = blickBrowserSettings.scrollAtBorders) {
576
        gazeScrollAtBorders = onScroll;
577
}