remote-calibrator 0.3.0-rc.3 → 0.5.0-beta.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. package/CHANGELOG.md +35 -3
  2. package/README.md +34 -49
  3. package/homepage/example.css +4 -3
  4. package/homepage/example.js +42 -22
  5. package/homepage/index.html +19 -4
  6. package/i18n/fetch-languages-sheets.js +11 -1
  7. package/lib/RemoteCalibrator.min.js +1 -1
  8. package/lib/RemoteCalibrator.min.js.LICENSE.txt +19 -2
  9. package/lib/RemoteCalibrator.min.js.map +1 -1
  10. package/netlify.toml +1 -1
  11. package/package.json +25 -24
  12. package/src/WebGazer4RC/package-lock.json +198 -143
  13. package/src/WebGazer4RC/package.json +2 -2
  14. package/src/WebGazer4RC/src/index.mjs +161 -52
  15. package/src/WebGazer4RC/test/webgazer_test.js +1 -1
  16. package/src/check/checkScreenSize.js +84 -0
  17. package/src/components/buttons.js +21 -4
  18. package/src/components/input.js +82 -0
  19. package/src/components/keyBinder.js +5 -6
  20. package/src/components/language.js +5 -0
  21. package/src/components/mediaPermission.js +21 -0
  22. package/src/components/onCanvas.js +2 -2
  23. package/src/components/sound.js +30 -2
  24. package/src/components/swalOptions.js +6 -3
  25. package/src/components/utils.js +27 -1
  26. package/src/components/video.js +9 -6
  27. package/src/const.js +15 -0
  28. package/src/core.js +103 -48
  29. package/src/css/buttons.scss +34 -7
  30. package/src/css/components.scss +57 -0
  31. package/src/css/distance.scss +71 -1
  32. package/src/css/gaze.css +9 -5
  33. package/src/css/main.css +22 -6
  34. package/src/css/panel.scss +33 -3
  35. package/src/css/screenSize.css +6 -5
  36. package/src/css/swal.css +1 -1
  37. package/src/css/video.scss +19 -0
  38. package/src/distance/distance.js +194 -41
  39. package/src/distance/distanceCheck.js +241 -0
  40. package/src/distance/distanceTrack.js +165 -68
  41. package/src/{interpupillaryDistance.js → distance/interPupillaryDistance.js} +27 -19
  42. package/src/gaze/gaze.js +4 -7
  43. package/src/gaze/gazeAccuracy.js +9 -4
  44. package/src/gaze/gazeCalibration.js +14 -4
  45. package/src/gaze/gazeTracker.js +40 -9
  46. package/src/i18n.js +1 -1
  47. package/src/index.js +7 -2
  48. package/src/media/two-side-arrow.svg +1 -0
  49. package/src/media/two-sided-horizontal.svg +1 -0
  50. package/src/media/two-sided-vertical.svg +3 -0
  51. package/src/panel.js +130 -65
  52. package/src/screenSize.js +38 -5
  53. package/webpack.config.js +7 -4
  54. package/media/measureDistance.png +0 -0
  55. package/media/panel.png +0 -0
  56. package/media/screenSize.png +0 -0
  57. package/media/trackGaze.png +0 -0
  58. package/src/displaySize.js +0 -28
@@ -69,7 +69,7 @@
69
69
  top: 0;
70
70
  width: 2px;
71
71
  transform: translate(-1px, 0);
72
- z-index: 1;
72
+ z-index: 2;
73
73
  }
74
74
 
75
75
  .rc-ruler-major {
@@ -87,3 +87,73 @@
87
87
  height: 16px;
88
88
  }
89
89
  }
90
+
91
+ /* ---------------------------------- Check --------------------------------- */
92
+
93
+ .hide-nudger {
94
+ .calibration-nudger {
95
+ display: none !important;
96
+ opacity: 0 !important;
97
+ }
98
+ }
99
+
100
+ .calibration-nudger {
101
+ z-index: 999999999;
102
+ position: fixed;
103
+ width: 100%;
104
+ height: 100%;
105
+ top: 0;
106
+ left: 0;
107
+ right: 0;
108
+ bottom: 0;
109
+ margin: 0;
110
+ overflow: hidden;
111
+ user-select: none;
112
+ box-sizing: border-box;
113
+ text-align: center;
114
+ scrollbar-width: none;
115
+
116
+ * {
117
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
118
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
119
+ }
120
+ }
121
+
122
+ #rc-distance-correct {
123
+ text-align: center;
124
+ width: 100%;
125
+ margin: 3rem auto auto auto;
126
+ padding: 2rem;
127
+ overflow-wrap: break-word;
128
+
129
+ #rc-distance-correct-instruction {
130
+ font-weight: 700;
131
+ font-size: 7rem;
132
+ margin: 2rem auto;
133
+ line-height: 100%;
134
+ }
135
+
136
+ #rc-distance-correct-guide {
137
+ font-weight: 500;
138
+ font-size: 3rem;
139
+ line-height: 150%;
140
+
141
+ .rc-distance-num {
142
+ padding: 0.5rem;
143
+ border-radius: 7px !important;
144
+ font-weight: 700;
145
+ font-family: monospace !important;
146
+ vertical-align: middle;
147
+ }
148
+
149
+ .rc-distance-now {
150
+ border: 2px solid #ff9a00;
151
+ background-color: #ff9a0066;
152
+ }
153
+
154
+ .rc-distance-desired {
155
+ border: 2px solid #3490de;
156
+ background-color: #3490de66;
157
+ }
158
+ }
159
+ }
package/src/css/gaze.css CHANGED
@@ -8,7 +8,7 @@
8
8
  position: fixed !important;
9
9
  display: block;
10
10
  cursor: initial;
11
- z-index: 9998;
11
+ z-index: 999999998;
12
12
  transition-timing-function: ease-in-out;
13
13
  transition: left 0.5s, right 0.5s, top 0.5s, bottom 0.5s;
14
14
  }
@@ -41,7 +41,7 @@
41
41
 
42
42
  #webgazerGazeDot {
43
43
  position: fixed;
44
- z-index: 999999;
44
+ z-index: 9999999999;
45
45
  opacity: 0.5;
46
46
  background-color: #111d5e;
47
47
  border-radius: 5px;
@@ -50,14 +50,18 @@
50
50
  }
51
51
 
52
52
  #webgazerVideoContainer {
53
- z-index: 9997;
53
+ z-index: 999999997;
54
54
  display: block;
55
55
  position: fixed !important;
56
56
  transform-origin: bottom left;
57
- /* border-radius: 7px; */
57
+ border-radius: 5px;
58
58
  /* opacity: 0.8; */
59
59
  overflow: hidden;
60
- pointer-events: none;
60
+ /* pointer-events: none; */
61
+ user-select: none;
62
+ }
63
+
64
+ #webgazerVideoContainer * {
61
65
  user-select: none;
62
66
  }
63
67
 
package/src/css/main.css CHANGED
@@ -1,6 +1,6 @@
1
1
  /* background div */
2
2
  #calibration-background {
3
- z-index: 999;
3
+ z-index: 999999990;
4
4
  position: fixed;
5
5
  width: 100%;
6
6
  height: 100%;
@@ -15,6 +15,12 @@
15
15
  user-select: none;
16
16
  box-sizing: border-box;
17
17
  text-align: center;
18
+ scrollbar-width: none;
19
+ }
20
+
21
+ #calibration-background::-webkit-scrollbar {
22
+ width: 0;
23
+ display: none;
18
24
  }
19
25
 
20
26
  #calibration-background * {
@@ -28,7 +34,6 @@
28
34
 
29
35
  .calibration-instruction {
30
36
  position: absolute;
31
- text-align: left;
32
37
  user-select: none;
33
38
  }
34
39
 
@@ -121,13 +126,13 @@
121
126
  border-radius: 10px;
122
127
  font-size: 1.2rem;
123
128
  font-weight: 500;
