remove svg dependency, update plugin behavior

This commit is contained in:
Josh de Leeuw 2022-04-07 10:34:59 -04:00
parent 5b1a967be3
commit 99bf2924be
6 changed files with 356 additions and 101 deletions

View File

@ -0,0 +1,10 @@
---
"@jspsych/plugin-virtual-chinrest": major
---
Several changes to this plugin:
* Removed dependency on svg.js
* Added a reset between each blind spot measurement for clarity
* Moved starting location of square and dot to right edge of screen for maximum compatibility with large viewing distances
* Refactored code

View File

@ -11,14 +11,6 @@ The plugin works in two phases.
**Phase 2**. To measure the participant's viewing distance from their screen we use a [blind spot](<https://en.wikipedia.org/wiki/Blind_spot_(vision)>) task. Participants are asked to focus on a black square on the screen with their right eye closed, while a red dot repeatedly sweeps from right to left. They press the spacebar on their keyboard whenever they perceive that the red dot has disappeared. This part allows the plugin to use the distance between the black square and the red dot when it disappears from eyesight to estimate how far the participant is from the monitor. This estimation assumes that the blind spot is located at 13.5° temporally.
## Dependency
This plugin requires the SVG.js library, available at [https://svgjs.com](https://svgjs.com/docs/3.0/) or via the CDN link below. You must include the library in the `<head>` section of your experiment page.
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.3/svg.min.js"></script>
```
## Parameters
Parameters can be left unspecified if the default value is acceptable.

View File

@ -45,7 +45,7 @@
// note: pixels_per_unit will be ignored
let no_resize = {
type: jsPsychVirtualChinrest,
blindspot_reps: 1,
blindspot_reps: 3,
resize_units: "none",
pixels_per_unit: 50
};
@ -65,7 +65,7 @@
prompt: '<p>The stimulus above should be 4cm x 4cm if resizing worked properly.</p>'
};
jsPsych.run([no_resize, validation_trial]); // deg_resize, no_resize, error_trial
jsPsych.run([cm_resize, validation_trial]); // deg_resize, no_resize, error_trial
</script>
</html>

290
package-lock.json generated
View File

@ -15,7 +15,7 @@
"lint-staged": "^12.3.5",
"prettier": "^2.5.1",
"prettier-plugin-import-sort": "^0.0.7",
"turbo": "^1.1.6"
"turbo": "^1.1.10"
},
"engines": {
"node": ">=14.0.0",
@ -14115,40 +14115,185 @@
}
},
"node_modules/turbo": {
"version": "1.1.6",
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo/-/turbo-1.1.10.tgz",
"integrity": "sha512-y8vx8uIyBRFI3aFjZ3PeGaOvYtNk6t7xNLzRsPY+xtnknTeqdBad56ElS8z+j0RyVwKCvI+wgvTHGkEle4VnJA==",
"dev": true,
"hasInstallScript": true,
"license": "MPL-2.0",
"bin": {
"turbo": "bin/turbo"
},
"optionalDependencies": {
"turbo-darwin-64": "1.1.6",
"turbo-darwin-arm64": "1.1.6",
"turbo-freebsd-64": "1.1.6",
"turbo-freebsd-arm64": "1.1.6",
"turbo-linux-32": "1.1.6",
"turbo-linux-64": "1.1.6",
"turbo-linux-arm": "1.1.6",
"turbo-linux-arm64": "1.1.6",
"turbo-linux-mips64le": "1.1.6",
"turbo-linux-ppc64le": "1.1.6",
"turbo-windows-32": "1.1.6",
"turbo-windows-64": "1.1.6"
"turbo-darwin-64": "1.1.10",
"turbo-darwin-arm64": "1.1.10",
"turbo-freebsd-64": "1.1.10",
"turbo-freebsd-arm64": "1.1.10",
"turbo-linux-32": "1.1.10",
"turbo-linux-64": "1.1.10",
"turbo-linux-arm": "1.1.10",
"turbo-linux-arm64": "1.1.10",
"turbo-linux-mips64le": "1.1.10",
"turbo-linux-ppc64le": "1.1.10",
"turbo-windows-32": "1.1.10",
"turbo-windows-64": "1.1.10"
}
},
"node_modules/turbo-linux-64": {
"version": "1.1.6",
"node_modules/turbo-darwin-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.1.10.tgz",
"integrity": "sha512-MY/1mHg+tS/GaZKG805e5JSGNS8A4j/M2GzLwCbNL+lwGMfneNASri1vAd80ss3T2MgMsfsFMVyIQJljqpDBvA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/turbo-darwin-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.1.10.tgz",
"integrity": "sha512-gMPLseYqGKwdy6UHVWKMLA433ZTfQRV5FlYz5n4XVtx30cF6ajOqq12ykeCUUX/lZkH4Uq5zT0tNEYpUhUw7mA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
]
},
"node_modules/turbo-freebsd-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-freebsd-64/-/turbo-freebsd-64-1.1.10.tgz",
"integrity": "sha512-wra27mvakr5ZFceQnCCSR8gHQtKV8Q0EhtzO/wEdyhEssw0wVaNtMHUOOdvFN0HLmjQmmLZgmfZbURc83UDuZQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/turbo-freebsd-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-freebsd-arm64/-/turbo-freebsd-arm64-1.1.10.tgz",
"integrity": "sha512-J2I76pTwtrEVjHt1+zWY/s/Y0YIGdWHBIWOjhCXi1E8dav98oGw+WUaiFwzAkcksAblOhNpDL3qhnrnm7kHqrg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
]
},
"node_modules/turbo-linux-32": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-32/-/turbo-linux-32-1.1.10.tgz",
"integrity": "sha512-d1ILhEv2B/lOtpH4niFUKGb8YMU6G7gNCQCY6wG+SXARWJtDti+KiNWESechD5DycCIMgtE40XNy/c1US+LI5g==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-linux-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.1.10.tgz",
"integrity": "sha512-8VEOiNJFNfUMZOyrN32wOcdT1Ik1nlIuTwkO4UeonAJhuWjTvdDLPCQkz0SECTu60q90l6nXCnNYtoZA6LrZzA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-linux-arm": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-arm/-/turbo-linux-arm-1.1.10.tgz",
"integrity": "sha512-qJ50K/s5MjpHjam+UdnK3GniEIv5XOBCZOGslgMMyz8V/q43vhB9BU9HQODclM89uQgsKxhs8Fue6ytOY4vIpg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-linux-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.1.10.tgz",
"integrity": "sha512-ng3dEEL4SbBudF/UZzsOrfyJh8DLtTHawTepeS30FdtvYuVBXdCPc5BAhbawGoau/2AV4vrN3qzh9e3LCqD6Qg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-linux-mips64le": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-mips64le/-/turbo-linux-mips64le-1.1.10.tgz",
"integrity": "sha512-Jd4yH7ZEXCo0xmdJWZ6YsyqcNLyL5vRU3j5ZT+1W97YJCT+g+1on3/nd3rBVPzVz52lb8JIqgGtrBrnOO0AWJg==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-linux-ppc64le": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-ppc64le/-/turbo-linux-ppc64le-1.1.10.tgz",
"integrity": "sha512-YF8+Oi53glqY29O1A7KJsHZxBzeVBobYFnPEXMt8vm+ouuo8kkbxXxShOP4h+33YGEkesTw/CTXtfDC1Xj1hDw==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
]
},
"node_modules/turbo-windows-32": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-windows-32/-/turbo-windows-32-1.1.10.tgz",
"integrity": "sha512-IO92tVTCtWVPPgcCjf8J7AmBEcwnjv1zPq7t9GFdqZ/6QA06atgPJNzQ/QvyzbzJgUsJUN2ByzwT04o4QUbrBQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/turbo-windows-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.1.10.tgz",
"integrity": "sha512-g/RIXaVDaOgliHEJuOsuB6Tefwue9fXBH1/iIH9dmT3Z7lL0banGh+C10RW6Jd6PBPMoPBWir9PLYuzxoPcCNQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
]
},
"node_modules/type": {
"version": "1.2.0",
"license": "ISC"
@ -25552,25 +25697,106 @@
}
},
"turbo": {
"version": "1.1.6",
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo/-/turbo-1.1.10.tgz",
"integrity": "sha512-y8vx8uIyBRFI3aFjZ3PeGaOvYtNk6t7xNLzRsPY+xtnknTeqdBad56ElS8z+j0RyVwKCvI+wgvTHGkEle4VnJA==",
"dev": true,
"requires": {
"turbo-darwin-64": "1.1.6",
"turbo-darwin-arm64": "1.1.6",
"turbo-freebsd-64": "1.1.6",
"turbo-freebsd-arm64": "1.1.6",
"turbo-linux-32": "1.1.6",
"turbo-linux-64": "1.1.6",
"turbo-linux-arm": "1.1.6",
"turbo-linux-arm64": "1.1.6",
"turbo-linux-mips64le": "1.1.6",
"turbo-linux-ppc64le": "1.1.6",
"turbo-windows-32": "1.1.6",
"turbo-windows-64": "1.1.6"
"turbo-darwin-64": "1.1.10",
"turbo-darwin-arm64": "1.1.10",
"turbo-freebsd-64": "1.1.10",
"turbo-freebsd-arm64": "1.1.10",
"turbo-linux-32": "1.1.10",
"turbo-linux-64": "1.1.10",
"turbo-linux-arm": "1.1.10",
"turbo-linux-arm64": "1.1.10",
"turbo-linux-mips64le": "1.1.10",
"turbo-linux-ppc64le": "1.1.10",
"turbo-windows-32": "1.1.10",
"turbo-windows-64": "1.1.10"
}
},
"turbo-darwin-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.1.10.tgz",
"integrity": "sha512-MY/1mHg+tS/GaZKG805e5JSGNS8A4j/M2GzLwCbNL+lwGMfneNASri1vAd80ss3T2MgMsfsFMVyIQJljqpDBvA==",
"dev": true,
"optional": true
},
"turbo-darwin-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.1.10.tgz",
"integrity": "sha512-gMPLseYqGKwdy6UHVWKMLA433ZTfQRV5FlYz5n4XVtx30cF6ajOqq12ykeCUUX/lZkH4Uq5zT0tNEYpUhUw7mA==",
"dev": true,
"optional": true
},
"turbo-freebsd-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-freebsd-64/-/turbo-freebsd-64-1.1.10.tgz",
"integrity": "sha512-wra27mvakr5ZFceQnCCSR8gHQtKV8Q0EhtzO/wEdyhEssw0wVaNtMHUOOdvFN0HLmjQmmLZgmfZbURc83UDuZQ==",
"dev": true,
"optional": true
},
"turbo-freebsd-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-freebsd-arm64/-/turbo-freebsd-arm64-1.1.10.tgz",
"integrity": "sha512-J2I76pTwtrEVjHt1+zWY/s/Y0YIGdWHBIWOjhCXi1E8dav98oGw+WUaiFwzAkcksAblOhNpDL3qhnrnm7kHqrg==",
"dev": true,
"optional": true
},
"turbo-linux-32": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-32/-/turbo-linux-32-1.1.10.tgz",
"integrity": "sha512-d1ILhEv2B/lOtpH4niFUKGb8YMU6G7gNCQCY6wG+SXARWJtDti+KiNWESechD5DycCIMgtE40XNy/c1US+LI5g==",
"dev": true,
"optional": true
},
"turbo-linux-64": {
"version": "1.1.6",
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.1.10.tgz",
"integrity": "sha512-8VEOiNJFNfUMZOyrN32wOcdT1Ik1nlIuTwkO4UeonAJhuWjTvdDLPCQkz0SECTu60q90l6nXCnNYtoZA6LrZzA==",
"dev": true,
"optional": true
},
"turbo-linux-arm": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-arm/-/turbo-linux-arm-1.1.10.tgz",
"integrity": "sha512-qJ50K/s5MjpHjam+UdnK3GniEIv5XOBCZOGslgMMyz8V/q43vhB9BU9HQODclM89uQgsKxhs8Fue6ytOY4vIpg==",
"dev": true,
"optional": true
},
"turbo-linux-arm64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.1.10.tgz",
"integrity": "sha512-ng3dEEL4SbBudF/UZzsOrfyJh8DLtTHawTepeS30FdtvYuVBXdCPc5BAhbawGoau/2AV4vrN3qzh9e3LCqD6Qg==",
"dev": true,
"optional": true
},
"turbo-linux-mips64le": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-mips64le/-/turbo-linux-mips64le-1.1.10.tgz",
"integrity": "sha512-Jd4yH7ZEXCo0xmdJWZ6YsyqcNLyL5vRU3j5ZT+1W97YJCT+g+1on3/nd3rBVPzVz52lb8JIqgGtrBrnOO0AWJg==",
"dev": true,
"optional": true
},
"turbo-linux-ppc64le": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-linux-ppc64le/-/turbo-linux-ppc64le-1.1.10.tgz",
"integrity": "sha512-YF8+Oi53glqY29O1A7KJsHZxBzeVBobYFnPEXMt8vm+ouuo8kkbxXxShOP4h+33YGEkesTw/CTXtfDC1Xj1hDw==",
"dev": true,
"optional": true
},
"turbo-windows-32": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-windows-32/-/turbo-windows-32-1.1.10.tgz",
"integrity": "sha512-IO92tVTCtWVPPgcCjf8J7AmBEcwnjv1zPq7t9GFdqZ/6QA06atgPJNzQ/QvyzbzJgUsJUN2ByzwT04o4QUbrBQ==",
"dev": true,
"optional": true
},
"turbo-windows-64": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.1.10.tgz",
"integrity": "sha512-g/RIXaVDaOgliHEJuOsuB6Tefwue9fXBH1/iIH9dmT3Z7lL0banGh+C10RW6Jd6PBPMoPBWir9PLYuzxoPcCNQ==",
"dev": true,
"optional": true
},

View File

@ -29,7 +29,7 @@
"lint-staged": "^12.3.5",
"prettier": "^2.5.1",
"prettier-plugin-import-sort": "^0.0.7",
"turbo": "^1.1.6"
"turbo": "^1.1.10"
},
"prettier": {
"printWidth": 100

View File

@ -147,6 +147,12 @@ declare global {
class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
static info = info;
private ball_size: number = 30;
private ball: HTMLElement = null;
private container: HTMLElement = null;
private reps_remaining = 0;
private ball_animation_frame_id = null;
constructor(private jsPsych: JsPsych) {}
trial(display_element: HTMLElement, trial: TrialType<Info>) {
@ -161,6 +167,8 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
return;
}
this.reps_remaining = trial.blindspot_reps;
/** some additional parameter configuration */
let trial_data = <any>{
item_width_mm: trial.item_width_mm,
@ -198,7 +206,7 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
let blindspot_content = `
<div id="blind-spot">
${trial.blindspot_prompt}
<div id="svgDiv" style="width:1000px;height:200px;"></div>
<div id="svgDiv" style="height:100px; position:relative;"></div>
<button class="btn btn-primary" id="proceed" style="display:none;"> +
${trial.blindspot_done_prompt} +
</button>
@ -220,6 +228,7 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
display_element.innerHTML = `<div id="content" style="width: 900px; margin: 0 auto;"></div>`;
const start_time = performance.now();
startResizePhase();
function startResizePhase() {
@ -271,7 +280,7 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
function finishResizePhase() {
// add item width info to data
const item_width_px = getScaledItemWidth();
const item_width_px = document.querySelector("#item").getBoundingClientRect().width;
trial_data["item_width_px"] = Math.round(item_width_px);
const px2mm = convertPixelsToMM(item_width_px);
trial_data["px2mm"] = accurateRound(px2mm, 2);
@ -290,9 +299,21 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
slider_clck: false,
};
// add the content to the page
document.querySelector("#content").innerHTML = blindspot_content;
display_element.querySelector("#content").innerHTML = blindspot_content;
this.container = display_element.querySelector("#svgDiv");
// draw the ball and fixation square
drawBall();
resetAndWaitForBallStart();
};
const resetAndWaitForBallStart = () => {
const rectX = this.container.getBoundingClientRect().width - this.ball_size;
const ballX = rectX * 0.85; // define where the ball is
this.ball.style.left = `${ballX}px`;
// wait for a spacebar to begin the animations
this.jsPsych.pluginAPI.getKeyboardResponse({
callback_function: startBall,
@ -304,20 +325,33 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
};
const startBall = () => {
const ball_position_listener = this.jsPsych.pluginAPI.getKeyboardResponse({
this.jsPsych.pluginAPI.getKeyboardResponse({
callback_function: recordPosition,
valid_responses: [" "],
rt_method: "performance",
allow_held_key: false,
persist: true,
persist: false,
});
animateBall();
this.ball_animation_frame_id = requestAnimationFrame(animateBall);
};
const finishBlindSpotPhase = () => {
window.ball.stop();
const angle = 13.5;
this.jsPsych.pluginAPI.cancelAllKeyboardResponses();
// calculate average ball position
const sum = blindspot_config_data["ball_pos"].reduce((a, b) => a + b, 0);
const ballPosLen = blindspot_config_data["ball_pos"].length;
blindspot_config_data["avg_ball_pos"] = accurateRound(sum / ballPosLen, 2);
// calculate distance between avg ball position and square
const ball_sqr_distance =
(blindspot_config_data["square_pos"] - blindspot_config_data["avg_ball_pos"]) /
trial_data["px2mm"];
// calculate viewing distance in mm
const viewDistance = ball_sqr_distance / Math.tan(deg_to_radians(angle));
trial_data["view_dist_mm"] = accurateRound(viewDistance, 2);
if (trial.viewing_distance_report == "none") {
endTrial();
@ -400,68 +434,53 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
this.jsPsych.finishTrial(trial_data);
};
function getScaledItemWidth() {
return document.querySelector("#item").getBoundingClientRect().width;
}
const drawBall = () => {
this.container.innerHTML = `
<div id="virtual-chinrest-circle" style="position: absolute; background-color: #f00; width: ${this.ball_size}px; height: ${this.ball_size}px; border-radius:${this.ball_size}px;"></div>
<div id="virtual-chinrest-square" style="position: absolute; background-color: #000; width: ${this.ball_size}px; height: ${this.ball_size}px;"></div>
`;
function drawBall(pos = 180) {
// pos: define where the fixation square should be.
// @ts-expect-error
var mySVG = SVG("svgDiv");
const rectX = trial_data["px2mm"] * pos;
const ballX = rectX * 0.6; // define where the ball is
var ball = mySVG.circle(30).move(ballX, 50).fill("#f00");
window.ball = ball;
var square = mySVG.rect(30, 30).move(Math.min(rectX - 50, 950), 50); //square position
blindspot_config_data["square_pos"] = accurateRound(square.cx(), 2);
blindspot_config_data["rectX"] = rectX;
blindspot_config_data["ballX"] = ballX;
}
const ball: HTMLElement = this.container.querySelector("#virtual-chinrest-circle");
const square: HTMLElement = this.container.querySelector("#virtual-chinrest-square");
function animateBall() {
window.ball
.animate(7000)
.during((pos) => {
let moveX = -pos * blindspot_config_data["ballX"];
window.moveX = moveX;
let moveY = 0;
window.ball.attr({ transform: "translate(" + moveX + "," + moveY + ")" }); //jqueryToVanilla: el.getAttribute('');
})
.loop(true, false)
.after(() => {
animateBall();
});
}
const rectX = this.container.getBoundingClientRect().width - this.ball_size;
const ballX = rectX * 0.85; // define where the ball is
function recordPosition() {
// angle: define horizontal blind spot entry point position in degrees.
const angle = 13.5;
ball.style.left = `${ballX}px`;
square.style.left = `${rectX}px`;
blindspot_config_data["ball_pos"].push(accurateRound(window.ball.cx() + window.moveX, 2));
var sum = blindspot_config_data["ball_pos"].reduce((a, b) => a + b, 0);
var ballPosLen = blindspot_config_data["ball_pos"].length;
blindspot_config_data["avg_ball_pos"] = accurateRound(sum / ballPosLen, 2);
var ball_sqr_distance =
(blindspot_config_data["square_pos"] - blindspot_config_data["avg_ball_pos"]) /
trial_data["px2mm"];
var viewDistance = ball_sqr_distance / Math.tan(deg_to_radians(angle));
trial_data["view_dist_mm"] = accurateRound(viewDistance, 2);
this.ball = ball;
blindspot_config_data["square_pos"] = accurateRound(getElementCenter(square).x, 2);
};
const animateBall = () => {
const dx = -2;
const x = parseInt(this.ball.style.left);
this.ball.style.left = `${x + dx}px`;
this.ball_animation_frame_id = requestAnimationFrame(animateBall);
};
const recordPosition = () => {
cancelAnimationFrame(this.ball_animation_frame_id);
blindspot_config_data["ball_pos"].push(accurateRound(getElementCenter(this.ball).x, 2));
//counter and stop
var counter = Number(document.querySelector("#click").textContent);
counter = counter - 1;
this.reps_remaining--;
(document.querySelector("#click") as HTMLDivElement).textContent = Math.max(
counter,
this.reps_remaining,
0
).toString();
if (counter <= 0) {
if (this.reps_remaining <= 0) {
finishBlindSpotPhase();
return;
} else {
window.ball.stop();
animateBall();
resetAndWaitForBallStart();
}
}
};
function convertPixelsToMM(item_width_px) {
const px2mm = item_width_px / trial_data["item_width_mm"];
@ -472,6 +491,14 @@ class VirtualChinrestPlugin implements JsPsychPlugin<Info> {
return Number(Math.round(Number(value + "e" + decimals)) + "e-" + decimals);
}
function getElementCenter(el: HTMLElement) {
const box = el.getBoundingClientRect();
return {
x: box.left + box.width / 2,
y: box.top + box.height / 2,
};
}
//helper function for radians
// Converts from degrees to radians.
const deg_to_radians = (degrees: number) => {