1
0
mirror of https://github.com/psychopy/psychojs.git synced 2025-05-10 10:40:54 +00:00

polished up QuestHandler, various comestic improvements, small fixes to Camera

This commit is contained in:
Alain Pitiot 2021-07-23 08:00:20 +02:00
parent 0a7d15077c
commit b6125d5b16
6 changed files with 73 additions and 33 deletions

View File

@ -145,9 +145,9 @@ export class PsychoJS
psychoJS: this
});
// to be loading `configURL` files in `_configure` calls from
const hostsEvidently = new Set([...hosts, 'https://pavlovia.org/run/', 'https://run.pavlovia.org/']);
this._hosts = Array.from(hostsEvidently);
// add the pavlovia server to the list of hosts:
const hostsWithPavlovia = new Set([...hosts, 'https://pavlovia.org/run/', 'https://run.pavlovia.org/']);
this._hosts = Array.from(hostsWithPavlovia);
// GUI:
this._gui = new GUI(this);
@ -181,7 +181,7 @@ export class PsychoJS
this.logger.info('[PsychoJS] Initialised.');
this.logger.info('[PsychoJS] @version 2021.2.x');
// Hide #root::after
// hide the initialisation message:
jQuery('#root').addClass('is-ready');
}
@ -591,17 +591,17 @@ export class PsychoJS
{
this.status = PsychoJS.Status.CONFIGURING;
// if the experiment is running from the pavlovia.org server, we read the configuration file:
// if the experiment is running from an approved hosts, e.e pavlovia.org,
// we read the configuration file:
const experimentUrl = window.location.href;
// go through each url in allow list
const isHost = this._hosts.some(url => experimentUrl.indexOf(url) === 0);
if (isHost)
{
const serverResponse = await this._serverManager.getConfiguration(configURL);
this._config = serverResponse.config;
// legacy experiments had a psychoJsManager block instead of a pavlovia block,
// and the URL pointed to https://pavlovia.org/server
// update the configuration for legacy experiments, which had a psychoJsManager
// block instead of a pavlovia block, with URL pointing to https://pavlovia.org/server
if ('psychoJsManager' in this._config)
{
delete this._config.psychoJsManager;
@ -744,10 +744,13 @@ export class PsychoJS
window.onunhandledrejection = function (error)
{
console.error(error?.reason);
if (error?.reason?.stack === undefined) {
if (error?.reason?.stack === undefined)
{
// No stack? Error thrown by PsychoJS; stringify whole error
document.body.setAttribute('data-error', JSON.stringify(error?.reason));
} else {
}
else
{
// Yes stack? Error thrown by JS; stringify stack
document.body.setAttribute('data-error', JSON.stringify(error?.reason?.stack));
}

View File

@ -445,8 +445,7 @@ export class ServerManager extends PsychObject
// if the experiment is hosted on the pavlovia.org server and
// resources is [ServerManager.ALL_RESOURCES], then we register all the resources
// in the "resources" sub-directory
if (this._psychoJS.config.environment === ExperimentHandler.Environment.SERVER
&& allResources)
if (this._psychoJS.config.environment === ExperimentHandler.Environment.SERVER && allResources)
{
// list the resources from the resources directory of the experiment on the server:
const serverResponse = await this._listResources();
@ -475,8 +474,7 @@ export class ServerManager extends PsychObject
{
// we cannot ask for all resources to be registered locally, since we cannot list
// them:
if (this._psychoJS.config.environment === ExperimentHandler.Environment.LOCAL
&& allResources)
if (this._psychoJS.config.environment === ExperimentHandler.Environment.LOCAL && allResources)
{
throw "resources must be manually specified when the experiment is running locally: ALL_RESOURCES cannot be used";
}
@ -818,11 +816,11 @@ export class ServerManager extends PsychObject
// query the pavlovia server:
const response = await fetch(url, {
method: 'POST',
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
body: formData
});
const jsonResponse = await response.json();

View File

@ -33,7 +33,7 @@ export class ExperimentHandler extends PsychObject
/**
* Getter for experimentEnded.
*
* @name module:core.Window#experimentEnded
* @name module:data.ExperimentHandler#experimentEnded
* @function
* @public
*/
@ -45,7 +45,7 @@ export class ExperimentHandler extends PsychObject
/**
* Setter for experimentEnded.
*
* @name module:core.Window#experimentEnded
* @name module:data.ExperimentHandler#experimentEnded
* @function
* @public
*/

View File

@ -14,14 +14,26 @@ import {TrialHandler} from "./TrialHandler";
/**
* <p>A Trial Handler that implements the Quest algorithm for quick measurement of
psychophysical thresholds.</p>
psychophysical thresholds.QuestHandler relies on the [jsQuest]{@link https://github.com/kurokida/jsQUEST} library, a port of Prof Dennis Pelli's QUEST algorithm by [Daiichiro Kuroki]{@link https://github.com/kurokida}.</p>
*
* @class
* @extends PsychObject
* @class module.data.QuestHandler
* @extends TrialHandler
* @param {Object} options
* @param {module:core.PsychoJS} options.psychoJS - the PsychoJS instance
* @param {string} options.varName - the name of the variable / intensity / contrast / threshold manipulated by QUEST
* @param {number} options.startVal - initial guess for the threshold
* @param {number} options.startValSd - standard deviation of the initial guess
* @param {number} options.minVal - minimum value for the threshold
* @param {number} options.maxVal - maximum value for the threshold
* @param {number} [options.pThreshold=0.82] - threshold criterion expressed as probability of getting a correct response
* @param {number} options.nTrials - maximum number of trials
* @param {number} options.stopInterval - minimum [5%, 95%] confidence interval required for the loop to stop
* @param {module:data.QuestHandler.Method} options.method - the QUEST method
* @param {number} [options.beta=3.5] - steepness of the QUEST psychometric function
* @param {number} [options.delta=0.01] - fraction of trials with blind responses
* @param {number} [options.gamma=0.5] - fraction of trails that would generate a correct response when the threshold is infinitely small
* @param {number} [options.grain=0.01] - quantization of the internal table
* @param {string} options.name - name of the handler
* @param {boolean} [options.autoLog= false] - whether or not to log
*/
export class QuestHandler extends TrialHandler
@ -80,9 +92,11 @@ export class QuestHandler extends TrialHandler
/**
* Add a response and update the PDF.
*
* @name module:data.QuestHandler#addResponse
* @function
* @public
* @param{number} response - the response to the trial, must be either 0 (incorrect,
* non-detected) or 1 (correct, detected).
* @param{number} response - the response to the trial, must be either 0 (incorrect or
* non-detected) or 1 (correct or detected).
*/
addResponse(response)
{
@ -110,7 +124,10 @@ export class QuestHandler extends TrialHandler
/**
* Simulate a response.
*
* @param{number} trueValue
* @name module:data.QuestHandler#simulate
* @function
* @public
* @param{number} trueValue - the true, known value of the threshold / contrast / intensity
*/
simulate(trueValue)
{
@ -128,6 +145,9 @@ export class QuestHandler extends TrialHandler
/**
* Get the mean of the Quest posterior PDF.
*
* @name module:data.QuestHandler#mean
* @function
* @public
* @returns {number} the mean
*/
mean()
@ -139,6 +159,9 @@ export class QuestHandler extends TrialHandler
/**
* Get the standard deviation of the Quest posterior PDF.
*
* @name module:data.QuestHandler#sd
* @function
* @public
* @returns {number} the standard deviation
*/
sd()
@ -150,6 +173,9 @@ export class QuestHandler extends TrialHandler
/**
* Get the mode of the Quest posterior PDF.
*
* @name module:data.QuestHandler#mode
* @function
* @public
* @returns {number} the mode
*/
mode()
@ -162,6 +188,9 @@ export class QuestHandler extends TrialHandler
/**
* Get the standard deviation of the Quest posterior PDF.
*
* @name module:data.QuestHandler#quantile
* @function
* @public
* @param{number} quantileOrder the quantile order
* @returns {number} the quantile
*/
@ -174,6 +203,8 @@ export class QuestHandler extends TrialHandler
/**
* Get an estimate of the 5%-95% confidence interval (CI).
*
* @name module:data.QuestHandler#confInterval
* @function
* @public
* @param{boolean} [getDifference=false] if true, return the width of the CI instead of the CI
*/
@ -198,6 +229,8 @@ export class QuestHandler extends TrialHandler
/**
* Setup the JS Quest object.
*
* @name module:data.QuestHandler#_setupJsQuest
* @function
* @protected
*/
_setupJsQuest()
@ -219,6 +252,8 @@ export class QuestHandler extends TrialHandler
* Estimate the next value of the QUEST variable, based on the current value
* and on the selected QUEST method.
*
* @name module:data.QuestHandler#_estimateQuestValue
* @function
* @protected
*/
_estimateQuestValue()
@ -248,7 +283,6 @@ export class QuestHandler extends TrialHandler
this._psychoJS.logger.debug(`estimated value for QUEST variable ${this._varName}: ${this._questValue}`);
// check whether we should finish the trial:
if (this.thisN > 0 &&
(this.nRemaining === 0 || this.confInterval(true) < this._stopInterval))
@ -269,7 +303,6 @@ export class QuestHandler extends TrialHandler
return;
}
// update the next undefined trial in the trial list, and the associated snapshot:
for (let t = 0; t < this._trialList.length; ++t)
{

View File

@ -1454,5 +1454,10 @@ export function extensionFromMimeType(mimeType)
return '.wav';
}
if (mimeType.indexOf('video/webm') === 0)
{
return '.webm';
}
return '.dat';
}

View File

@ -456,14 +456,15 @@ export class Camera extends PsychObject
// create a new stream with ideal dimensions:
this._stream = await navigator.mediaDevices.getUserMedia({
video: {
video: true
/*video: {
width: {
ideal: 1920
ideal: 640 //1920
},
height: {
ideal: 1080
ideal: 480 //1080
}
}
}*/
});
// check the actual width and height: