remote-calibrator 0.3.0-beta.0 → 0.3.0-beta.4
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.js +1 -1
- package/.husky/pre-commit +1 -1
- package/.prettierignore +4 -0
- package/CHANGELOG.md +38 -1
- package/README.md +33 -13
- package/homepage/example.css +4 -0
- package/homepage/example.js +1 -0
- package/homepage/index.html +26 -0
- package/i18n/.eslintrc.js +12 -0
- package/i18n/fetch-languages-sheets.js +62 -0
- package/lib/RemoteCalibrator.min.js +1 -1
- package/lib/RemoteCalibrator.min.js.LICENSE.txt +1 -1
- package/lib/RemoteCalibrator.min.js.map +1 -1
- package/package.json +12 -8
- package/src/components/buttons.js +4 -3
- package/src/components/language.js +31 -0
- package/src/components/onCanvas.js +4 -8
- package/src/components/swalOptions.js +25 -23
- package/src/{helpers.js → components/utils.js} +8 -2
- package/src/{video.js → components/video.js} +23 -4
- package/src/const.js +23 -3
- package/src/core.js +106 -6
- package/src/css/distance.scss +12 -7
- package/src/css/main.css +65 -10
- package/src/css/panel.scss +1 -1
- package/src/css/screenSize.css +28 -14
- package/src/debug.js +2 -0
- package/src/displaySize.js +1 -1
- package/src/distance/distance.js +20 -13
- package/src/distance/distanceTrack.js +9 -8
- package/src/gaze/gaze.js +22 -20
- package/src/gaze/gazeAccuracy.js +3 -4
- package/src/gaze/gazeCalibration.js +30 -22
- package/src/gaze/gazeTracker.js +4 -2
- package/src/i18n.js +6 -0
- package/src/index.js +1 -1
- package/src/interpupillaryDistance.js +34 -18
- package/src/{panel/panel.js → panel.js} +57 -21
- package/src/screenSize.js +72 -35
- package/src/constants.js +0 -11
- package/src/text.json +0 -34
package/src/screenSize.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import RemoteCalibrator from './core'
|
2
|
-
import { toFixedNumber, blurAll, remap } from './
|
2
|
+
import { toFixedNumber, blurAll, remap } from './components/utils'
|
3
3
|
|
4
4
|
import Card from './media/card.svg'
|
5
5
|
import Arrow from './media/arrow.svg'
|
@@ -7,8 +7,7 @@ import USBA from './media/usba.svg'
|
|
7
7
|
import USBC from './media/usbc.svg'
|
8
8
|
import { bindKeys, unbindKeys } from './components/keyBinder'
|
9
9
|
import { addButtons } from './components/buttons'
|
10
|
-
import {
|
11
|
-
import text from './text.json'
|
10
|
+
import { phrases } from './i18n'
|
12
11
|
|
13
12
|
// TODO Make it customizable
|
14
13
|
const defaultObj = 'usba'
|
@@ -50,19 +49,30 @@ RemoteCalibrator.prototype.screenSize = function (options = {}, callback) {
|
|
50
49
|
quitFullscreenOnFinished: false,
|
51
50
|
repeatTesting: 1,
|
52
51
|
decimalPlace: 1,
|
53
|
-
headline:
|
54
|
-
description:
|
52
|
+
headline: '🖥️ ' + phrases.RC_screenSizeTitle[this.L],
|
53
|
+
description: phrases.RC_screenSizeIntro[this.L],
|
55
54
|
},
|
56
55
|
options
|
57
56
|
)
|
58
57
|
|
59
58
|
this.getFullscreen(options.fullscreen)
|
60
59
|
|
61
|
-
options.description += `<br /><b
|
60
|
+
options.description += `<br /><br /><b class="rc-size-obj-selection">${phrases.RC_screenSizeHave[
|
61
|
+
this.L
|
62
|
+
].replace(
|
63
|
+
'xxx',
|
64
|
+
`<select id="matching-obj"><option value="usba" selected>${
|
65
|
+
phrases.RC_screenSizeUSBA[this.L]
|
66
|
+
}</option><option value="usbc">${
|
67
|
+
phrases.RC_screenSizeUSBC[this.L]
|
68
|
+
}</option><option value="card">${
|
69
|
+
phrases.RC_screenSizeCreditCard[this.L]
|
70
|
+
}</option></select>`
|
71
|
+
)}</b>`
|
62
72
|
|
63
73
|
this._addBackground()
|
64
74
|
this._addBackgroundText(options.headline, options.description)
|
65
|
-
this._addCreditOnBackground(this.
|
75
|
+
this._addCreditOnBackground(phrases.RC_screenSizeCredit[this.L])
|
66
76
|
|
67
77
|
getSize(this, this.background, options, callback)
|
68
78
|
|
@@ -72,8 +82,8 @@ RemoteCalibrator.prototype.screenSize = function (options = {}, callback) {
|
|
72
82
|
function getSize(RC, parent, options, callback) {
|
73
83
|
// Slider
|
74
84
|
const sliderElement = document.createElement('input')
|
75
|
-
sliderElement.id = 'size-slider'
|
76
|
-
sliderElement.className = 'slider'
|
85
|
+
sliderElement.id = 'rc-size-slider'
|
86
|
+
sliderElement.className = 'rc-slider'
|
77
87
|
sliderElement.type = 'range'
|
78
88
|
sliderElement.min = 0
|
79
89
|
sliderElement.max = 100
|
@@ -84,28 +94,38 @@ function getSize(RC, parent, options, callback) {
|
|
84
94
|
sliderElement.step = 0.1
|
85
95
|
|
86
96
|
setSliderPosition(sliderElement, parent)
|
97
|
+
setSliderStyle(sliderElement)
|
87
98
|
parent.appendChild(sliderElement)
|
88
99
|
|
89
|
-
const
|
100
|
+
const _onDown = (e, type) => {
|
90
101
|
if (
|
91
|
-
e.target.className === 'slider' &&
|
92
|
-
e.target.id === 'size-slider' &&
|
93
|
-
e.which === 1
|
102
|
+
e.target.className === 'rc-slider' &&
|
103
|
+
e.target.id === 'rc-size-slider' &&
|
104
|
+
((type === RC._CONST.S.CLICK_TYPE.MOUSE && e.which === 1) ||
|
105
|
+
type === RC._CONST.S.CLICK_TYPE.TOUCH)
|
94
106
|
) {
|
95
107
|
e.target.style.cursor = 'grabbing'
|
96
|
-
arrowFillElement.setAttribute('fill',
|
97
|
-
|
98
|
-
'
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
108
|
+
arrowFillElement.setAttribute('fill', RC._CONST.COLOR.ORANGE)
|
109
|
+
const _onEnd = () => {
|
110
|
+
sliderElement.style.cursor = 'grab'
|
111
|
+
arrowFillElement.setAttribute('fill', RC._CONST.COLOR.LIGHT_GREY)
|
112
|
+
document.removeEventListener('mouseup', _onEnd, false)
|
113
|
+
}
|
114
|
+
if (type === RC._CONST.S.CLICK_TYPE.MOUSE)
|
115
|
+
document.addEventListener('mouseup', _onEnd, false)
|
116
|
+
else if (type === RC._CONST.S.CLICK_TYPE.TOUCH)
|
117
|
+
document.addEventListener('touchend', _onEnd, false)
|
106
118
|
}
|
107
119
|
}
|
120
|
+
|
121
|
+
const onMouseDown = e => {
|
122
|
+
_onDown(e, 'mouse')
|
123
|
+
}
|
124
|
+
const onTouchStart = e => {
|
125
|
+
_onDown(e, 'touch')
|
126
|
+
}
|
108
127
|
document.addEventListener('mousedown', onMouseDown, false)
|
128
|
+
document.addEventListener('touchstart', onTouchStart, false)
|
109
129
|
|
110
130
|
// Add all objects
|
111
131
|
const elements = addMatchingObj(['card', 'arrow', 'usba', 'usbc'], parent)
|
@@ -113,27 +133,28 @@ function getSize(RC, parent, options, callback) {
|
|
113
133
|
// Switch OBJ
|
114
134
|
let currentMatchingObj = defaultObj // DEFAULT
|
115
135
|
document.getElementById('matching-obj').addEventListener('change', e => {
|
116
|
-
switchMatchingObj(e.target.value, elements)
|
136
|
+
switchMatchingObj(e.target.value, elements, setSizes)
|
117
137
|
currentMatchingObj = e.target.value
|
118
138
|
})
|
119
139
|
|
120
140
|
switchMatchingObj('card', elements)
|
121
141
|
// Card & Arrow
|
122
142
|
let arrowFillElement = document.getElementById('size-arrow-fill')
|
123
|
-
arrowFillElement.setAttribute('fill',
|
143
|
+
arrowFillElement.setAttribute('fill', RC._CONST.COLOR.LIGHT_GREY)
|
124
144
|
let arrowSizes = {
|
125
145
|
width: elements.arrow.getBoundingClientRect().width,
|
126
146
|
height: elements.arrow.getBoundingClientRect().height,
|
127
147
|
}
|
128
148
|
|
129
149
|
const setSizes = () => {
|
130
|
-
setCardSizes(sliderElement, elements.card, elements.arrow, arrowSizes)
|
150
|
+
setCardSizes(RC, sliderElement, elements.card, elements.arrow, arrowSizes)
|
131
151
|
setConnectorSizes(sliderElement, elements.usba)
|
132
152
|
setConnectorSizes(sliderElement, elements.usbc)
|
133
153
|
}
|
134
|
-
setSizes()
|
135
154
|
|
155
|
+
setSizes()
|
136
156
|
const onSliderInput = () => {
|
157
|
+
setSliderStyle(sliderElement)
|
137
158
|
setSizes()
|
138
159
|
}
|
139
160
|
const resizeObserver = new ResizeObserver(() => {
|
@@ -146,6 +167,7 @@ function getSize(RC, parent, options, callback) {
|
|
146
167
|
// Call when ESC pressed
|
147
168
|
const breakFunction = () => {
|
148
169
|
document.removeEventListener('mousedown', onMouseDown, false)
|
170
|
+
document.removeEventListener('touchstart', onTouchStart, false)
|
149
171
|
document.removeEventListener('input', onSliderInput, false)
|
150
172
|
resizeObserver.unobserve(parent)
|
151
173
|
RC._removeBackground()
|
@@ -181,11 +203,12 @@ function getSize(RC, parent, options, callback) {
|
|
181
203
|
sliderElement.addEventListener('input', onSliderInput, false)
|
182
204
|
const bindKeysFunction = bindKeys({
|
183
205
|
Escape: breakFunction,
|
206
|
+
Enter: finishFunction,
|
184
207
|
' ': finishFunction,
|
185
|
-
Enter: () => {},
|
186
208
|
})
|
187
209
|
|
188
210
|
addButtons(
|
211
|
+
RC.L,
|
189
212
|
RC.background,
|
190
213
|
{
|
191
214
|
go: finishFunction,
|
@@ -195,10 +218,10 @@ function getSize(RC, parent, options, callback) {
|
|
195
218
|
)
|
196
219
|
|
197
220
|
// Set to actual default object
|
198
|
-
switchMatchingObj(currentMatchingObj, elements)
|
221
|
+
switchMatchingObj(currentMatchingObj, elements, setSizes)
|
199
222
|
}
|
200
223
|
|
201
|
-
const setCardSizes = (slider, card, arrow, aS) => {
|
224
|
+
const setCardSizes = (RC, slider, card, arrow, aS) => {
|
202
225
|
// Card
|
203
226
|
const targetWidth =
|
204
227
|
(slider.offsetWidth - 30) *
|
@@ -211,7 +234,10 @@ const setCardSizes = (slider, card, arrow, aS) => {
|
|
211
234
|
if (cardSizes.width !== 0) {
|
212
235
|
arrow.style.left = cardSizes.left + targetWidth + 'px'
|
213
236
|
arrow.style.top =
|
214
|
-
cardSizes.top +
|
237
|
+
cardSizes.top +
|
238
|
+
RC.background.scrollTop +
|
239
|
+
(targetWidth * 0.63 - aS.height) / 2 +
|
240
|
+
'px'
|
215
241
|
}
|
216
242
|
}
|
217
243
|
|
@@ -239,18 +265,20 @@ const addMatchingObj = (names, parent) => {
|
|
239
265
|
elements[name] = element
|
240
266
|
}
|
241
267
|
|
242
|
-
setObjectsPosition(elements, document.querySelector('#size-slider'))
|
268
|
+
setObjectsPosition(elements, document.querySelector('#rc-size-slider'))
|
243
269
|
|
244
270
|
return elements
|
245
271
|
}
|
246
272
|
|
247
|
-
const switchMatchingObj = (name, elements) => {
|
273
|
+
const switchMatchingObj = (name, elements, setSizes) => {
|
248
274
|
for (let obj in elements) {
|
249
275
|
if (obj === name) elements[obj].style.visibility = 'visible'
|
250
276
|
else elements[obj].style.visibility = 'hidden'
|
251
277
|
}
|
252
|
-
if (name === 'card') elements.arrow.style.visibility = 'visible'
|
253
|
-
else elements.arrow.style.visibility = 'hidden'
|
278
|
+
// if (name === 'card') elements.arrow.style.visibility = 'visible'
|
279
|
+
// else elements.arrow.style.visibility = 'hidden'
|
280
|
+
elements.arrow.style.visibility = 'hidden'
|
281
|
+
if (setSizes) setSizes()
|
254
282
|
}
|
255
283
|
|
256
284
|
/**
|
@@ -300,3 +328,12 @@ const setObjectsPosition = (objects, slider) => {
|
|
300
328
|
for (let i in objects)
|
301
329
|
objects[i].style.top = slider.getBoundingClientRect().top + 50 + 'px'
|
302
330
|
}
|
331
|
+
|
332
|
+
/* -------------------------------------------------------------------------- */
|
333
|
+
|
334
|
+
const setSliderStyle = ele => {
|
335
|
+
const ratio = ele.value / ele.max
|
336
|
+
ele.style.background = `linear-gradient(90deg, #ffc772, #ffc772 ${
|
337
|
+
ratio * 100
|
338
|
+
}%, #fff ${ratio * 100}%)`
|
339
|
+
}
|
package/src/constants.js
DELETED
package/src/text.json
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"screenSize": {
|
3
|
-
"headline": "🖥️ Screen Size Calibration",
|
4
|
-
"description": "We will measure your screen size. Find a <b>USB connector</b> (like the one providing power to your laptop) or a <b>credit card</b> (or any card of the same size), place it on the screen and drag the slider to match the sizes of the physical and displayed objects. When the sizes match, press <b>SPACE</b> or click <b>OK</b>."
|
5
|
-
},
|
6
|
-
"measureDistance": {
|
7
|
-
"headline": "📏 Measure Viewing Distance",
|
8
|
-
"description": "We'll measure your viewing distance. To do this, we will perform a blind spot test. Close/Cover one of your eyes (as instructed below) and focus on the black crosshair. Press <b>SPACE</b> or click <b>OK</b> when the red circle disappears. If it doesn't disappear, try moving closer to the screen."
|
9
|
-
},
|
10
|
-
"trackDistance": {
|
11
|
-
"headline": "🙂 Set up for Head Tracking",
|
12
|
-
"description": "Now we'll set up head tracking, to monitor viewing distance. When asked, please grant permission to access your camera. We'll perform a blind spot test first. Close/Cover one of your eyes (as instructed below) and focus on the black crosshair. Please press <b>SPACE</b> or click <b>OK</b> when the red dot disappears. If it doesn't disappear, try moving closer to the screen. You'll do this twice with each eye. Once you're done, head tracking will begin."
|
13
|
-
},
|
14
|
-
"calibrateGaze": {
|
15
|
-
"headline": "👀 Set up for Gaze Tracking",
|
16
|
-
"description": "Now we'll set up gaze tracking, to monitor eye position. When asked, please grant permission to access your camera. Try to keep your face centered in the video feed. Click on the <b style=\"color: #ff005c\">pink dot</b> at each location that it stops at. Make sure that your eyes are on the dot when you click."
|
17
|
-
},
|
18
|
-
"getGazeAccuracy": {
|
19
|
-
"headline": "👀 Get Gaze Accuracy",
|
20
|
-
"description": "We will measure your gaze accuracy. Please do not move the mouse and look at the fixation at the middle of the screen for the next 5 seconds."
|
21
|
-
},
|
22
|
-
"panel": {
|
23
|
-
"headline": "Please press a button, to calibrate.",
|
24
|
-
"description": "",
|
25
|
-
"nextHeadline": "Thanks for calibrating. Hit the button to continue.",
|
26
|
-
"nextDescription": "",
|
27
|
-
"nextButton": "Done"
|
28
|
-
},
|
29
|
-
"measurePD": {
|
30
|
-
"headline": "👁️ Measure Pupillary Distance",
|
31
|
-
"description": "We'll measure the distance between the centers of your eyes. Hold the cable to your eyes, align the thumbs with the centers of your pupils. Then hold the cable against the ruler and align the left thumb with zero, check where the right thumb is. Finally, click on the ruler and click <b>OK</b> to submit your measurement. You can use the video image as a reference. If you do have a ruler with you, go ahead and use it.",
|
32
|
-
"shortDescription": "Hold the cable to your eyes, align the thumbs with the centers of your pupils. Then hold the cable against the ruler and align the left thumb with zero, check where the right thumb is. Finally, click on the ruler and click <b>OK</b> to submit your measurement. You can use the video image as a reference. If you do have a ruler with you, go ahead and use it."
|
33
|
-
}
|
34
|
-
}
|