124
- z-index: 9999;
129
+ z-index: 999999991;
125
130
  }
126
131
 
127
132
  /* -------------------------------------------------------------------------- */
128
133
 
129
134
  .swal2-container {
130
- z-index: 999997 !important;
135
+ z-index: 999999999 !important;
131
136
  }
132
137
 
133
138
  /* -------------------------------------------------------------------------- */
@@ -136,12 +141,11 @@
136
141
  position: fixed !important;
137
142
  width: 100% !important;
138
143
  bottom: 3px !important;
139
- left: 50% !important;
140
- transform: translate(-50%, 0) !important;
141
144
  color: #999 !important;
142
145
  margin: 0 !important;
143
146
  padding: 0 !important;
144
147
  line-height: 100% !important;
148
+ text-align: center !important;
145
149
  }
146
150
 
147
151
  /* -------------------------------------------------------------------------- */
@@ -149,3 +153,15 @@
149
153
  .lock-view {
150
154
  overflow: hidden !important;
151
155
  }
156
+
157
+ /* -------------------------------------------------------------------------- */
158
+
159
+ .rc-lang-ltr {
160
+ direction: ltr !important;
161
+ text-align: left !important;
162
+ }
163
+
164
+ .rc-lang-rtl {
165
+ direction: rtl !important;
166
+ text-align: right !important;
167
+ }
@@ -17,7 +17,6 @@
17
17
  border-radius: 10px !important;
18
18
  box-shadow: var(--rc-panel-darken-color-semi) 0px 50px 100px -20px,
19
19
  var(--rc-panel-theme-color-semi) 0px 30px 60px -30px !important;
20
- text-align: left !important;
21
20
 
22
21
  * {
23
22
  outline: none;
@@ -30,6 +29,7 @@
30
29
  user-select: none;
31
30
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
32
31
  Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
32
+ scrollbar-width: none;
33
33
  }
34
34
 
35
35
  .rc-panel-title {
@@ -46,8 +46,27 @@
46
46
  font-weight: 500 !important;
47
47
  }
48
48
 
49
+ #rc-panel-language-parent {
50
+ display: flex;
51
+ flex-direction: row-reverse;
52
+ margin: 0;
53
+ padding: 0;
54
+
55
+ #rc-panel-lang-picker {
56
+ display: block;
57
+ background-color: #ffffffcc !important;
58
+ border: none !important;
59
+ outline: none !important;
60
+ margin: 0.25rem 0.25rem 0 0.25rem !important;
61
+ padding: 0.25rem !important;
62
+ font-size: 1rem !important;
63
+ font-weight: 500 !important;
64
+ border-radius: 5px !important;
65
+ }
66
+ }
67
+
49
68
  .rc-panel-steps {
50
- margin: 1.5rem 0 0 0 !important;
69
+ margin: 1rem 0 0 0 !important;
51
70
 
52
71
  &.rc-panel-steps-l,
53
72
  &.rc-panel-steps-s {
@@ -63,6 +82,10 @@
63
82
  // overflow: hidden !important;
64
83
  background: #ffffffcc;
65
84
 
85
+ // &:focus {
86
+ // outline: 3px solid black !important;
87
+ // }
88
+
66
89
  .rc-panel-step-use {
67
90
  position: absolute;
68
91
  right: 0;
@@ -91,6 +114,8 @@
91
114
 
92
115
  &.rc-panel-steps-l {
93
116
  flex-flow: row nowrap;
117
+ max-width: 100%;
118
+ overflow-x: scroll;
94
119
 
95
120
  .rc-panel-step-name {
96
121
  margin: 1.5rem 0.5rem !important;
@@ -101,7 +126,7 @@
101
126
  flex-flow: column nowrap;
102
127
 
103
128
  .rc-panel-step {
104
- text-align: left;
129
+ overflow-x: hidden;
105
130
  }
106
131
 
107
132
  .rc-panel-step-name {
@@ -191,4 +216,9 @@
191
216
  cursor: pointer;
192
217
  }
193
218
  }
219
+
220
+ ::-webkit-scrollbar {
221
+ width: 0;
222
+ display: none;
223
+ }
194
224
  }
@@ -10,10 +10,11 @@
10
10
  /* top: max(45%, 200px); */
11
11
  left: 2rem;
12
12
  border-radius: 5px;
13
- z-index: 1;
13
+ z-index: 10;
14
14
  cursor: grab;
15
15
  -webkit-transition: opacity 0.3s;
16
16
  transition: opacity 0.3s;
17
+ direction: ltr !important;
17
18
  }
18
19
 
19
20
  .rc-slider:hover {
@@ -59,18 +60,18 @@
59
60
  /* display: none; */
60
61
  width: 70px;
61
62
  height: auto;
62
- z-index: 3;
63
+ z-index: 1;
63
64
  }
64
65
 
65
66
  #size-arrow-fill {
66
- transition: fill 0.1s;
67
+ transition: fill 0.3s;
67
68
  }
68
69
 
69
70
  .minor {
70
- transition: opacity 0.1s;
71
+ transition: opacity 0.25s;
71
72
  }
72
73
 
73
- .rc-slider:hover ~ .size-obj .minor,
74
+ /* .rc-slider:hover ~ .size-obj .minor, */
74
75
  .rc-slider:active ~ .size-obj .minor {
75
76
  opacity: 0;
76
77
  }
package/src/css/swal.css CHANGED
@@ -20,12 +20,12 @@
20
20
  }
