Skip to content

Commit

Permalink
Merge pull request #529 from brown-ccv/ref-trial-cons-var
Browse files Browse the repository at this point in the history
ref: change all func taking in jspsych to const syntax / trials to co…
  • Loading branch information
YUUU23 authored Aug 14, 2024
2 parents 25b93e9 + f310479 commit 99556aa
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 166 deletions.
7 changes: 3 additions & 4 deletions src/experiment/honeycomb.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@ export const honeycombOptions = {
* Take a look at how the code here compares to the jsPsych documentation!
* See the jsPsych documentation for more: https://www.jspsych.org/7.3/tutorials/rt-task/
*
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych timeline object
*/
export function buildHoneycombTimeline() {
export const buildHoneycombTimeline = () => {
// Build the trials that make up the start procedure
const startProcedure = buildStartProcedure();

// Build the trials that make up the task procedure
const honeycombProcedure = buildHoneycombProcedure();

// Builds the trial needed to debrief the participant on their performance
const debriefTrial = buildDebriefTrial();
const debriefTrial = buildDebriefTrial;

// Builds the trials that make up the end procedure
const endProcedure = buildEndProcedure();
Expand All @@ -56,4 +55,4 @@ export function buildHoneycombTimeline() {
endProcedure,
];
return timeline;
}
};
6 changes: 3 additions & 3 deletions src/experiment/procedures/endProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { exitFullscreenTrial } from "../trials/fullscreen";
*
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildEndProcedure() {
export const buildEndProcedure = () => {
const procedure = [];

// Conditionally add the camera breakdown trials
if (ENV.USE_CAMERA) {
procedure.push(buildCameraEndTrial());
procedure.push(buildCameraEndTrial);
}

// Add the other trials needed to end the experiment
procedure.push(exitFullscreenTrial, conclusionTrial);

// Return the block as a nested timeline
return { timeline: procedure };
}
};
6 changes: 3 additions & 3 deletions src/experiment/procedures/honeycombProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { getJsPsych } from "../../lib/utils";
*
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildHoneycombProcedure() {
export const buildHoneycombProcedure = () => {
const honeycombSettings = SETTINGS.honeycomb;
const fixationTrial = buildFixationTrial();
const fixationTrial = buildFixationTrial;
/**
* Displays a colored circle and waits for participant to response with a keyboard press
*
Expand Down Expand Up @@ -68,4 +68,4 @@ export function buildHoneycombProcedure() {
timeline: [fixationTrial, taskTrial],
};
return honeycombBlock;
}
};
6 changes: 3 additions & 3 deletions src/experiment/procedures/startProcedure.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { introductionTrial } from "../trials/introduction";
*
* @returns {Object} A jsPsych (nested) timeline object
*/
export function buildStartProcedure() {
export const buildStartProcedure = () => {
const procedure = [nameTrial, enterFullscreenTrial, introductionTrial];

// Conditionally add the photodiode setup trials
Expand All @@ -28,9 +28,9 @@ export function buildStartProcedure() {

// Conditionally add the camera setup trials
if (ENV.USE_CAMERA) {
procedure.push(buildCameraStartTrial());
procedure.push(buildCameraStartTrial);
}

// Return the block as a nested timeline
return { timeline: procedure };
}
};
175 changes: 85 additions & 90 deletions src/experiment/trials/camera.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,111 +10,106 @@ const WEBCAM_ID = "webcam";

/**
* A trial that begins recording the participant using their computer's default camera
* @param {Object} jsPsych The jsPsych instance being used to run the task
* @returns {Object} A jsPsych trial object
*
* @type {Object} A jsPsych trial object
*/
// TODO @brown-ccv #301: Use jsPsych extension, deprecate this function
// TODO @brown-ccv #301: Use jsPsych extension, deprecate this variable
// TODO @brown-ccv #343: We should be able to make this work on both electron and browser?
// TODO @brown-ccv #301: Rolling save to the deployment (webm is a subset of mkv)
export function buildCameraStartTrial() {
return {
timeline: [
{
// Prompts user permission for camera device
type: initializeCamera,
include_audio: true,
mime_type: "video/webm",
export const buildCameraStartTrial = {
timeline: [
{
// Prompts user permission for camera device
type: initializeCamera,
include_audio: true,
mime_type: "video/webm",
},
{
// Helps participant center themselves inside the camera
type: htmlButtonResponse,
stimulus: function () {
const videoMarkup = tag("video", "", {
id: WEBCAM_ID,
width: 640,
height: 480,
autoplay: true,
});
const cameraStartMarkup = p(LANGUAGE.trials.camera.start);
const trialMarkup = div(cameraStartMarkup + videoMarkup, {
class: "align-items-center-col",
});
return div(trialMarkup);
},
{
// Helps participant center themselves inside the camera
type: htmlButtonResponse,
stimulus: function () {
const videoMarkup = tag("video", "", {
id: WEBCAM_ID,
width: 640,
height: 480,
autoplay: true,
});
const cameraStartMarkup = p(LANGUAGE.trials.camera.start);
const trialMarkup = div(cameraStartMarkup + videoMarkup, {
class: "align-items-center-col",
});
return div(trialMarkup);
},
choices: [LANGUAGE.prompts.continue.button],
response_ends_trial: true,
on_start: function () {
// Initialize and store the camera feed
if (!ENV.USE_ELECTRON) {
throw new Error("video recording is only available when running inside Electron");
}
choices: [LANGUAGE.prompts.continue.button],
response_ends_trial: true,
on_start: function () {
// Initialize and store the camera feed
if (!ENV.USE_ELECTRON) {
throw new Error("video recording is only available when running inside Electron");
}

const cameraRecorder = getJsPsych().pluginAPI.getCameraRecorder();
if (!cameraRecorder) {
console.error("Camera is not initialized, no data will be recorded.");
return;
}
const cameraChunks = [];
const cameraRecorder = getJsPsych().pluginAPI.getCameraRecorder();
if (!cameraRecorder) {
console.error("Camera is not initialized, no data will be recorded.");
return;
}
const cameraChunks = [];

// Push data whenever available
cameraRecorder.addEventListener("dataavailable", (event) => {
if (event.data.size > 0) cameraChunks.push(event.data);
});
// Push data whenever available
cameraRecorder.addEventListener("dataavailable", (event) => {
if (event.data.size > 0) cameraChunks.push(event.data);
});

// Saves the raw data feed from the participants camera (executed on cameraRecorder.stop()).
cameraRecorder.addEventListener("stop", () => {
const blob = new Blob(cameraChunks, { type: cameraRecorder.mimeType });
// Saves the raw data feed from the participants camera (executed on cameraRecorder.stop()).
cameraRecorder.addEventListener("stop", () => {
const blob = new Blob(cameraChunks, { type: cameraRecorder.mimeType });

// Pass video data to Electron as a base64 encoded string
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
window.electronAPI.saveVideo(reader.result);
};
});
},
on_load: function () {
// Assign camera feed to the <video> element
const camera = document.getElementById(WEBCAM_ID);
// Pass video data to Electron as a base64 encoded string
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
window.electronAPI.saveVideo(reader.result);
};
});
},
on_load: function () {
// Assign camera feed to the <video> element
const camera = document.getElementById(WEBCAM_ID);

camera.srcObject = getJsPsych().pluginAPI.getCameraRecorder().stream;
},
on_finish: function () {
// Begin video recording
getJsPsych().pluginAPI.getCameraRecorder().start();
},
camera.srcObject = getJsPsych().pluginAPI.getCameraRecorder().stream;
},
on_finish: function () {
// Begin video recording
getJsPsych().pluginAPI.getCameraRecorder().start();
},
],
};
}
},
],
};

const recordingEndMarkup = h1(LANGUAGE.trials.camera.end);

/**
* A trial that finishes recording the participant using their computer's default camera
*
* @param {Number} duration How long to show the trial for
* @returns {Object} A jsPsych trial object
* @type {Object} A jsPsych trial object
*/
export function buildCameraEndTrial() {
const recordingEndMarkup = h1(LANGUAGE.trials.camera.end);
export const buildCameraEndTrial = {
type: htmlKeyboardResponse,
stimulus: div(recordingEndMarkup),
trial_duration: 5000,
on_start: function () {
// Complete the camera recording

return {
type: htmlKeyboardResponse,
stimulus: div(recordingEndMarkup),
trial_duration: 5000,
on_start: function () {
// Complete the camera recording
if (!ENV.USE_ELECTRON) {
throw new Error("video recording is only available when running inside Electron");
}

if (!ENV.USE_ELECTRON) {
throw new Error("video recording is only available when running inside Electron");
}
const cameraRecorder = getJsPsych().pluginAPI.getCameraRecorder();
if (!cameraRecorder) {
console.error("Camera is not initialized, no data will be recorded.");
return;
}

const cameraRecorder = getJsPsych().pluginAPI.getCameraRecorder();
if (!cameraRecorder) {
console.error("Camera is not initialized, no data will be recorded.");
return;
}

cameraRecorder.stop();
},
};
}
cameraRecorder.stop();
},
};
69 changes: 32 additions & 37 deletions src/experiment/trials/fixation.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,38 @@ import { pdSpotEncode, photodiodeGhostBox } from "../../lib/markup/photodiode";
import { div } from "../../lib/markup/tags";
import { getJsPsych } from "../../lib/utils";

const fixationSettings = SETTINGS.fixation;
const fixationCode = eventCodes.fixation;

/**
* Builds a trial with a fixation dot and optional photodiode box.
* @param {Object} jsPsych The global jsPsych object used to build the trial
* @returns {Object} A jsPsych trial object
*
* @type {Object} A jsPsych trial object
*/
export function buildFixationTrial() {
const fixationSettings = SETTINGS.fixation;
const fixationCode = eventCodes.fixation;

return {
type: htmlKeyboardResponse,
choices: "NO_KEYS",
// Display the fixation dot
stimulus: div("", { id: "fixation-dot" }),
prompt: function () {
// Conditionally display the photodiodeGhostBox
if (ENV.USE_PHOTODIODE) return photodiodeGhostBox;
else return null;
},
trial_duration: function () {
if (fixationSettings.randomize_duration) {
// Select a random duration from the durations array to show the fixation dot for
return getJsPsych().randomization.sampleWithoutReplacement(
fixationSettings.durations,
1
)[0];
} else {
// Show the fixation dot for default duration seconds
return fixationSettings.default_duration;
}
},
data: {
code: fixationCode, // Add event code to the recorded data
},
on_load: function () {
// Conditionally flash the photodiode when the trial first loads
if (ENV.USE_PHOTODIODE) pdSpotEncode(fixationCode);
},
};
}
export const buildFixationTrial = {
type: htmlKeyboardResponse,
choices: "NO_KEYS",
// Display the fixation dot
stimulus: div("", { id: "fixation-dot" }),
prompt: function () {
// Conditionally display the photodiodeGhostBox
if (ENV.USE_PHOTODIODE) return photodiodeGhostBox;
else return null;
},
trial_duration: function () {
if (fixationSettings.randomize_duration) {
// Select a random duration from the durations array to show the fixation dot for
return getJsPsych().randomization.sampleWithoutReplacement(fixationSettings.durations, 1)[0];
} else {
// Show the fixation dot for default duration seconds
return fixationSettings.default_duration;
}
},
data: {
code: fixationCode, // Add event code to the recorded data
},
on_load: function () {
// Conditionally flash the photodiode when the trial first loads
if (ENV.USE_PHOTODIODE) pdSpotEncode(fixationCode);
},
};
Loading

0 comments on commit 99556aa

Please sign in to comment.