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/.eslintrc.js
CHANGED
package/.husky/pre-commit
CHANGED
package/.prettierignore
CHANGED
package/CHANGELOG.md
CHANGED
@@ -9,9 +9,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
9
9
|
|
10
10
|
### Added
|
11
11
|
|
12
|
+
**i18n!**
|
13
|
+
|
14
|
+
- Internationalization! A full list of supported languages can be found at https://docs.google.com/spreadsheets/d/1UFfNikfLuo8bSromE34uWDuJrMPFiJG3VpoQKdCGkII/edit#gid=0.
|
15
|
+
- A few new getters related to languages:
|
16
|
+
- `.userLanguage` (as a part of `.environment()`)
|
17
|
+
- `.language` (e.g., `en-US`, `zh-CN`)
|
18
|
+
- `.languageNameEnglish` (e.g., `English`, `Chinese (Simplified)`)
|
19
|
+
- `.languageNameNative` (e.g., `简体中文`)
|
20
|
+
- `.languageDirection` (`LTR` or `RTL`)
|
21
|
+
- `.languagePhraseSource` (e.g., `Denis Pelli & Peiling Jiang 2021.10.10`)
|
22
|
+
- `.languageData` gets the whole data history of languages.
|
23
|
+
- `.supportedLanguages` gets an array of supported languages.
|
24
|
+
- `.newLanguage(lang = 'en-US')` to set a new language for the calibrator.
|
25
|
+
- Allows researchers to set language on initialization using the `language` option. Set to `AUTO` (default) will let the calibrator go with the user language.
|
26
|
+
- `.isMobile` getter.
|
27
|
+
- Call `.environment()` automatically when initializing the calibrator.
|
28
|
+
- Instructions in the viewing distance measurement (and head tracking setup) is scrollable to avoid overlapping with the canvas on small screen sizes.
|
29
|
+
|
30
|
+
### Changed
|
31
|
+
|
32
|
+
- Improved UI and performance for small screens and mobile devices.
|
33
|
+
- Take Return instead of Space for confirming screen size measurement.
|
34
|
+
|
35
|
+
### Removed
|
36
|
+
|
37
|
+
- The responsive arrow in the screen size calibration with credit card.
|
38
|
+
|
39
|
+
## [0.2.3] - 2021-10-05
|
40
|
+
|
41
|
+
### Added
|
42
|
+
|
43
|
+
- (Breaking) Callback function of gaze tracking is split into two functions: `callbackOnCalibrationEnd` that will only be called once when calibration ends, and `callbackTrack` that will be called continuously as the tracking runs (with data parameter passed in).
|
12
44
|
- `sparkle` option (default `true`) for measuring and tracking viewing distance. The red dot sparkles at 10 Hz to make it more prominent when absent from the view.
|
13
45
|
- Ignore the Return key in screen size calibration.
|
14
46
|
|
47
|
+
### Fixed
|
48
|
+
|
49
|
+
- Panel final callback function is called multiple times if gaze tracking is the last calibration task.
|
50
|
+
|
15
51
|
## [0.2.2] - 2021-10-04
|
16
52
|
|
17
53
|
### Added
|
@@ -207,7 +243,8 @@ No new feature updates in this release. Updated dependency packages and the lice
|
|
207
243
|
|
208
244
|
The framework and some basic functions, e.g., screen size calibration. Released for integration testing.
|
209
245
|
|
210
|
-
[unreleased]: https://github.com/EasyEyes/remote-calibrator/compare/v0.2.
|
246
|
+
[unreleased]: https://github.com/EasyEyes/remote-calibrator/compare/v0.2.3...develop
|
247
|
+
[0.2.3]: https://github.com/EasyEyes/remote-calibrator/compare/v0.2.2...v0.2.3
|
211
248
|
[0.2.2]: https://github.com/EasyEyes/remote-calibrator/compare/v0.2.1...v0.2.2
|
212
249
|
[0.2.1]: https://github.com/EasyEyes/remote-calibrator/compare/v0.2.0...v0.2.1
|
213
250
|
[0.2.0]: https://github.com/EasyEyes/remote-calibrator/compare/v0.1.1...v0.2.0
|
package/README.md
CHANGED
@@ -52,13 +52,13 @@ RemoteCalibrator.measureDistance({}, data => {
|
|
52
52
|
| [🎬 Initialize](#-initialize) | [`init()`](#-initialize) (always required) |
|
53
53
|
| [🍱 Panel](#-panel) | [`async panel()`](#-panel) `removePanel()` `resetPanel()` |
|
54
54
|
| [🖥️ Screen](#️-screen) | [`displaySize()`](#measure-display-pixels) [`screenSize()`](#measure-screen-size) |
|
55
|
-
| [📏 Viewing Distance](#-viewing-distance) | `measureDistance()`
|
55
|
+
| [📏 Viewing Distance](#-viewing-distance) | [`measureDistance()`](#-viewing-distance) |
|
56
56
|
| [🙂 Head Tracking](#-head-tracking) | (viewing distance and [near point](#near-point)) [`trackDistance()`](#-head-tracking) [`async getDistanceNow()`](#async-get-distance-now) [Lifecycle](#lifecycle) [Others](#others) |
|
57
57
|
| [👀 Gaze](#-gaze) | [`trackGaze()`](#start-tracking) [`async getGazeNow()`](#async-get-gaze-now) [`calibrateGaze()`](#calibrate) [`getGazeAccuracy()`](#get-accuracy-) [Lifecycle](#lifecycle-1) [Others](#others-1) |
|
58
58
|
| [💻 Environment](#-environment) | [`environment()`](#-environment) |
|
59
59
|
| [💄 Customization](#-customization) | `backgroundColor()` `videoOpacity()` `showCancelButton()` |
|
60
|
-
| [📔 Other Functions](#-other-functions) | `checkInitialized()` `getFullscreen()`
|
61
|
-
| [🎣 Getters](#-getters) | [Experiment](#experiment) [Environment](#environment) [All Data](#all-data) [Others](#others-2)
|
60
|
+
| [📔 Other Functions](#-other-functions) | `checkInitialized()` `getFullscreen()` `newLanguage()` |
|
61
|
+
| [🎣 Getters](#-getters) | [Experiment](#experiment) [Environment](#environment) [i18n](#i18n) [All Data](#all-data) [Others](#others-2) |
|
62
62
|
|
63
63
|
Arguments in square brackets are optional, e.g. `init([options, [callback]])` means both `options` configuration and the `callback` function are optional, but you have to put `options`, e.g., `{}`, if you want to call the callback function. The default values of `options` are listed in each section with explanation.
|
64
64
|
|
@@ -81,8 +81,17 @@ Pass `{ value, timestamp }` (equivalent to `RemoteCalibrator.id`) to callback.
|
|
81
81
|
* A random one will be generated if no value is passed into the function
|
82
82
|
*/
|
83
83
|
id: /* Randomized value */,
|
84
|
-
|
85
|
-
|
84
|
+
/**
|
85
|
+
* Set the language, e.g., 'en-US', 'zh-CN'
|
86
|
+
* If set to 'AUTO' (default), the calibrator will try to follow the browser settings
|
87
|
+
* A full list of supported languages can be found at
|
88
|
+
* https://docs.google.com/spreadsheets/d/1UFfNikfLuo8bSromE34uWDuJrMPFiJG3VpoQKdCGkII/edit#gid=0
|
89
|
+
*/
|
90
|
+
language: 'AUTO',
|
91
|
+
/**
|
92
|
+
* Enter full screen if set to true
|
93
|
+
* Will be ignored if already in full screen mode
|
94
|
+
*/
|
86
95
|
fullscreen: false,
|
87
96
|
}
|
88
97
|
```
|
@@ -112,11 +121,9 @@ The `data` passed into the callback function is an [object](https://www.w3school
|
|
112
121
|
![Panel](./media/panel.png)
|
113
122
|
|
114
123
|
```js
|
115
|
-
.panel(tasks, parentQuery, [options, [callback, [resolveOnFinish]]])
|
124
|
+
/* async */ .panel(tasks, parentQuery, [options, [callback, [resolveOnFinish]]])
|
116
125
|
```
|
117
126
|
|
118
|
-
**Since 0.2.0:** `.panel()` is now an async function.
|
119
|
-
|
120
127
|
`.panel()` is a powerful tool to help you set up a graphical user interface for participants to go through step-by-step and calibrate or set up tracking. It is highly customizable: tasks, task order, title, description, and "Done" button can all be customized. It is appended to the parent HTML node as set by `parentQuery`, e.g., if the parent node has id `main-area`, put `#main-area` as the `parentQuery`. Can only run once. Return a JavaScript [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) that will resolve the `resolveOnFinish` once the "Done" button is pressed.
|
121
128
|
|
122
129
|
`tasks` is an array of tasks which can be a string or an object. Valid names are `screenSize`, `displaySize`, `measureDistance`, `trackDistance`, `trackGaze`, `environment` (system information).
|
@@ -128,7 +135,7 @@ The `data` passed into the callback function is an [object](https://www.w3school
|
|
128
135
|
{
|
129
136
|
name: 'trackGaze',
|
130
137
|
options: { framerate: 60 }, // Same as setting the options for .trackGaze()
|
131
|
-
|
138
|
+
callbackTrack: gotGaze, // Same as setting the callback for .trackGaze()
|
132
139
|
},
|
133
140
|
// Tracking viewing distance accepts two callbacks just like .trackDistance()
|
134
141
|
{
|
@@ -300,14 +307,14 @@ The value returned are the horizontal and vertical offsets, in centimeters, comp
|
|
300
307
|
![Start Gaze Tracking](./media/trackGaze.png)
|
301
308
|
|
302
309
|
```js
|
303
|
-
.trackGaze([options, [
|
310
|
+
.trackGaze([options, [callbackOnCalibrationEnd, [callbackTrack]]])
|
304
311
|
```
|
305
312
|
|
306
313
|
Use [WebGazer](https://github.com/peilingjiang-DEV/WebGazer). Pop an interface for participants to calibrate their gaze position on the screen (only when this function is called for the first time), then run in the background and continuously predict the current gaze position. Require access to the camera of the participant's computer. The callback function will be executed repeatedly **every time** there's a new prediction.
|
307
314
|
|
308
315
|
This function should only be called once, unless you want to change the callback functions for every prediction.
|
309
316
|
|
310
|
-
Pass `{ value: { x, y }, timestamp }` (equivalent to `RemoteCalibrator.gazePositionPx`) to
|
317
|
+
Pass `{ value: { x, y }, timestamp }` (equivalent to `RemoteCalibrator.gazePositionPx`) to `callbackTrack` function.
|
311
318
|
|
312
319
|
```js
|
313
320
|
/* [options] Default value */
|
@@ -391,7 +398,7 @@ Pop an interface for participants to calibrate their gaze position on the screen
|
|
391
398
|
|
392
399
|
Get the setup information of the experiment, including browser type, device model, operating system family and version, etc. This function does not create its own timestamp, but use the one associated with `id`, i.e. the one created when `init()` is called.
|
393
400
|
|
394
|
-
Pass `{ value: { browser, browserVersion, model, manufacturer, engine, system, systemFamily, description, fullDescription }, timestamp }` to callback.
|
401
|
+
Pass `{ value: { browser, browserVersion, model, manufacturer, engine, system, systemFamily, description, fullDescription, userLanguage }, timestamp }` to callback.
|
395
402
|
|
396
403
|
### 💄 Customization
|
397
404
|
|
@@ -403,6 +410,7 @@ Pass `{ value: { browser, browserVersion, model, manufacturer, engine, system, s
|
|
403
410
|
|
404
411
|
- `.checkInitialized()` Check if the model is initialized. Return a boolean.
|
405
412
|
- `.getFullscreen()` Get fullscreen mode.
|
413
|
+
- `.newLanguage(lang = 'en-US')` Set a new language for the calibrator.
|
406
414
|
|
407
415
|
### 🎣 Getters
|
408
416
|
|
@@ -424,10 +432,11 @@ Getters will get `null` if no data can be found, i.e. the corresponding function
|
|
424
432
|
|
425
433
|
The associated timestamp of the following items is the one created at initiation, i.e. when `init()` is called.
|
426
434
|
|
427
|
-
- `.bot` If the user agent is a bot or not,
|
435
|
+
- `.bot` If the user agent is a bot or not, `null` will be returned if no bot detected, e.g., `Googlebot (Search bot) by Google Inc.`.
|
428
436
|
- `.browser` The browser type, e.g., `Safari`, `Chrome`.
|
429
437
|
- `.browserVersion` The browser version.
|
430
438
|
- `.deviceType` The type of device, e.g., `desktop`.
|
439
|
+
- `.isMobile` The type of device is mobile or not.
|
431
440
|
- `.model` The model type of the device, e.g., `iPad`.
|
432
441
|
- `.manufacturer` The device manufacturer.
|
433
442
|
- `.engine` The browser engine, e.g., `Webkit`.
|
@@ -435,6 +444,16 @@ The associated timestamp of the following items is the one created at initiation
|
|
435
444
|
- `.systemFamily` The family name of the device OS, e.g., `OS X`.
|
436
445
|
- `.description` A tidy description of the current environment, e.g., `Chrome 89.0.4389.90 on OS X 11.2.1 64-bit`.
|
437
446
|
- `.fullDescription` The full description of the current environment.
|
447
|
+
- `.userLanguage` The language used in the browser, e.g., `en`.
|
448
|
+
|
449
|
+
#### i18n
|
450
|
+
|
451
|
+
- `.language` (e.g., `en-US`, `zh-CN`)
|
452
|
+
- `.languageNameEnglish` (e.g., `English`, `Chinese (Simplified)`)
|
453
|
+
- `.languageNameNative` (e.g., `简体中文`)
|
454
|
+
- `.languageDirection` (`LTR` or `RTL`)
|
455
|
+
- `.languagePhraseSource` (e.g., `Denis Pelli & Peiling Jiang 2021.10.10`)
|
456
|
+
- `.supportedLanguages` An array of all supported languages. Can be called before initialization.
|
438
457
|
|
439
458
|
#### All Data
|
440
459
|
|
@@ -448,6 +467,7 @@ Use the following keywords to retrieve the whole dataset.
|
|
448
467
|
- `.gazeData`
|
449
468
|
- `.fullScreenData`
|
450
469
|
- `.environmentData`
|
470
|
+
- `.languageData`
|
451
471
|
|
452
472
|
#### Others
|
453
473
|
|
package/homepage/example.css
CHANGED
package/homepage/example.js
CHANGED
package/homepage/index.html
CHANGED
@@ -51,6 +51,8 @@
|
|
51
51
|
>
|
52
52
|
</p>
|
53
53
|
|
54
|
+
<div id="rc-language"></div>
|
55
|
+
|
54
56
|
<h2>Functions</h2>
|
55
57
|
|
56
58
|
<div id="functions" class="flex-wrapper"></div>
|
@@ -128,6 +130,12 @@
|
|
128
130
|
'nearPointCm',
|
129
131
|
'gazePositionPx',
|
130
132
|
'isFullscreen',
|
133
|
+
'id',
|
134
|
+
'language',
|
135
|
+
'languageNameEnglish',
|
136
|
+
'languageNameNative',
|
137
|
+
'languageDirection',
|
138
|
+
'languagePhraseSource',
|
131
139
|
]
|
132
140
|
|
133
141
|
const gettersEnv = [
|
@@ -142,6 +150,7 @@
|
|
142
150
|
'systemFamily',
|
143
151
|
'description',
|
144
152
|
'fullDescription',
|
153
|
+
'userLanguage',
|
145
154
|
'version',
|
146
155
|
]
|
147
156
|
|
@@ -163,6 +172,23 @@
|
|
163
172
|
setGetters(document.getElementById('getters-exp'), gettersExp)
|
164
173
|
setGetters(document.getElementById('getters-env'), gettersEnv)
|
165
174
|
|
175
|
+
// i18n
|
176
|
+
const langPickerParent = document.getElementById('rc-language')
|
177
|
+
let langInner = '<select name="lang" id="lang-picker">'
|
178
|
+
for (let lang of RemoteCalibrator.supportedLanguages) {
|
179
|
+
langInner += `<option value="${lang.language}">${lang.languageNameNative}</option>`
|
180
|
+
}
|
181
|
+
langInner += '</select>'
|
182
|
+
langPickerParent.innerHTML = langInner
|
183
|
+
|
184
|
+
document.querySelector('#lang-picker').onchange = e => {
|
185
|
+
RemoteCalibrator.newLanguage(
|
186
|
+
document.querySelector('#lang-picker').value
|
187
|
+
)
|
188
|
+
RemoteCalibrator.resetPanel()
|
189
|
+
}
|
190
|
+
//
|
191
|
+
|
166
192
|
initialize({ target: document.getElementById('init-button') })
|
167
193
|
</script>
|
168
194
|
<!-- GitHub corner -->
|
@@ -0,0 +1,62 @@
|
|
1
|
+
const process = require('process')
|
2
|
+
const fs = require('fs')
|
3
|
+
const XLSX = require('xlsx')
|
4
|
+
const google = require('googleapis')
|
5
|
+
|
6
|
+
const auth = new google.Auth.GoogleAuth({
|
7
|
+
keyFile: `${__dirname}/credentials.json`,
|
8
|
+
scopes: 'https://www.googleapis.com/auth/spreadsheets',
|
9
|
+
})
|
10
|
+
|
11
|
+
async function processLanguageSheet() {
|
12
|
+
const spreadsheetId = '1UFfNikfLuo8bSromE34uWDuJrMPFiJG3VpoQKdCGkII'
|
13
|
+
const googleSheets = new google.sheets_v4.Sheets()
|
14
|
+
const rows = await googleSheets.spreadsheets.values.get({
|
15
|
+
auth,
|
16
|
+
spreadsheetId,
|
17
|
+
range: 'Sheet1',
|
18
|
+
})
|
19
|
+
|
20
|
+
const rowsJSON = XLSX.utils.sheet_to_json(
|
21
|
+
XLSX.utils.aoa_to_sheet(rows.data.values),
|
22
|
+
{
|
23
|
+
defval: '',
|
24
|
+
}
|
25
|
+
)
|
26
|
+
|
27
|
+
const data = {}
|
28
|
+
for (let phrase of rowsJSON) {
|
29
|
+
const { language, ...translations } = phrase
|
30
|
+
if (language.includes('RC_') || language.includes('EE_'))
|
31
|
+
data[language] = translations
|
32
|
+
}
|
33
|
+
|
34
|
+
const exportWarning = `/*
|
35
|
+
Do not modify this file! Run npm \`npm run phrases\` at ROOT of this project to fetch from the Google Sheets.
|
36
|
+
https://docs.google.com/spreadsheets/d/1UFfNikfLuo8bSromE34uWDuJrMPFiJG3VpoQKdCGkII/edit#gid=0
|
37
|
+
*/\n\n`
|
38
|
+
const exportHandle = `export const phrases = `
|
39
|
+
|
40
|
+
fs.writeFile(
|
41
|
+
`${process.cwd()}/src/i18n.js`,
|
42
|
+
exportWarning + exportHandle + JSON.stringify(data) + '\n',
|
43
|
+
error => {
|
44
|
+
if (error) {
|
45
|
+
console.log("Error! Couldn't write to the file.", error)
|
46
|
+
} else {
|
47
|
+
console.log(
|
48
|
+
'EasyEyes International Phrases fetched and written into files successfully.'
|
49
|
+
)
|
50
|
+
}
|
51
|
+
}
|
52
|
+
)
|
53
|
+
}
|
54
|
+
|
55
|
+
require('dns').resolve('www.google.com', function (err) {
|
56
|
+
if (err) {
|
57
|
+
console.log('No internet connection. Skip fetching phrases.')
|
58
|
+
} else {
|
59
|
+
console.log('Fetching up-to-date phrases...')
|
60
|
+
processLanguageSheet()
|
61
|
+
}
|
62
|
+
})
|