21
21
 
22
22
  .my__swal2__html {
23
+ margin: 1rem 1.6rem;
23
24
  color: #444 !important;
24
25
  font-size: 1.2rem !important;
25
26
  line-height: 150% !important;
26
27
  font-weight: normal !important;
27
28
  user-select: none !important;
28
- text-align: left !important;
29
29
  }
30
30
 
31
31
  .animate__animated.animate__fadeInUp,
@@ -0,0 +1,19 @@
1
+ #webgazerVideoContainer {
2
+ .webgazer-videoinput-select {
3
+ z-index: 9;
4
+ position: absolute;
5
+ top: 0;
6
+ left: 0;
7
+ margin: 0.3rem;
8
+ padding: 0.2rem 0.3rem;
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
10
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
11
+ font-size: 0.6rem;
12
+ line-height: 100%;
13
+ border: none !important;
14
+ outline: none !important;
15
+ border-radius: 0.6rem !important;
16
+ background: #ffffffcc !important;
17
+ color: #666;
18
+ }
19
+ }
@@ -5,11 +5,13 @@ import {
5
5
  toFixedNumber,
6
6
  median,
7
7
  blurAll,
8
+ safeExecuteFunc,
9
+ average,
8
10
  } from '../components/utils'
9
11
  import {
10
12
  _getCrossX,
11
13
  _cross,
12
- circleDeltaX,
14
+ // circleDeltaX,
13
15
  _getCircleBounds,
14
16
  _circle,
15
17
  } from '../components/onCanvas'
@@ -23,7 +25,7 @@ const blindSpotHTML = `<canvas id="blind-spot-canvas"></canvas>`
23
25
  /* -------------------------------------------------------------------------- */
24
26
 
25
27
  export function blindSpotTest(RC, options, toTrackDistance = false, callback) {
26
- let ppi = 108 // Dangerous! Arbitrary value
28
+ let ppi = RC._CONST.N.PPI_DONT_USE // Dangerous! Arbitrary value
27
29
  if (RC.screenPpi) ppi = RC.screenPpi.value
28
30
  else
29
31
  console.error(
@@ -40,7 +42,7 @@ export function blindSpotTest(RC, options, toTrackDistance = false, callback) {
40
42
  RC.background.appendChild(blindSpotDiv)
41
43
  RC._constructFloatInstructionElement(
42
44
  'blind-spot-instruction',
43
- phrases.RC_headTrackingCloseL[RC.L]
45
+ phrases.RC_distanceTrackingCloseL[RC.L]
44
46
  )
45
47
  RC._addCreditOnBackground(phrases.RC_viewingBlindSpotCredit[RC.L])
46
48
 
@@ -74,63 +76,186 @@ export function blindSpotTest(RC, options, toTrackDistance = false, callback) {
74
76
  let v = eyeSide === 'left' ? 1 : -1
75
77
 
76
78
  // ! KEY
77
- const breakFunction = () => {
79
+ const breakFunction = (toBreakTracking = true) => {
78
80
  // ! BREAK
79
81
  inTest = false
80
82
  resizeObserver.unobserve(RC.background)
81
83
  RC._removeBackground()
82
84
 
85
+ if (!RC._trackingSetupFinishedStatus.distance && toBreakTracking) {
86
+ RC._trackingSetupFinishedStatus.distance = true
87
+ if (RC.gazeTracker.checkInitialized('distance', false)) RC.endDistance()
88
+ }
89
+
83
90
  unbindKeys(bindKeysFunction)
91
+ unbindKeys(bindKeyUpsFunction, 'keyup')
84
92
  }
85
93
 
86
94
  // SPACE
87
95
  const finishFunction = () => {
96
+ customButton.disabled = false
88
97
  soundFeedback()
89
98
 
90
99
  tested += 1
91
100
  // Average
92
- dist.push(
93
- toFixedNumber(_getDist(circleX, crossX, ppi), options.decimalPlace)
94
- )
101
+ dist.push({
102
+ dist: toFixedNumber(_getDist(circleX, crossX, ppi), options.decimalPlace),
103
+ v: v,
104
+ closedEyeSide: eyeSide,
105
+ crossX: crossX,
106
+ circleX: circleX,
107
+ ppi: ppi,
108
+ timestamp: new Date(),
109
+ })
95
110
 
96
111
  // Enough tests?
97
112
  if (Math.floor(tested / options.repeatTesting) === 2) {
98
- // ! Put dist into data and callback function
99
- const data = (RC.newViewingDistanceData = {
100
- value: toFixedNumber(median(dist), options.decimalPlace),
101
- timestamp: new Date(),
102
- method: 'Blind Spot',
103
- })
104
- if (callback) callback(data)
105
-
106
- // Break
107
- if (!toTrackDistance) {
108
- breakFunction()
113
+ // Check if these data are acceptable
114
+ if (checkDataRepeatability(dist)) {
115
+ // ! Put dist into data and callback function
116
+ const data = (RC.newViewingDistanceData = {
117
+ value: toFixedNumber(
118
+ median(_getDistValues(dist)),
119
+ options.decimalPlace
120
+ ),
121
+ timestamp: new Date(),
122
+ method: RC._CONST.VIEW_METHOD.B,
123
+ raw: { ...dist },
124
+ })
125
+ safeExecuteFunc(callback, data)
126
+
127
+ // Break
128
+ if (!toTrackDistance) {
129
+ breakFunction(false)
130
+ } else {
131
+ // ! For tracking
132
+ // Stop test
133
+ inTest = false
134
+ // Clear observer and keys
135
+ resizeObserver.unobserve(RC.background)
136
+ unbindKeys(bindKeysFunction)
137
+ unbindKeys(bindKeyUpsFunction, 'keyup')
138
+ }
109
139
  } else {
110
- // ! For tracking
111
- // Stop test
112
- inTest = false
113
- // Clear observer and keys
114
- resizeObserver.unobserve(RC.background)
115
- unbindKeys(bindKeysFunction)
140
+ // ! Reset
141
+ tested = 0
142
+ customButton.disabled = true
143
+ // Get first response
144
+ const firstResponse = dist[0]
145
+ _resetCanvasLayout(
146
+ firstResponse.v,
147
+ firstResponse.closedEyeSide,
148
+ firstResponse.crossX
149
+ )
116
150
  }
117
151
  } else if (tested % options.repeatTesting === 0) {
118
152
  // Switch eye side
119
153
  if (eyeSide === 'left') {
120
154
  // Change to RIGHT
121
155
  eyeSide = 'right'
122
- eyeSideEle.innerHTML = phrases.RC_headTrackingCloseR[RC.L]
156
+ eyeSideEle.innerHTML = phrases.RC_distanceTrackingCloseR[RC.L]
123
157
  } else {
124
158
  eyeSide = 'left'
125
- eyeSideEle.innerHTML = phrases.RC_headTrackingCloseL[RC.L]
159
+ eyeSideEle.innerHTML = phrases.RC_distanceTrackingCloseL[RC.L]
160
+ }
161
+ RC._setFloatInstructionElementPos(eyeSide, 16)
162
+
163
+ _resetCanvasLayout(
164
+ // eyeSide === 'left' ? 1 : -1, // v
165
+ 1, // v
166
+ eyeSide, // eyeSide
167
+ _getCrossX(eyeSide, c.width), // crossX
168
+ false,
169
+ true
170
+ )
171
+ } else {
172
+ // Shift circle
173
+ v = -v
174
+ if (v > 0)
175
+ // Going to the right
176
+ circleX = circleBounds[0]
177
+ else if (v < 0) circleX = circleBounds[1]
178
+ }
179
+ }
180
+
181
+ const redoFunction = () => {
182
+ if (!tested) return
183
+ tested--
184
+ customButton.disabled = true
185
+
186
+ soundFeedback(3)
187
+
188
+ const lastResponse = dist.pop()
189
+ _resetCanvasLayout(
190
+ lastResponse.v,
191
+ lastResponse.closedEyeSide,
192
+ lastResponse.crossX,
193
+ true,
194
+ true
195
+ )
196
+ }
197
+
198
+ let arrowKeyDown = false
199
+ let arrowIntervalFunction = null
200
+ const arrowDownFunction = e => {
201
+ if (arrowKeyDown) return
202
+
203
+ arrowUpFunction()
204
+ arrowKeyDown = true
205
+
206
+ arrowIntervalFunction = setInterval(() => {
207
+ if (e.key === 'ArrowLeft') {
208
+ circleX -= 10
209
+ helpMoveCircleX()
210
+ } else if (e.key === 'ArrowRight') {
211
+ circleX += 10
212
+ helpMoveCircleX()
126
213
  }
214
+ }, 30)
215
+ }
216
+
217
+ const arrowUpFunction = () => {
218
+ arrowKeyDown = false
219
+ if (arrowIntervalFunction) {
220
+ clearInterval(arrowIntervalFunction)
221
+ arrowIntervalFunction = null
222
+ }
223
+ }
224
+
225
+ const helpMoveCircleX = () => {
226
+ tempX = constrain(circleX, ...circleBounds)
227
+ if (circleX !== tempX) {
228
+ circleX = tempX
229
+ for (let b of circleBounds)
230
+ if (circleX !== b) {
231
+ circleX = b
232
+ break
233
+ }
234
+ }
235
+ }
236
+
237
+ const _resetCanvasLayout = (
238
+ nextV,
239
+ nextEyeSide,
240
+ nextCrossX,
241
+ shiftFloatingElement = true,
242
+ shiftCircle = true
243
+ ) => {
244
+ v = nextV
245
+ eyeSide = nextEyeSide
246
+ crossX = nextCrossX
247
+ circleBounds = _getCircleBounds(eyeSide, crossX, c.width)
248
+
249
+ if (shiftFloatingElement) {
250
+ if (eyeSide === 'left')
251
+ eyeSideEle.innerHTML = phrases.RC_distanceTrackingCloseL[RC.L]
252
+ else eyeSideEle.innerHTML = phrases.RC_distanceTrackingCloseR[RC.L]
127
253
  RC._setFloatInstructionElementPos(eyeSide, 16)
254
+ }
128
255
 
129
- circleBounds = _getCircleBounds(eyeSide, crossX, c.width)
130
- circleX = circleBounds[eyeSide === 'left' ? 0 : 1]
131
- v = eyeSide === 'left' ? 1 : -1
132
- crossX = _getCrossX(eyeSide, c.width)
133
- circleBounds = _getCircleBounds(eyeSide, crossX, c.width)
256
+ if (shiftCircle) {
257
+ if (v > 0) circleX = circleBounds[0]
258
+ else circleX = circleBounds[1]
134
259
  }
135
260
  }
136
261
 
@@ -138,17 +263,33 @@ export function blindSpotTest(RC, options, toTrackDistance = false, callback) {
138
263
  const bindKeysFunction = bindKeys({
139
264
  Escape: breakFunction,
140
265
  ' ': finishFunction,
266
+ ArrowLeft: arrowDownFunction,
267
+ ArrowRight: arrowDownFunction,
141
268
  })
142
- addButtons(
269
+ const bindKeyUpsFunction = bindKeys(
270
+ {
271
+ ArrowLeft: arrowUpFunction,
272
+ ArrowRight: arrowUpFunction,
273
+ },
274
+ 'keyup'
275
+ )
276
+ const addedButtons = addButtons(
143
277
  RC.L,
144
278
  RC.background,
145
279
  {
146
280
  go: finishFunction,
147
281
  cancel: breakFunction,
282
+ custom: {
283
+ callback: redoFunction,
284
+ content: phrases.RC_viewingDistanceRedo[RC.L],
285
+ },
148
286
  },
149
287
  RC.params.showCancelButton
150
288
  )
151
289
 
290
+ const customButton = addedButtons[3]
291
+ customButton.disabled = true
292
+
152
293
  // ! ACTUAL TEST
153
294
  let frameCount = 0
154
295
  const runTest = () => {
@@ -160,12 +301,7 @@ export function blindSpotTest(RC, options, toTrackDistance = false, callback) {
160
301
  _cross(ctx, crossX, c.height / 2)
161
302
 
162
303
  _circle(RC, ctx, circleX, c.height / 2, frameCount, options.sparkle)
163
- circleX += v * circleDeltaX
164
- tempX = constrain(circleX, ...circleBounds)
165
- if (circleX !== tempX) {
166
- circleX = tempX
167
- v = -v
168
- }
304
+ // circleX += v * circleDeltaX
169
305
 
170
306
  if (inTest) {
171
307
  frameCount++
@@ -183,7 +319,6 @@ RemoteCalibrator.prototype.measureDistance = function (options = {}, callback) {
183
319
  * options -
184
320
  *
185
321
  * fullscreen: [Boolean]
186
- * quitFullscreenOnFinished: [Boolean] // TODO
187
322
  * repeatTesting: 2
188
323
  * sparkle: true
189
324
  * decimalPlace: 1
@@ -200,9 +335,8 @@ RemoteCalibrator.prototype.measureDistance = function (options = {}, callback) {
200
335
  options = Object.assign(
201
336
  {
202
337
  fullscreen: false,
203
- quitFullscreenOnFinished: false,
204
338
  repeatTesting: 2,
205
- sparkle: true,
339
+ sparkle: false,
206
340
  decimalPlace: 1,
207
341
  headline: '📏 ' + phrases.RC_viewingDistanceTitle[this.L],
208
342
  description: phrases.RC_viewingDistanceIntro[this.L],
@@ -230,3 +364,22 @@ function _getDist(x, crossX, ppi) {
230
364
  function _getTanDeg(deg) {
231
365
  return Math.tan((deg * Math.PI) / 180)
232
366
  }
367
+
368
+ function checkDataRepeatability(dist) {
369
+ let lefts = []
370
+ let rights = []
371
+ for (let d of dist) {
372
+ if (d.closedEyeSide === 'left') lefts.push(d.dist)
373
+ else rights.push(d.dist)
374
+ }
375
+ const leftMean = average(lefts)
376
+ const rightMean = average(rights)
377
+
378
+ return Math.abs(leftMean - rightMean) < 0.2 * Math.min(leftMean, rightMean)
379
+ }
380
+
381
+ function _getDistValues(dist) {
382
+ const v = []
383
+ for (let d of dist) v.push(d.dist)
384
+ return v
385
+ }