mirror of
https://github.com/psychopy/psychojs.git
synced 2025-05-11 16:18:10 +00:00
visual: enforce consistent formatting
This commit is contained in:
parent
61fb7744a1
commit
c9cb3c8412
@ -7,10 +7,8 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import {TextBox} from './TextBox.js';
|
||||
import {Mouse} from '../core/Mouse.js';
|
||||
|
||||
import { Mouse } from "../core/Mouse.js";
|
||||
import { TextBox } from "./TextBox.js";
|
||||
|
||||
/**
|
||||
* <p>ButtonStim visual stimulus.</p>
|
||||
@ -39,28 +37,71 @@ import {Mouse} from '../core/Mouse.js';
|
||||
*/
|
||||
export class ButtonStim extends TextBox
|
||||
{
|
||||
constructor({win, name, text, font, pos, size, padding, anchor = 'center', units, color, fillColor = 'darkgrey', borderColor, borderWidth = 0, opacity, letterHeight, bold = true, italic, autoDraw, autoLog} = {})
|
||||
constructor(
|
||||
{
|
||||
win,
|
||||
name,
|
||||
text,
|
||||
font,
|
||||
pos,
|
||||
size,
|
||||
padding,
|
||||
anchor = "center",
|
||||
units,
|
||||
color,
|
||||
fillColor = "darkgrey",
|
||||
borderColor,
|
||||
borderWidth = 0,
|
||||
opacity,
|
||||
letterHeight,
|
||||
bold = true,
|
||||
italic,
|
||||
autoDraw,
|
||||
autoLog,
|
||||
} = {},
|
||||
)
|
||||
{
|
||||
super({win, name, text, font, pos, size, padding, anchor, units, color, fillColor, borderColor, borderWidth, opacity, letterHeight, bold, italic, alignment: 'center', autoDraw, autoLog});
|
||||
super({
|
||||
win,
|
||||
name,
|
||||
text,
|
||||
font,
|
||||
pos,
|
||||
size,
|
||||
padding,
|
||||
anchor,
|
||||
units,
|
||||
color,
|
||||
fillColor,
|
||||
borderColor,
|
||||
borderWidth,
|
||||
opacity,
|
||||
letterHeight,
|
||||
bold,
|
||||
italic,
|
||||
alignment: "center",
|
||||
autoDraw,
|
||||
autoLog,
|
||||
});
|
||||
|
||||
this.psychoJS.logger.debug('create a new Button with name: ', name);
|
||||
this.psychoJS.logger.debug("create a new Button with name: ", name);
|
||||
|
||||
this.listener = new Mouse({name, win, autoLog});
|
||||
this.listener = new Mouse({ name, win, autoLog });
|
||||
|
||||
this._addAttribute(
|
||||
'wasClicked',
|
||||
false
|
||||
"wasClicked",
|
||||
false,
|
||||
);
|
||||
|
||||
// Arrays to store times of clicks on and off
|
||||
this._addAttribute(
|
||||
'timesOn',
|
||||
[]
|
||||
"timesOn",
|
||||
[],
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'timesOff',
|
||||
[]
|
||||
"timesOff",
|
||||
[],
|
||||
);
|
||||
|
||||
if (this._autoLog)
|
||||
@ -69,8 +110,6 @@ export class ButtonStim extends TextBox
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* How many times has this button been clicked on?
|
||||
*
|
||||
@ -82,8 +121,6 @@ export class ButtonStim extends TextBox
|
||||
return this.timesOn.length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Is this button currently being clicked on?
|
||||
*
|
||||
@ -94,5 +131,4 @@ export class ButtonStim extends TextBox
|
||||
{
|
||||
return this.listener.isPressedIn(this, [1, 0, 0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,19 +7,16 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import {TrialHandler} from '../data/TrialHandler.js';
|
||||
import {TextStim} from './TextStim.js';
|
||||
import {TextBox} from './TextBox.js';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Slider} from './Slider.js';
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { TrialHandler } from "../data/TrialHandler.js";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { Slider } from "./Slider.js";
|
||||
import { TextBox } from "./TextBox.js";
|
||||
import { TextStim } from "./TextStim.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* Form stimulus.
|
||||
@ -58,99 +55,127 @@ import { to_pixiPoint } from "../util/Pixi.js";
|
||||
*/
|
||||
export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({name, win, pos, size, units, borderColor, fillColor, itemColor, markerColor, responseColor, color, contrast, opacity, depth, items, randomize, itemPadding, font, fontFamily, bold, italic, fontSize, clipMask, autoDraw, autoLog} = {})
|
||||
constructor(
|
||||
{
|
||||
name,
|
||||
win,
|
||||
pos,
|
||||
size,
|
||||
units,
|
||||
borderColor,
|
||||
fillColor,
|
||||
itemColor,
|
||||
markerColor,
|
||||
responseColor,
|
||||
color,
|
||||
contrast,
|
||||
opacity,
|
||||
depth,
|
||||
items,
|
||||
randomize,
|
||||
itemPadding,
|
||||
font,
|
||||
fontFamily,
|
||||
bold,
|
||||
italic,
|
||||
fontSize,
|
||||
clipMask,
|
||||
autoDraw,
|
||||
autoLog,
|
||||
} = {},
|
||||
)
|
||||
{
|
||||
super({name, win, units, opacity, depth, pos, size, clipMask, autoDraw, autoLog});
|
||||
super({ name, win, units, opacity, depth, pos, size, clipMask, autoDraw, autoLog });
|
||||
|
||||
this._addAttribute(
|
||||
'itemPadding',
|
||||
"itemPadding",
|
||||
itemPadding,
|
||||
util.to_unit([20, 0], 'pix', win, this._units)[0],
|
||||
this._onChange(true, false)
|
||||
util.to_unit([20, 0], "pix", win, this._units)[0],
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
// colors:
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
// Same as itemColor
|
||||
color,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'borderColor',
|
||||
"borderColor",
|
||||
borderColor,
|
||||
fillColor,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'fillColor',
|
||||
"fillColor",
|
||||
fillColor,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'itemColor',
|
||||
"itemColor",
|
||||
itemColor,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'markerColor',
|
||||
"markerColor",
|
||||
markerColor,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'responseColor',
|
||||
"responseColor",
|
||||
responseColor,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
// fonts:
|
||||
this._addAttribute(
|
||||
'font',
|
||||
"font",
|
||||
font,
|
||||
'Arial',
|
||||
this._onChange(true, true)
|
||||
"Arial",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
// Not in use at present
|
||||
this._addAttribute(
|
||||
'fontFamily',
|
||||
"fontFamily",
|
||||
fontFamily,
|
||||
'Helvetica',
|
||||
this._onChange(true, true)
|
||||
"Helvetica",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'fontSize',
|
||||
"fontSize",
|
||||
fontSize,
|
||||
(this._units === 'pix') ? 14 : 0.03,
|
||||
this._onChange(true, true)
|
||||
(this._units === "pix") ? 14 : 0.03,
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'bold',
|
||||
"bold",
|
||||
bold,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'italic',
|
||||
"italic",
|
||||
italic,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
// callback to deal with changes to items:
|
||||
@ -166,16 +191,17 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
};
|
||||
|
||||
this._addAttribute(
|
||||
'items',
|
||||
"items",
|
||||
items,
|
||||
[],
|
||||
onItemChange);
|
||||
onItemChange,
|
||||
);
|
||||
this._addAttribute(
|
||||
'randomize',
|
||||
"randomize",
|
||||
randomize,
|
||||
false,
|
||||
onItemChange);
|
||||
|
||||
onItemChange,
|
||||
);
|
||||
|
||||
this._scrollbarWidth = 0.02;
|
||||
this._responseTextHeightRatio = 0.8;
|
||||
@ -192,8 +218,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Force a refresh of the stimulus.
|
||||
*
|
||||
@ -218,8 +242,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Overridden draw that also calls the draw method of all form elements.
|
||||
*
|
||||
@ -260,8 +282,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._scrollbar.draw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Overridden hide that also calls the hide method of all form elements.
|
||||
*
|
||||
@ -276,7 +296,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
super.hide();
|
||||
|
||||
// hide the stimuli:
|
||||
if (typeof this._items !== 'undefined')
|
||||
if (typeof this._items !== "undefined")
|
||||
{
|
||||
for (let i = 0; i < this._items.length; ++i)
|
||||
{
|
||||
@ -298,8 +318,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reset the form.
|
||||
*
|
||||
@ -309,7 +327,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
reset()
|
||||
{
|
||||
this.psychoJS.logger.debug('reset Form: ', this._name);
|
||||
this.psychoJS.logger.debug("reset Form: ", this._name);
|
||||
|
||||
// reset the stimuli:
|
||||
for (let i = 0; i < this._items.length; ++i)
|
||||
@ -327,8 +345,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Collate the questions and responses into a single dataset.
|
||||
*
|
||||
@ -352,9 +368,9 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
item.response = responseStim.getRating();
|
||||
item.rt = responseStim.getRT();
|
||||
|
||||
if (typeof item.response === 'undefined')
|
||||
if (typeof item.response === "undefined")
|
||||
{
|
||||
++ nbIncompleteResponse;
|
||||
++nbIncompleteResponse;
|
||||
}
|
||||
}
|
||||
else if (item.type === Form.Types.FREE_TEXT)
|
||||
@ -364,7 +380,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
if (item.response.length === 0)
|
||||
{
|
||||
++ nbIncompleteResponse;
|
||||
++nbIncompleteResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -372,9 +388,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
this._items._complete = (nbIncompleteResponse === 0);
|
||||
|
||||
|
||||
// return a copy of this._items:
|
||||
return this._items.map(item => Object.assign({}, item));
|
||||
return this._items.map((item) => Object.assign({}, item));
|
||||
}
|
||||
/**
|
||||
* Check if the form is complete.
|
||||
@ -386,7 +401,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
formComplete()
|
||||
{
|
||||
//same as complete but might be used by some experiments before 2020.2
|
||||
// same as complete but might be used by some experiments before 2020.2
|
||||
this.getData();
|
||||
return this._items._complete;
|
||||
}
|
||||
@ -399,15 +414,21 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
* @param {module:data.ExperimentHandler} experiment - the experiment into which to insert the form data
|
||||
* @param {string} [format= 'rows'] - whether to insert the data as rows or as columns
|
||||
*/
|
||||
addDataToExp(experiment, format = 'rows')
|
||||
addDataToExp(experiment, format = "rows")
|
||||
{
|
||||
const addAsColumns = ['cols', 'columns'].includes(format.toLowerCase());
|
||||
const addAsColumns = ["cols", "columns"].includes(format.toLowerCase());
|
||||
const data = this.getData();
|
||||
|
||||
const _doNotSave = [
|
||||
'itemCtrl', 'responseCtrl',
|
||||
'itemColor', 'options', 'ticks', 'tickLabels',
|
||||
'responseWidth', 'responseColor', 'layout'
|
||||
"itemCtrl",
|
||||
"responseCtrl",
|
||||
"itemColor",
|
||||
"options",
|
||||
"ticks",
|
||||
"tickLabels",
|
||||
"responseWidth",
|
||||
"responseColor",
|
||||
"layout",
|
||||
];
|
||||
|
||||
for (const item of this.getData())
|
||||
@ -420,7 +441,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
const columnName = (addAsColumns) ? `${this._name}[${index}]${field}` : `${this._name}${field}`;
|
||||
experiment.addData(columnName, item[field]);
|
||||
}
|
||||
++ index;
|
||||
++index;
|
||||
}
|
||||
|
||||
if (!addAsColumns)
|
||||
@ -435,8 +456,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Import and process the form items from either a spreadsheet resource files (.csv, .xlsx, etc.) or from an array.
|
||||
*
|
||||
@ -447,8 +466,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
_processItems()
|
||||
{
|
||||
const response = {
|
||||
origin: 'Form._processItems',
|
||||
context: 'when processing the form items'
|
||||
origin: "Form._processItems",
|
||||
context: "when processing the form items",
|
||||
};
|
||||
|
||||
try
|
||||
@ -456,7 +475,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
if (this._autoLog)
|
||||
{
|
||||
// note: we use the same log message as PsychoPy even though we called this method differently
|
||||
this._psychoJS.experimentLogger.exp('Importing items...');
|
||||
this._psychoJS.experimentLogger.exp("Importing items...");
|
||||
}
|
||||
|
||||
// import the items:
|
||||
@ -474,12 +493,10 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
catch (error)
|
||||
{
|
||||
// throw { ...response, error };
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Import the form items from either a spreadsheet resource files (.csv, .xlsx, etc.) or from an array.
|
||||
*
|
||||
@ -490,8 +507,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
_importItems()
|
||||
{
|
||||
const response = {
|
||||
origin: 'Form._importItems',
|
||||
context: 'when importing the form items'
|
||||
origin: "Form._importItems",
|
||||
context: "when importing the form items",
|
||||
};
|
||||
|
||||
try
|
||||
@ -499,17 +516,15 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
const itemsType = typeof this._items;
|
||||
|
||||
// we treat undefined items as a list with a single default entry:
|
||||
if (itemsType === 'undefined')
|
||||
if (itemsType === "undefined")
|
||||
{
|
||||
this._items = [Form._defaultItems];
|
||||
}
|
||||
|
||||
// if items is a string, we treat it as the name of a resource file and import it:
|
||||
else if (itemsType === 'string')
|
||||
else if (itemsType === "string")
|
||||
{
|
||||
this._items = TrialHandler.importConditions(this._psychoJS.serverManager, this._items);
|
||||
}
|
||||
|
||||
// unknown items type:
|
||||
else
|
||||
{
|
||||
@ -521,17 +536,14 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
this._items = [Form._defaultItems];
|
||||
}
|
||||
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
// throw { ...response, error };
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize the form items: check that the keys are valid, and fill in default values.
|
||||
*
|
||||
@ -542,8 +554,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
_sanitizeItems()
|
||||
{
|
||||
const response = {
|
||||
origin: 'Form._sanitizeItems',
|
||||
context: 'when sanitizing the form items'
|
||||
origin: "Form._sanitizeItems",
|
||||
context: "when sanitizing the form items",
|
||||
};
|
||||
|
||||
try
|
||||
@ -552,7 +564,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
for (const item of this._items)
|
||||
{
|
||||
// old style forms have questionText instead of itemText:
|
||||
if (typeof item.questionText !== 'undefined')
|
||||
if (typeof item.questionText !== "undefined")
|
||||
{
|
||||
item.itemText = item.questionText;
|
||||
delete item.questionText;
|
||||
@ -561,12 +573,11 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
delete item.questionWidth;
|
||||
|
||||
// for items of type 'rating, the ticks are in 'options' instead of in 'ticks':
|
||||
if (item.type === 'rating' || item.type === 'slider')
|
||||
if (item.type === "rating" || item.type === "slider")
|
||||
{
|
||||
item.ticks = item.options;
|
||||
item.options = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -584,9 +595,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
missingKeys.add(key);
|
||||
item[key] = Form._defaultItems[key];
|
||||
}
|
||||
|
||||
// undefined value:
|
||||
else if (typeof item[key] === 'undefined')
|
||||
else if (typeof item[key] === "undefined")
|
||||
{
|
||||
// TODO: options = '' for FREE_TEXT
|
||||
item[key] = Form._defaultItems[key];
|
||||
@ -596,16 +606,17 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
if (missingKeys.size > 0)
|
||||
{
|
||||
this._psychoJS.logger.warn(`Missing headers: ${Array.from(missingKeys).join(', ')}\nNote, headers are case sensitive and must match: ${Array.from(defaultKeys).join(', ')}`);
|
||||
this._psychoJS.logger.warn(
|
||||
`Missing headers: ${Array.from(missingKeys).join(", ")}\nNote, headers are case sensitive and must match: ${Array.from(defaultKeys).join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// check the types and options:
|
||||
const formTypes = Object.getOwnPropertyNames(Form.Types);
|
||||
for (const item of this._items)
|
||||
{
|
||||
// convert type to upper case, replace spaces by underscores
|
||||
item.type = item.type.toUpperCase().replace(' ', '_');
|
||||
item.type = item.type.toUpperCase().replace(" ", "_");
|
||||
|
||||
// check that the type is valid:
|
||||
if (!formTypes.includes(item.type))
|
||||
@ -614,9 +625,9 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
|
||||
// Support the 'radio' type found on older versions of PsychoPy
|
||||
if (item.type === 'RADIO')
|
||||
if (item.type === "RADIO")
|
||||
{
|
||||
item.type = 'CHOICE';
|
||||
item.type = "CHOICE";
|
||||
}
|
||||
|
||||
// convert item type to symbol:
|
||||
@ -625,18 +636,17 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
// turn the option into an array and check length, where applicable:
|
||||
if (item.type === Form.Types.CHOICE)
|
||||
{
|
||||
item.options = item.options.split(',');
|
||||
item.options = item.options.split(",");
|
||||
if (item.options.length < 2)
|
||||
{
|
||||
throw `at least two choices should be provided for choice item: ${item.itemText}`;
|
||||
}
|
||||
}
|
||||
|
||||
// turn the ticks and tickLabels into arrays, where applicable:
|
||||
else if (item.type === Form.Types.RATING || item.type === Form.Types.SLIDER)
|
||||
{
|
||||
item.ticks = item.ticks.split(',').map( (_,t) => parseInt(t) );
|
||||
item.tickLabels = (item.tickLabels.length > 0) ? item.tickLabels.split(',') : [];
|
||||
item.ticks = item.ticks.split(",").map((_, t) => parseInt(t));
|
||||
item.tickLabels = (item.tickLabels.length > 0) ? item.tickLabels.split(",") : [];
|
||||
}
|
||||
|
||||
// TODO
|
||||
@ -645,7 +655,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
|
||||
// check the layout:
|
||||
const formLayouts = ['HORIZ', 'VERT'];
|
||||
const formLayouts = ["HORIZ", "VERT"];
|
||||
for (const item of this._items)
|
||||
{
|
||||
// convert layout to upper case:
|
||||
@ -658,18 +668,16 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
|
||||
// convert item layout to symbol:
|
||||
item.layout = (item.layout === 'HORIZ') ? Form.Layout.HORIZONTAL : Form.Layout.VERTICAL;
|
||||
item.layout = (item.layout === "HORIZ") ? Form.Layout.HORIZONTAL : Form.Layout.VERTICAL;
|
||||
}
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
// throw { ...response, error };
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -685,12 +693,10 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pos[0] - this._size[0] / 2.0,
|
||||
this._pos[1] - this._size[1] / 2.0,
|
||||
this._size[0],
|
||||
this._size[1]
|
||||
this._size[1],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the stimuli, and the scrollbar.
|
||||
*
|
||||
@ -706,7 +712,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
|
||||
// clean up the previously setup stimuli:
|
||||
if (typeof this._visual !== 'undefined')
|
||||
if (typeof this._visual !== "undefined")
|
||||
{
|
||||
for (const textStim of this._visual.textStims)
|
||||
{
|
||||
@ -724,31 +730,30 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
textStims: [],
|
||||
responseStims: [],
|
||||
visibles: [],
|
||||
stimuliTotalHeight: 0
|
||||
stimuliTotalHeight: 0,
|
||||
};
|
||||
|
||||
// instantiate the clip mask that will be used by all stimuli:
|
||||
this._stimuliClipMask = new PIXI.Graphics();
|
||||
|
||||
|
||||
// default stimulus options:
|
||||
const textStimOption = {
|
||||
win: this._win,
|
||||
name: 'item text',
|
||||
name: "item text",
|
||||
font: this.font,
|
||||
units: this._units,
|
||||
alignHoriz: 'left',
|
||||
alignVert: 'top',
|
||||
alignHoriz: "left",
|
||||
alignVert: "top",
|
||||
height: this._fontSize,
|
||||
color: this.itemColor,
|
||||
ori: 0,
|
||||
opacity: 1,
|
||||
depth: this._depth + 1,
|
||||
clipMask: this._stimuliClipMask
|
||||
clipMask: this._stimuliClipMask,
|
||||
};
|
||||
const sliderOption = {
|
||||
win: this._win,
|
||||
name: 'choice response',
|
||||
name: "choice response",
|
||||
units: this._units,
|
||||
flip: false,
|
||||
// Not part of Slider options as things stand
|
||||
@ -763,13 +768,13 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
opacity: 1,
|
||||
depth: this._depth + 1,
|
||||
clipMask: this._stimuliClipMask,
|
||||
granularity: 1
|
||||
granularity: 1,
|
||||
};
|
||||
const textBoxOption = {
|
||||
win: this._win,
|
||||
name: 'free text response',
|
||||
name: "free text response",
|
||||
units: this._units,
|
||||
anchor: 'left-top',
|
||||
anchor: "left-top",
|
||||
flip: false,
|
||||
opacity: 1,
|
||||
depth: this._depth + 1,
|
||||
@ -777,7 +782,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
letterHeight: this._fontSize * this._responseTextHeightRatio,
|
||||
bold: false,
|
||||
italic: false,
|
||||
alignment: 'left',
|
||||
alignment: "left",
|
||||
color: this.responseColor,
|
||||
fillColor: this.fillColor,
|
||||
contrast: 1.0,
|
||||
@ -785,17 +790,16 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
borderWidth: 0.002,
|
||||
padding: 0.01,
|
||||
editable: true,
|
||||
clipMask: this._stimuliClipMask
|
||||
clipMask: this._stimuliClipMask,
|
||||
};
|
||||
|
||||
// we use for the slider's tick size the height of a word:
|
||||
const textStim = new TextStim(Object.assign(textStimOption, { text: 'Ag', pos: [0, 0]}));
|
||||
const textStim = new TextStim(Object.assign(textStimOption, { text: "Ag", pos: [0, 0] }));
|
||||
const textMetrics_px = textStim.getTextMetrics();
|
||||
const sliderTickSize = this._getLengthUnits(textMetrics_px.height) / 2;
|
||||
textStim.release(false);
|
||||
|
||||
|
||||
let stimulusOffset = - this._itemPadding;
|
||||
let stimulusOffset = -this._itemPadding;
|
||||
for (const item of this._items)
|
||||
{
|
||||
// initially, all items are invisible:
|
||||
@ -806,8 +810,10 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
// - description: <padding> + <item> + <padding> + <scrollbar> = this._size[0]
|
||||
// - choice with vert layout: <padding> + <item> + <padding> + <scrollbar> = this._size[0]
|
||||
let rowWidth;
|
||||
if (item.type === Form.Types.HEADING || item.type === Form.Types.DESCRIPTION ||
|
||||
(item.type === Form.Types.CHOICE && item.layout === Form.Layout.VERTICAL))
|
||||
if (
|
||||
item.type === Form.Types.HEADING || item.type === Form.Types.DESCRIPTION
|
||||
|| (item.type === Form.Types.CHOICE && item.layout === Form.Layout.VERTICAL)
|
||||
)
|
||||
{
|
||||
rowWidth = (this._size[0] - this._itemPadding * 2 - this._scrollbarWidth);
|
||||
}
|
||||
@ -818,12 +824,13 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
|
||||
// item text
|
||||
const itemWidth = rowWidth * item.itemWidth;
|
||||
const itemWidth = rowWidth * item.itemWidth;
|
||||
const textStim = new TextStim(
|
||||
Object.assign(textStimOption, {
|
||||
text: item.itemText,
|
||||
wrapWidth: itemWidth
|
||||
}));
|
||||
wrapWidth: itemWidth,
|
||||
}),
|
||||
);
|
||||
textStim._relativePos = [this._itemPadding, stimulusOffset];
|
||||
const textHeight = textStim.boundingBox.height;
|
||||
this._visual.textStims.push(textStim);
|
||||
@ -847,7 +854,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderSize = [sliderTickSize, (sliderTickSize*1.5) * item.options.length];
|
||||
sliderSize = [sliderTickSize, (sliderTickSize * 1.5) * item.options.length];
|
||||
compact = false;
|
||||
flip = true;
|
||||
}
|
||||
@ -882,23 +889,23 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
labels,
|
||||
ticks,
|
||||
compact,
|
||||
flip
|
||||
})
|
||||
flip,
|
||||
}),
|
||||
);
|
||||
responseHeight = responseStim.boundingBox.height;
|
||||
if (item.layout === Form.Layout.HORIZONTAL)
|
||||
{
|
||||
responseStim._relativePos = [
|
||||
this._itemPadding * 2 + itemWidth + responseWidth / 2,
|
||||
stimulusOffset
|
||||
//- Math.max(0, (textHeight - responseHeight) / 2) // (vertical centering)
|
||||
stimulusOffset,
|
||||
// - Math.max(0, (textHeight - responseHeight) / 2) // (vertical centering)
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
responseStim._relativePos = [
|
||||
this._itemPadding * 2 + itemWidth, //this._itemPadding + sliderTickSize,
|
||||
stimulusOffset - responseHeight / 2 - textHeight - this._itemPadding
|
||||
this._itemPadding * 2 + itemWidth, // this._itemPadding + sliderTickSize,
|
||||
stimulusOffset - responseHeight / 2 - textHeight - this._itemPadding,
|
||||
];
|
||||
|
||||
// since rowHeight will be the max of itemHeight and responseHeight, we need to alter responseHeight
|
||||
@ -906,20 +913,19 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
responseHeight += textHeight + this._itemPadding;
|
||||
}
|
||||
}
|
||||
|
||||
// FREE TEXT
|
||||
else if (item.type === Form.Types.FREE_TEXT)
|
||||
{
|
||||
responseStim = new TextBox(
|
||||
Object.assign(textBoxOption, {
|
||||
text: item.options,
|
||||
size: [responseWidth, -1]
|
||||
})
|
||||
size: [responseWidth, -1],
|
||||
}),
|
||||
);
|
||||
responseHeight = responseStim.boundingBox.height;
|
||||
responseStim._relativePos = [
|
||||
this._itemPadding * 2 + itemWidth,
|
||||
stimulusOffset
|
||||
stimulusOffset,
|
||||
];
|
||||
}
|
||||
|
||||
@ -932,13 +938,12 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
this._visual.stimuliTotalHeight = stimulusOffset;
|
||||
|
||||
|
||||
// scrollbar
|
||||
// note: we add this Form as a dependent stimulus such that the Form is redrawn whenever
|
||||
// the slider is updated
|
||||
this._scrollbar = new Slider({
|
||||
win: this._win,
|
||||
name: 'scrollbar',
|
||||
name: "scrollbar",
|
||||
units: this._units,
|
||||
color: this.itemColor,
|
||||
depth: this._depth + 1,
|
||||
@ -946,24 +951,20 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
size: [this._scrollbarWidth, this._size[1]],
|
||||
style: [Slider.Style.SLIDER],
|
||||
ticks: [0, -this._visual.stimuliTotalHeight / this._size[1]],
|
||||
dependentStims: [this]
|
||||
dependentStims: [this],
|
||||
});
|
||||
this._prevScrollbarMarkerPos = 0;
|
||||
this._scrollbar.setMarkerPos(this._prevScrollbarMarkerPos);
|
||||
|
||||
|
||||
// estimate the bounding box:
|
||||
this._estimateBoundingBox();
|
||||
|
||||
|
||||
if (this._autoLog)
|
||||
{
|
||||
this._psychoJS.experimentLogger.exp(`Layout set for: ${this.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the form visual representation, if necessary.
|
||||
*
|
||||
@ -991,17 +992,18 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
[this._leftEdge, this._topEdge],
|
||||
this.units,
|
||||
this.win,
|
||||
true);
|
||||
true,
|
||||
);
|
||||
[this._rightEdge_px, this._bottomEdge_px] = util.to_px(
|
||||
[this._rightEdge, this._bottomEdge],
|
||||
this.units,
|
||||
this.win,
|
||||
true);
|
||||
true,
|
||||
);
|
||||
this._itemPadding_px = this._getLengthPix(this._itemPadding);
|
||||
this._scrollbarWidth_px = this._getLengthPix(this._scrollbarWidth, true);
|
||||
this._size_px = util.to_px(this._size, this.units, this.win, true);
|
||||
|
||||
|
||||
// update the stimuli clip mask
|
||||
// note: the clip mask is in screen coordinates
|
||||
this._stimuliClipMask.clear();
|
||||
@ -1010,11 +1012,10 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._win._rootContainer.position.x + this._leftEdge_px + 2,
|
||||
this._win._rootContainer.position.y + this._bottomEdge_px + 2,
|
||||
this._size_px[0] - 4,
|
||||
this._size_px[1] - 6
|
||||
this._size_px[1] - 6,
|
||||
);
|
||||
this._stimuliClipMask.endFill();
|
||||
|
||||
|
||||
// position the scrollbar and get the scrollbar offset, in form units:
|
||||
this._scrollbar.setPos([this._rightEdge - this._scrollbarWidth / 2, this._pos[1]], false);
|
||||
this._scrollbar.setOpacity(0.5);
|
||||
@ -1025,8 +1026,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._updateDecorations();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the visible stimuli.
|
||||
*
|
||||
@ -1042,7 +1041,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
const textStim = this._visual.textStims[i];
|
||||
const textStimPos = [
|
||||
this._leftEdge + textStim._relativePos[0],
|
||||
this._topEdge + textStim._relativePos[1] - this._scrollbarOffset
|
||||
this._topEdge + textStim._relativePos[1] - this._scrollbarOffset,
|
||||
];
|
||||
textStim.setPos(textStimPos);
|
||||
|
||||
@ -1052,7 +1051,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
const responseStimPos = [
|
||||
this._leftEdge + responseStim._relativePos[0],
|
||||
this._topEdge + responseStim._relativePos[1] - this._scrollbarOffset
|
||||
this._topEdge + responseStim._relativePos[1] - this._scrollbarOffset,
|
||||
];
|
||||
responseStim.setPos(responseStimPos);
|
||||
}
|
||||
@ -1078,11 +1077,8 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._visual.visibles[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the form decorations (bounding box, lines between items, etc.)
|
||||
*
|
||||
@ -1092,7 +1088,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
_updateDecorations()
|
||||
{
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
@ -1109,7 +1105,6 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
// apply the form clip mask (n.b., that is not the stimuli clip mask):
|
||||
this._pixi.mask = this._clipMask;
|
||||
|
||||
|
||||
// form background:
|
||||
this._pixi.lineStyle(1, new Color(this.borderColor).int, this._opacity, 0.5);
|
||||
// this._decorations.beginFill(this._barFillColor.int, this._opacity);
|
||||
@ -1122,7 +1117,7 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._decorations = new PIXI.Graphics();
|
||||
this._pixi.addChild(this._decorations);
|
||||
this._decorations.mask = this._stimuliClipMask;
|
||||
this._decorations.lineStyle(1, new Color('gray').int, this._opacity, 0.5);
|
||||
this._decorations.lineStyle(1, new Color("gray").int, this._opacity, 0.5);
|
||||
this._decorations.alpha = 0.5;
|
||||
|
||||
for (let i = 0; i < this._items.length; ++i)
|
||||
@ -1136,27 +1131,23 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
const textStim = this._visual.textStims[i];
|
||||
const textStimPos = [
|
||||
this._leftEdge + textStim._relativePos[0],
|
||||
this._topEdge + textStim._relativePos[1] - this._scrollbarOffset
|
||||
this._topEdge + textStim._relativePos[1] - this._scrollbarOffset,
|
||||
];
|
||||
const textStimPos_px = util.to_px(textStimPos, this._units, this._win);
|
||||
this._decorations.beginFill(new Color('darkgray').int);
|
||||
this._decorations.beginFill(new Color("darkgray").int);
|
||||
this._decorations.drawRect(
|
||||
textStimPos_px[0] - this._itemPadding_px / 2,
|
||||
textStimPos_px[1] + this._itemPadding_px / 2,
|
||||
this._size_px[0] - this._itemPadding_px - this._scrollbarWidth_px,
|
||||
-this._getLengthPix(this._visual.rowHeights[i]) - this._itemPadding_px
|
||||
-this._getLengthPix(this._visual.rowHeights[i]) - this._itemPadding_px,
|
||||
);
|
||||
this._decorations.endFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Form item types.
|
||||
*
|
||||
@ -1165,17 +1156,15 @@ export class Form extends util.mix(VisualStim).with(ColorMixin)
|
||||
* @public
|
||||
*/
|
||||
Form.Types = {
|
||||
HEADING: Symbol.for('HEADING'),
|
||||
DESCRIPTION: Symbol.for('DESCRIPTION'),
|
||||
RATING: Symbol.for('RATING'),
|
||||
SLIDER: Symbol.for('SLIDER'),
|
||||
FREE_TEXT: Symbol.for('FREE_TEXT'),
|
||||
CHOICE: Symbol.for('CHOICE'),
|
||||
RADIO: Symbol.for('RADIO')
|
||||
HEADING: Symbol.for("HEADING"),
|
||||
DESCRIPTION: Symbol.for("DESCRIPTION"),
|
||||
RATING: Symbol.for("RATING"),
|
||||
SLIDER: Symbol.for("SLIDER"),
|
||||
FREE_TEXT: Symbol.for("FREE_TEXT"),
|
||||
CHOICE: Symbol.for("CHOICE"),
|
||||
RADIO: Symbol.for("RADIO"),
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Form item layout.
|
||||
*
|
||||
@ -1184,12 +1173,10 @@ Form.Types = {
|
||||
* @public
|
||||
*/
|
||||
Form.Layout = {
|
||||
HORIZONTAL: Symbol.for('HORIZONTAL'),
|
||||
VERTICAL: Symbol.for('VERTICAL')
|
||||
HORIZONTAL: Symbol.for("HORIZONTAL"),
|
||||
VERTICAL: Symbol.for("VERTICAL"),
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default form item.
|
||||
*
|
||||
@ -1198,18 +1185,16 @@ Form.Layout = {
|
||||
*
|
||||
*/
|
||||
Form._defaultItems = {
|
||||
'itemText': 'Default question',
|
||||
'type': 'rating',
|
||||
'options': 'Yes, No',
|
||||
'tickLabels': '',
|
||||
'itemWidth': 0.7,
|
||||
'itemColor': 'white',
|
||||
"itemText": "Default question",
|
||||
"type": "rating",
|
||||
"options": "Yes, No",
|
||||
"tickLabels": "",
|
||||
"itemWidth": 0.7,
|
||||
"itemColor": "white",
|
||||
|
||||
'responseWidth': 0.3,
|
||||
'responseColor': 'white',
|
||||
"responseWidth": 0.3,
|
||||
"responseColor": "white",
|
||||
|
||||
'index': 0,
|
||||
'layout': 'horiz'
|
||||
"index": 0,
|
||||
"layout": "horiz",
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,14 +7,12 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* Image Stimulus.
|
||||
@ -46,53 +44,53 @@ import { to_pixiPoint } from "../util/Pixi.js";
|
||||
*/
|
||||
export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({name, win, image, mask, pos, units, ori, size, color, opacity, contrast, texRes, depth, interpolate, flipHoriz, flipVert, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, image, mask, pos, units, ori, size, color, opacity, contrast, texRes, depth, interpolate, flipHoriz, flipVert, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({name, win, units, ori, opacity, depth, pos, size, autoDraw, autoLog});
|
||||
super({ name, win, units, ori, opacity, depth, pos, size, autoDraw, autoLog });
|
||||
|
||||
this._addAttribute(
|
||||
'image',
|
||||
image
|
||||
"image",
|
||||
image,
|
||||
);
|
||||
this._addAttribute(
|
||||
'mask',
|
||||
mask
|
||||
"mask",
|
||||
mask,
|
||||
);
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
color,
|
||||
'white',
|
||||
this._onChange(true, false)
|
||||
"white",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'texRes',
|
||||
"texRes",
|
||||
texRes,
|
||||
128,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'interpolate',
|
||||
"interpolate",
|
||||
interpolate,
|
||||
false,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipHoriz',
|
||||
"flipHoriz",
|
||||
flipHoriz,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipVert',
|
||||
"flipVert",
|
||||
flipVert,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
// estimate the bounding box:
|
||||
@ -104,8 +102,6 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the image attribute.
|
||||
*
|
||||
@ -117,22 +113,22 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
setImage(image, log = false)
|
||||
{
|
||||
const response = {
|
||||
origin: 'ImageStim.setImage',
|
||||
context: 'when setting the image of ImageStim: ' + this._name
|
||||
origin: "ImageStim.setImage",
|
||||
context: "when setting the image of ImageStim: " + this._name,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// image is undefined: that's fine but we raise a warning in case this is a symptom of an actual problem
|
||||
if (typeof image === 'undefined')
|
||||
if (typeof image === "undefined")
|
||||
{
|
||||
this.psychoJS.logger.warn('setting the image of ImageStim: ' + this._name + ' with argument: undefined.');
|
||||
this.psychoJS.logger.debug('set the image of ImageStim: ' + this._name + ' as: undefined');
|
||||
this.psychoJS.logger.warn("setting the image of ImageStim: " + this._name + " with argument: undefined.");
|
||||
this.psychoJS.logger.debug("set the image of ImageStim: " + this._name + " as: undefined");
|
||||
}
|
||||
else
|
||||
{
|
||||
// image is a string: it should be the name of a resource, which we load
|
||||
if (typeof image === 'string')
|
||||
if (typeof image === "string")
|
||||
{
|
||||
image = this.psychoJS.serverManager.getResource(image);
|
||||
}
|
||||
@ -140,16 +136,16 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
// image should now be an actual HTMLImageElement: we raise an error if it is not
|
||||
if (!(image instanceof HTMLImageElement))
|
||||
{
|
||||
throw 'the argument: ' + image.toString() + ' is not an image" }';
|
||||
throw "the argument: " + image.toString() + ' is not an image" }';
|
||||
}
|
||||
|
||||
this.psychoJS.logger.debug('set the image of ImageStim: ' + this._name + ' as: src= ' + image.src + ', size= ' + image.width + 'x' + image.height);
|
||||
this.psychoJS.logger.debug("set the image of ImageStim: " + this._name + " as: src= " + image.src + ", size= " + image.width + "x" + image.height);
|
||||
}
|
||||
|
||||
const existingImage = this.getImage();
|
||||
const hasChanged = existingImage ? existingImage.src !== image.src : true;
|
||||
|
||||
this._setAttribute('image', image, log);
|
||||
this._setAttribute("image", image, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -158,12 +154,10 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the mask attribute.
|
||||
*
|
||||
@ -175,22 +169,22 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
setMask(mask, log = false)
|
||||
{
|
||||
const response = {
|
||||
origin: 'ImageStim.setMask',
|
||||
context: 'when setting the mask of ImageStim: ' + this._name
|
||||
origin: "ImageStim.setMask",
|
||||
context: "when setting the mask of ImageStim: " + this._name,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// mask is undefined: that's fine but we raise a warning in case this is a sympton of an actual problem
|
||||
if (typeof mask === 'undefined')
|
||||
if (typeof mask === "undefined")
|
||||
{
|
||||
this.psychoJS.logger.warn('setting the mask of ImageStim: ' + this._name + ' with argument: undefined.');
|
||||
this.psychoJS.logger.debug('set the mask of ImageStim: ' + this._name + ' as: undefined');
|
||||
this.psychoJS.logger.warn("setting the mask of ImageStim: " + this._name + " with argument: undefined.");
|
||||
this.psychoJS.logger.debug("set the mask of ImageStim: " + this._name + " as: undefined");
|
||||
}
|
||||
else
|
||||
{
|
||||
// mask is a string: it should be the name of a resource, which we load
|
||||
if (typeof mask === 'string')
|
||||
if (typeof mask === "string")
|
||||
{
|
||||
mask = this.psychoJS.serverManager.getResource(mask);
|
||||
}
|
||||
@ -198,24 +192,22 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
// mask should now be an actual HTMLImageElement: we raise an error if it is not
|
||||
if (!(mask instanceof HTMLImageElement))
|
||||
{
|
||||
throw 'the argument: ' + mask.toString() + ' is not an image" }';
|
||||
throw "the argument: " + mask.toString() + ' is not an image" }';
|
||||
}
|
||||
|
||||
this.psychoJS.logger.debug('set the mask of ImageStim: ' + this._name + ' as: src= ' + mask.src + ', size= ' + mask.width + 'x' + mask.height);
|
||||
this.psychoJS.logger.debug("set the mask of ImageStim: " + this._name + " as: src= " + mask.src + ", size= " + mask.width + "x" + mask.height);
|
||||
}
|
||||
|
||||
this._setAttribute('mask', mask, log);
|
||||
this._setAttribute("mask", mask, log);
|
||||
|
||||
this._onChange(true, false)();
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -227,21 +219,19 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
_estimateBoundingBox()
|
||||
{
|
||||
const size = this._getDisplaySize();
|
||||
if (typeof size !== 'undefined')
|
||||
if (typeof size !== "undefined")
|
||||
{
|
||||
this._boundingBox = new PIXI.Rectangle(
|
||||
this._pos[0] - size[0] / 2,
|
||||
this._pos[1] - size[1] / 2,
|
||||
size[0],
|
||||
size[1]
|
||||
size[1],
|
||||
);
|
||||
}
|
||||
|
||||
// TODO take the orientation into account
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -261,14 +251,14 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
this._needPixiUpdate = false;
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
this._pixi = undefined;
|
||||
|
||||
// no image to draw: return immediately
|
||||
if (typeof this._image === 'undefined')
|
||||
if (typeof this._image === "undefined")
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -279,7 +269,7 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pixi = PIXI.Sprite.from(this._texture);
|
||||
|
||||
// add a mask if need be:
|
||||
if (typeof this._mask !== 'undefined')
|
||||
if (typeof this._mask !== "undefined")
|
||||
{
|
||||
this._pixi.mask = PIXI.Sprite.from(this._mask);
|
||||
|
||||
@ -330,8 +320,6 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._estimateBoundingBox();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the size of the display image, which is either that of the ImageStim or that of the image
|
||||
* it contains.
|
||||
@ -344,18 +332,16 @@ export class ImageStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
let displaySize = this.size;
|
||||
|
||||
if (typeof displaySize === 'undefined')
|
||||
if (typeof displaySize === "undefined")
|
||||
{
|
||||
// use the size of the texture, if we have access to it:
|
||||
if (typeof this._texture !== 'undefined' && this._texture.width > 0)
|
||||
if (typeof this._texture !== "undefined" && this._texture.width > 0)
|
||||
{
|
||||
const textureSize = [this._texture.width, this._texture.height];
|
||||
displaySize = util.to_unit(textureSize, 'pix', this.win, this.units);
|
||||
displaySize = util.to_unit(textureSize, "pix", this.win, this.units);
|
||||
}
|
||||
}
|
||||
|
||||
return displaySize;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,15 +7,13 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import {PsychoJS} from "../core/PsychoJS.js";
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { PsychoJS } from "../core/PsychoJS.js";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* Movie Stimulus.
|
||||
@ -49,82 +47,81 @@ import { to_pixiPoint } from "../util/Pixi.js";
|
||||
*/
|
||||
export class MovieStim extends VisualStim
|
||||
{
|
||||
constructor({name, win, movie, pos, units, ori, size, color, opacity, contrast, interpolate, flipHoriz, flipVert, loop, volume, noAudio, autoPlay, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, movie, pos, units, ori, size, color, opacity, contrast, interpolate, flipHoriz, flipVert, loop, volume, noAudio, autoPlay, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({name, win, units, ori, opacity, pos, size, autoDraw, autoLog});
|
||||
super({ name, win, units, ori, opacity, pos, size, autoDraw, autoLog });
|
||||
|
||||
this.psychoJS.logger.debug('create a new MovieStim with name: ', name);
|
||||
this.psychoJS.logger.debug("create a new MovieStim with name: ", name);
|
||||
|
||||
// movie and movie control:
|
||||
this._addAttribute(
|
||||
'movie',
|
||||
movie
|
||||
"movie",
|
||||
movie,
|
||||
);
|
||||
this._addAttribute(
|
||||
'volume',
|
||||
"volume",
|
||||
volume,
|
||||
1.0,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'noAudio',
|
||||
"noAudio",
|
||||
noAudio,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'autoPlay',
|
||||
"autoPlay",
|
||||
autoPlay,
|
||||
true,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'flipHoriz',
|
||||
"flipHoriz",
|
||||
flipHoriz,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipVert',
|
||||
"flipVert",
|
||||
flipVert,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'interpolate',
|
||||
"interpolate",
|
||||
interpolate,
|
||||
false,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
// colors:
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
color,
|
||||
'white',
|
||||
this._onChange(true, false)
|
||||
"white",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'loop',
|
||||
"loop",
|
||||
loop,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
|
||||
// estimate the bounding box:
|
||||
this._estimateBoundingBox();
|
||||
|
||||
// check whether the fastSeek method on HTMLVideoElement is implemented:
|
||||
const videoElement = document.createElement('video');
|
||||
this._hasFastSeek = (typeof videoElement.fastSeek === 'function');
|
||||
const videoElement = document.createElement("video");
|
||||
this._hasFastSeek = (typeof videoElement.fastSeek === "function");
|
||||
|
||||
if (this._autoLog)
|
||||
{
|
||||
@ -132,8 +129,6 @@ export class MovieStim extends VisualStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the movie attribute.
|
||||
*
|
||||
@ -146,22 +141,22 @@ export class MovieStim extends VisualStim
|
||||
setMovie(movie, log = false)
|
||||
{
|
||||
const response = {
|
||||
origin: 'MovieStim.setMovie',
|
||||
context: 'when setting the movie of MovieStim: ' + this._name
|
||||
origin: "MovieStim.setMovie",
|
||||
context: "when setting the movie of MovieStim: " + this._name,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// movie is undefined: that's fine but we raise a warning in case this is a symptom of an actual problem
|
||||
if (typeof movie === 'undefined')
|
||||
if (typeof movie === "undefined")
|
||||
{
|
||||
this.psychoJS.logger.warn('setting the movie of MovieStim: ' + this._name + ' with argument: undefined.');
|
||||
this.psychoJS.logger.debug('set the movie of MovieStim: ' + this._name + ' as: undefined');
|
||||
this.psychoJS.logger.warn("setting the movie of MovieStim: " + this._name + " with argument: undefined.");
|
||||
this.psychoJS.logger.debug("set the movie of MovieStim: " + this._name + " as: undefined");
|
||||
}
|
||||
else
|
||||
{
|
||||
// movie is a string: it should be the name of a resource, which we load
|
||||
if (typeof movie === 'string')
|
||||
if (typeof movie === "string")
|
||||
{
|
||||
movie = this.psychoJS.serverManager.getResource(movie);
|
||||
}
|
||||
@ -169,7 +164,7 @@ export class MovieStim extends VisualStim
|
||||
// movie should now be an actual HTMLVideoElement: we raise an error if it is not
|
||||
if (!(movie instanceof HTMLVideoElement))
|
||||
{
|
||||
throw 'the argument: ' + movie.toString() + ' is not a video" }';
|
||||
throw "the argument: " + movie.toString() + ' is not a video" }';
|
||||
}
|
||||
|
||||
this.psychoJS.logger.debug(`set the movie of MovieStim: ${this._name} as: src= ${movie.src}, size= ${movie.videoWidth}x${movie.videoHeight}, duration= ${movie.duration}s`);
|
||||
@ -186,20 +181,16 @@ export class MovieStim extends VisualStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
this._setAttribute('movie', movie, log);
|
||||
this._setAttribute("movie", movie, log);
|
||||
this._needUpdate = true;
|
||||
this._needPixiUpdate = true;
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
throw Object.assign(response, {error});
|
||||
throw Object.assign(response, { error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reset the stimulus.
|
||||
*
|
||||
@ -212,8 +203,6 @@ export class MovieStim extends VisualStim
|
||||
this.seek(0, log);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Start playing the movie.
|
||||
*
|
||||
@ -228,18 +217,17 @@ export class MovieStim extends VisualStim
|
||||
|
||||
if (playPromise !== undefined)
|
||||
{
|
||||
playPromise.catch((error) => {
|
||||
playPromise.catch((error) =>
|
||||
{
|
||||
throw {
|
||||
origin: 'MovieStim.play',
|
||||
origin: "MovieStim.play",
|
||||
context: `when attempting to play MovieStim: ${this._name}`,
|
||||
error
|
||||
error,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pause the movie.
|
||||
*
|
||||
@ -251,8 +239,6 @@ export class MovieStim extends VisualStim
|
||||
this._movie.pause();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Stop the movie and reset to 0s.
|
||||
*
|
||||
@ -265,8 +251,6 @@ export class MovieStim extends VisualStim
|
||||
this.seek(0, log);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Jump to a specific timepoint
|
||||
*
|
||||
@ -280,9 +264,9 @@ export class MovieStim extends VisualStim
|
||||
if (timePoint < 0 || timePoint > this._movie.duration)
|
||||
{
|
||||
throw {
|
||||
origin: 'MovieStim.seek',
|
||||
origin: "MovieStim.seek",
|
||||
context: `when seeking to timepoint: ${timePoint} of MovieStim: ${this._name}`,
|
||||
error: `the timepoint does not belong to [0, ${this._movie.duration}`
|
||||
error: `the timepoint does not belong to [0, ${this._movie.duration}`,
|
||||
};
|
||||
}
|
||||
|
||||
@ -299,16 +283,14 @@ export class MovieStim extends VisualStim
|
||||
catch (error)
|
||||
{
|
||||
throw {
|
||||
origin: 'MovieStim.seek',
|
||||
origin: "MovieStim.seek",
|
||||
context: `when seeking to timepoint: ${timePoint} of MovieStim: ${this._name}`,
|
||||
error
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -320,21 +302,19 @@ export class MovieStim extends VisualStim
|
||||
_estimateBoundingBox()
|
||||
{
|
||||
const size = this._getDisplaySize();
|
||||
if (typeof size !== 'undefined')
|
||||
if (typeof size !== "undefined")
|
||||
{
|
||||
this._boundingBox = new PIXI.Rectangle(
|
||||
this._pos[0] - size[0] / 2,
|
||||
this._pos[1] - size[1] / 2,
|
||||
size[0],
|
||||
size[1]
|
||||
size[1],
|
||||
);
|
||||
}
|
||||
|
||||
// TODO take the orientation into account
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -354,20 +334,20 @@ export class MovieStim extends VisualStim
|
||||
{
|
||||
this._needPixiUpdate = false;
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
// Leave original video in place
|
||||
// https://pixijs.download/dev/docs/PIXI.Sprite.html#destroy
|
||||
this._pixi.destroy({
|
||||
children: true,
|
||||
texture: true,
|
||||
baseTexture: false
|
||||
baseTexture: false,
|
||||
});
|
||||
}
|
||||
this._pixi = undefined;
|
||||
|
||||
// no movie to draw: return immediately
|
||||
if (typeof this._movie === 'undefined')
|
||||
if (typeof this._movie === "undefined")
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -414,8 +394,6 @@ export class MovieStim extends VisualStim
|
||||
this._estimateBoundingBox();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the size of the display image, which is either that of the ImageStim or that of the image
|
||||
* it contains.
|
||||
@ -428,18 +406,16 @@ export class MovieStim extends VisualStim
|
||||
{
|
||||
let displaySize = this.size;
|
||||
|
||||
if (typeof displaySize === 'undefined')
|
||||
if (typeof displaySize === "undefined")
|
||||
{
|
||||
// use the size of the texture, if we have access to it:
|
||||
if (typeof this._texture !== 'undefined' && this._texture.width > 0)
|
||||
if (typeof this._texture !== "undefined" && this._texture.width > 0)
|
||||
{
|
||||
const textureSize = [this._texture.width, this._texture.height];
|
||||
displaySize = util.to_unit(textureSize, 'pix', this.win, this.units);
|
||||
displaySize = util.to_unit(textureSize, "pix", this.win, this.units);
|
||||
}
|
||||
}
|
||||
|
||||
return displaySize;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -7,10 +7,8 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import {ShapeStim} from './ShapeStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ShapeStim } from "./ShapeStim.js";
|
||||
|
||||
/**
|
||||
* <p>Polygonal visual stimulus.</p>
|
||||
@ -39,7 +37,7 @@ import {Color} from '../util/Color.js';
|
||||
*/
|
||||
export class Polygon extends ShapeStim
|
||||
{
|
||||
constructor({name, win, lineWidth, lineColor, fillColor, opacity, edges, radius, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, lineWidth, lineColor, fillColor, opacity, edges, radius, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({
|
||||
name,
|
||||
@ -56,20 +54,20 @@ export class Polygon extends ShapeStim
|
||||
depth,
|
||||
interpolate,
|
||||
autoDraw,
|
||||
autoLog
|
||||
autoLog,
|
||||
});
|
||||
|
||||
this._psychoJS.logger.debug('create a new Polygon with name: ', name);
|
||||
this._psychoJS.logger.debug("create a new Polygon with name: ", name);
|
||||
|
||||
this._addAttribute(
|
||||
'edges',
|
||||
"edges",
|
||||
edges,
|
||||
3
|
||||
3,
|
||||
);
|
||||
this._addAttribute(
|
||||
'radius',
|
||||
"radius",
|
||||
radius,
|
||||
0.5
|
||||
0.5,
|
||||
);
|
||||
|
||||
this._updateVertices();
|
||||
@ -80,8 +78,6 @@ export class Polygon extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the radius attribute.
|
||||
*
|
||||
@ -92,7 +88,7 @@ export class Polygon extends ShapeStim
|
||||
*/
|
||||
setRadius(radius, log = false)
|
||||
{
|
||||
const hasChanged = this._setAttribute('radius', radius, log);
|
||||
const hasChanged = this._setAttribute("radius", radius, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -100,8 +96,6 @@ export class Polygon extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the edges attribute.
|
||||
*
|
||||
@ -112,7 +106,7 @@ export class Polygon extends ShapeStim
|
||||
*/
|
||||
setEdges(edges, log = false)
|
||||
{
|
||||
const hasChanged = this._setAttribute('edges', Math.round(edges), log);
|
||||
const hasChanged = this._setAttribute("edges", Math.round(edges), log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -120,8 +114,6 @@ export class Polygon extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the vertices.
|
||||
*
|
||||
@ -130,7 +122,7 @@ export class Polygon extends ShapeStim
|
||||
*/
|
||||
_updateVertices()
|
||||
{
|
||||
this._psychoJS.logger.debug('update the vertices of Polygon: ', this.name);
|
||||
this._psychoJS.logger.debug("update the vertices of Polygon: ", this.name);
|
||||
|
||||
const angle = 2.0 * Math.PI / this._edges;
|
||||
const vertices = [];
|
||||
@ -141,5 +133,4 @@ export class Polygon extends ShapeStim
|
||||
|
||||
this.setVertices(vertices);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,10 +7,8 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import {ShapeStim} from './ShapeStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ShapeStim } from "./ShapeStim.js";
|
||||
|
||||
/**
|
||||
* <p>Rectangular visual stimulus.</p>
|
||||
@ -39,7 +37,7 @@ import {Color} from '../util/Color.js';
|
||||
*/
|
||||
export class Rect extends ShapeStim
|
||||
{
|
||||
constructor({name, win, lineWidth, lineColor, fillColor, opacity, width, height, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, lineWidth, lineColor, fillColor, opacity, width, height, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({
|
||||
name,
|
||||
@ -56,20 +54,20 @@ export class Rect extends ShapeStim
|
||||
depth,
|
||||
interpolate,
|
||||
autoDraw,
|
||||
autoLog
|
||||
autoLog,
|
||||
});
|
||||
|
||||
this._psychoJS.logger.debug('create a new Rect with name: ', name);
|
||||
this._psychoJS.logger.debug("create a new Rect with name: ", name);
|
||||
|
||||
this._addAttribute(
|
||||
'width',
|
||||
"width",
|
||||
width,
|
||||
0.5
|
||||
0.5,
|
||||
);
|
||||
this._addAttribute(
|
||||
'height',
|
||||
"height",
|
||||
height,
|
||||
0.5
|
||||
0.5,
|
||||
);
|
||||
|
||||
this._updateVertices();
|
||||
@ -80,8 +78,6 @@ export class Rect extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the width attribute.
|
||||
*
|
||||
@ -92,9 +88,9 @@ export class Rect extends ShapeStim
|
||||
*/
|
||||
setWidth(width, log = false)
|
||||
{
|
||||
this._psychoJS.logger.debug('set the width of Rect: ', this.name, 'to: ', width);
|
||||
this._psychoJS.logger.debug("set the width of Rect: ", this.name, "to: ", width);
|
||||
|
||||
const hasChanged = this._setAttribute('width', width, log);
|
||||
const hasChanged = this._setAttribute("width", width, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -102,8 +98,6 @@ export class Rect extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the height attribute.
|
||||
*
|
||||
@ -114,9 +108,9 @@ export class Rect extends ShapeStim
|
||||
*/
|
||||
setHeight(height, log = false)
|
||||
{
|
||||
this._psychoJS.logger.debug('set the height of Rect: ', this.name, 'to: ', height);
|
||||
this._psychoJS.logger.debug("set the height of Rect: ", this.name, "to: ", height);
|
||||
|
||||
const hasChanged = this._setAttribute('height', height, log);
|
||||
const hasChanged = this._setAttribute("height", height, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -124,8 +118,6 @@ export class Rect extends ShapeStim
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the vertices.
|
||||
*
|
||||
@ -134,7 +126,7 @@ export class Rect extends ShapeStim
|
||||
*/
|
||||
_updateVertices()
|
||||
{
|
||||
this._psychoJS.logger.debug('update the vertices of Rect: ', this.name);
|
||||
this._psychoJS.logger.debug("update the vertices of Rect: ", this.name);
|
||||
|
||||
const halfWidth = this._width / 2.0;
|
||||
const halfHeight = this._height / 2.0;
|
||||
@ -143,8 +135,7 @@ export class Rect extends ShapeStim
|
||||
[-halfWidth, -halfHeight],
|
||||
[halfWidth, -halfHeight],
|
||||
[halfWidth, halfHeight],
|
||||
[-halfWidth, halfHeight]
|
||||
[-halfWidth, halfHeight],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,15 +8,13 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { WindowMixin } from "../core/WindowMixin.js";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
import {WindowMixin} from "../core/WindowMixin.js";
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* <p>This class provides the basic functionality of shape stimuli.</p>
|
||||
@ -45,9 +43,9 @@ import {WindowMixin} from "../core/WindowMixin.js";
|
||||
*/
|
||||
export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
{
|
||||
constructor({name, win, lineWidth, lineColor, fillColor, opacity, vertices, closeShape, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, lineWidth, lineColor, fillColor, opacity, vertices, closeShape, pos, size, ori, units, contrast, depth, interpolate, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({name, win, units, ori, opacity, pos, depth, size, autoDraw, autoLog});
|
||||
super({ name, win, units, ori, opacity, pos, depth, size, autoDraw, autoLog });
|
||||
|
||||
// the PIXI polygon corresponding to the vertices, in pixel units:
|
||||
this._pixiPolygon_px = undefined;
|
||||
@ -55,58 +53,56 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
this._vertices_px = undefined;
|
||||
|
||||
// shape:
|
||||
if (typeof size === 'undefined' || size === null)
|
||||
if (typeof size === "undefined" || size === null)
|
||||
{
|
||||
this.size = [1.0, 1.0];
|
||||
}
|
||||
this._addAttribute(
|
||||
'vertices',
|
||||
"vertices",
|
||||
vertices,
|
||||
[[-0.5, 0], [0, 0.5], [0.5, 0]]
|
||||
[[-0.5, 0], [0, 0.5], [0.5, 0]],
|
||||
);
|
||||
this._addAttribute(
|
||||
'closeShape',
|
||||
"closeShape",
|
||||
closeShape,
|
||||
true,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'interpolate',
|
||||
"interpolate",
|
||||
interpolate,
|
||||
true,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'lineWidth',
|
||||
"lineWidth",
|
||||
lineWidth,
|
||||
1.5,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
// colors:
|
||||
this._addAttribute(
|
||||
'lineColor',
|
||||
"lineColor",
|
||||
lineColor,
|
||||
'white',
|
||||
this._onChange(true, false)
|
||||
"white",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'fillColor',
|
||||
"fillColor",
|
||||
fillColor,
|
||||
undefined,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the vertices attribute.
|
||||
*
|
||||
@ -118,16 +114,16 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
setVertices(vertices, log = false)
|
||||
{
|
||||
const response = {
|
||||
origin: 'ShapeStim.setVertices',
|
||||
context: 'when setting the vertices of ShapeStim: ' + this._name
|
||||
origin: "ShapeStim.setVertices",
|
||||
context: "when setting the vertices of ShapeStim: " + this._name,
|
||||
};
|
||||
|
||||
this._psychoJS.logger.debug('set the vertices of ShapeStim:', this.name);
|
||||
this._psychoJS.logger.debug("set the vertices of ShapeStim:", this.name);
|
||||
|
||||
try
|
||||
{
|
||||
// if vertices is a string, we check whether it is a known shape:
|
||||
if (typeof vertices === 'string')
|
||||
if (typeof vertices === "string")
|
||||
{
|
||||
if (vertices in ShapeStim.KnownShapes)
|
||||
{
|
||||
@ -139,18 +135,16 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
}
|
||||
}
|
||||
|
||||
this._setAttribute('vertices', vertices, log);
|
||||
this._setAttribute("vertices", vertices, log);
|
||||
|
||||
this._onChange(true, true)();
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
throw Object.assign(response, {error: error});
|
||||
throw Object.assign(response, { error: error });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether an object is inside the bounding box of the ShapeStim.
|
||||
*
|
||||
@ -168,24 +162,22 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
// get the position of the object, in pixel coordinates:
|
||||
const objectPos_px = util.getPositionFromObject(object, units);
|
||||
|
||||
if (typeof objectPos_px === 'undefined')
|
||||
if (typeof objectPos_px === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'VisualStim.contains',
|
||||
context: 'when determining whether VisualStim: ' + this._name + ' contains object: ' + util.toString(object),
|
||||
error: 'unable to determine the position of the object'
|
||||
origin: "VisualStim.contains",
|
||||
context: "when determining whether VisualStim: " + this._name + " contains object: " + util.toString(object),
|
||||
error: "unable to determine the position of the object",
|
||||
};
|
||||
}
|
||||
|
||||
// test for inclusion:
|
||||
const pos_px = util.to_px(this.pos, this.units, this.win);
|
||||
this._getVertices_px();
|
||||
const polygon_px = this._vertices_px.map(v => [v[0] + pos_px[0], v[1] + pos_px[1]]);
|
||||
const polygon_px = this._vertices_px.map((v) => [v[0] + pos_px[0], v[1] + pos_px[1]]);
|
||||
return util.IsPointInsidePolygon(objectPos_px, polygon_px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -203,7 +195,7 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
Number.POSITIVE_INFINITY,
|
||||
Number.POSITIVE_INFINITY,
|
||||
Number.NEGATIVE_INFINITY,
|
||||
Number.NEGATIVE_INFINITY
|
||||
Number.NEGATIVE_INFINITY,
|
||||
];
|
||||
for (const vertex of this._vertices_px)
|
||||
{
|
||||
@ -217,14 +209,12 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
this._pos[0] + this._getLengthUnits(limits_px[0]),
|
||||
this._pos[1] + this._getLengthUnits(limits_px[1]),
|
||||
this._getLengthUnits(limits_px[2] - limits_px[0]),
|
||||
this._getLengthUnits(limits_px[3] - limits_px[1])
|
||||
this._getLengthUnits(limits_px[3] - limits_px[1]),
|
||||
);
|
||||
|
||||
// TODO take the orientation into account
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -244,7 +234,7 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
{
|
||||
this._needPixiUpdate = false;
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
@ -256,13 +246,13 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
// prepare the polygon in the given color and opacity:
|
||||
this._pixi = new PIXI.Graphics();
|
||||
this._pixi.lineStyle(this._lineWidth, this._lineColor.int, this._opacity, 0.5);
|
||||
if (typeof this._fillColor !== 'undefined' && this._fillColor !== null)
|
||||
if (typeof this._fillColor !== "undefined" && this._fillColor !== null)
|
||||
{
|
||||
const contrastedColor = this.getContrastedColor(new Color(this._fillColor), this._contrast);
|
||||
this._pixi.beginFill(contrastedColor.int, this._opacity);
|
||||
}
|
||||
this._pixi.drawPolygon(this._pixiPolygon_px);
|
||||
if (typeof this._fillColor !== 'undefined' && this._fillColor !== null)
|
||||
if (typeof this._fillColor !== "undefined" && this._fillColor !== null)
|
||||
{
|
||||
this._pixi.endFill();
|
||||
}
|
||||
@ -273,8 +263,6 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
this._pixi.rotation = this.ori * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the PIXI polygon (in pixel units) corresponding to the vertices.
|
||||
*
|
||||
@ -312,8 +300,6 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
return this._pixiPolygon_px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the vertices in pixel units.
|
||||
*
|
||||
@ -325,28 +311,28 @@ export class ShapeStim extends util.mix(VisualStim).with(ColorMixin, WindowMixin
|
||||
{
|
||||
// handle flipping:
|
||||
let flip = [1.0, 1.0];
|
||||
if ('_flipHoriz' in this && this._flipHoriz)
|
||||
if ("_flipHoriz" in this && this._flipHoriz)
|
||||
{
|
||||
flip[0] = -1.0;
|
||||
}
|
||||
if ('_flipVert' in this && this._flipVert)
|
||||
if ("_flipVert" in this && this._flipVert)
|
||||
{
|
||||
flip[1] = -1.0;
|
||||
}
|
||||
|
||||
// handle size, flipping, and convert to pixel units:
|
||||
this._vertices_px = this._vertices.map(v => util.to_px(
|
||||
[v[0] * this._size[0] * flip[0], v[1] * this._size[1] * flip[1]],
|
||||
this._units,
|
||||
this._win)
|
||||
this._vertices_px = this._vertices.map((v) =>
|
||||
util.to_px(
|
||||
[v[0] * this._size[0] * flip[0], v[1] * this._size[1] * flip[1]],
|
||||
this._units,
|
||||
this._win,
|
||||
)
|
||||
);
|
||||
|
||||
return this._vertices_px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Known shapes.
|
||||
*
|
||||
@ -358,15 +344,15 @@ ShapeStim.KnownShapes = {
|
||||
[-0.1, +0.5], // up
|
||||
[+0.1, +0.5],
|
||||
[+0.1, +0.1],
|
||||
[+0.5, +0.1], // right
|
||||
[+0.5, +0.1], // right
|
||||
[+0.5, -0.1],
|
||||
[+0.1, -0.1],
|
||||
[+0.1, -0.5], // down
|
||||
[+0.1, -0.5], // down
|
||||
[-0.1, -0.5],
|
||||
[-0.1, -0.1],
|
||||
[-0.5, -0.1], // left
|
||||
[-0.5, -0.1], // left
|
||||
[-0.5, +0.1],
|
||||
[-0.1, +0.1]
|
||||
[-0.1, +0.1],
|
||||
],
|
||||
|
||||
star7: [
|
||||
@ -383,7 +369,6 @@ ShapeStim.KnownShapes = {
|
||||
[-0.49, -0.11],
|
||||
[-0.19, 0.04],
|
||||
[-0.39, 0.31],
|
||||
[-0.09, 0.18]
|
||||
]
|
||||
|
||||
[-0.09, 0.18],
|
||||
],
|
||||
};
|
||||
|
@ -7,17 +7,15 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import {WindowMixin} from '../core/WindowMixin.js';
|
||||
import {Clock} from '../util/Clock.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import {PsychoJS} from "../core/PsychoJS.js";
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { PsychoJS } from "../core/PsychoJS.js";
|
||||
import { WindowMixin } from "../core/WindowMixin.js";
|
||||
import { Clock } from "../util/Clock.js";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* Slider stimulus.
|
||||
@ -70,9 +68,38 @@ import { to_pixiPoint } from "../util/Pixi.js";
|
||||
*/
|
||||
export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
{
|
||||
constructor({name, win, pos, size, ori, units, color, markerColor, lineColor, contrast, opacity, style, ticks, labels, granularity, flip, readOnly, font, bold, italic, fontSize, compact, clipMask, autoDraw, autoLog, dependentStims} = {})
|
||||
constructor(
|
||||
{
|
||||
name,
|
||||
win,
|
||||
pos,
|
||||
size,
|
||||
ori,
|
||||
units,
|
||||
color,
|
||||
markerColor,
|
||||
lineColor,
|
||||
contrast,
|
||||
opacity,
|
||||
style,
|
||||
ticks,
|
||||
labels,
|
||||
granularity,
|
||||
flip,
|
||||
readOnly,
|
||||
font,
|
||||
bold,
|
||||
italic,
|
||||
fontSize,
|
||||
compact,
|
||||
clipMask,
|
||||
autoDraw,
|
||||
autoLog,
|
||||
dependentStims,
|
||||
} = {},
|
||||
)
|
||||
{
|
||||
super({name, win, units, ori, opacity, pos, size, clipMask, autoDraw, autoLog});
|
||||
super({ name, win, units, ori, opacity, pos, size, clipMask, autoDraw, autoLog });
|
||||
|
||||
this._needMarkerUpdate = false;
|
||||
|
||||
@ -96,119 +123,117 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
};
|
||||
|
||||
this._addAttribute(
|
||||
'style',
|
||||
"style",
|
||||
style,
|
||||
[Slider.Style.RATING],
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'ticks',
|
||||
"ticks",
|
||||
ticks,
|
||||
[1, 2, 3, 4, 5],
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'labels',
|
||||
"labels",
|
||||
labels,
|
||||
[],
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'granularity',
|
||||
"granularity",
|
||||
granularity,
|
||||
0,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'readOnly',
|
||||
"readOnly",
|
||||
readOnly,
|
||||
false
|
||||
false,
|
||||
);
|
||||
this._addAttribute(
|
||||
'compact',
|
||||
"compact",
|
||||
compact,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
// font:
|
||||
this._addAttribute(
|
||||
'font',
|
||||
"font",
|
||||
font,
|
||||
'Arial',
|
||||
this._onChange(true, true)
|
||||
"Arial",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'fontSize',
|
||||
"fontSize",
|
||||
fontSize,
|
||||
(this._units === 'pix') ? 14 : 0.03,
|
||||
this._onChange(true, true)
|
||||
(this._units === "pix") ? 14 : 0.03,
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'bold',
|
||||
"bold",
|
||||
bold,
|
||||
true,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'italic',
|
||||
"italic",
|
||||
italic,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flip',
|
||||
"flip",
|
||||
flip,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
// color:
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
color,
|
||||
'lightgray',
|
||||
this._onChange(true, false)
|
||||
"lightgray",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'lineColor',
|
||||
"lineColor",
|
||||
lineColor,
|
||||
'lightgray',
|
||||
this._onChange(true, false)
|
||||
"lightgray",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'markerColor',
|
||||
"markerColor",
|
||||
markerColor,
|
||||
'red',
|
||||
this._onChange(true, false)
|
||||
"red",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
this._addAttribute(
|
||||
'dependentStims',
|
||||
"dependentStims",
|
||||
dependentStims,
|
||||
[],
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
|
||||
|
||||
// slider rating (which might be different from the visible marker rating):
|
||||
this._addAttribute('rating', undefined);
|
||||
this._addAttribute("rating", undefined);
|
||||
|
||||
// visible marker rating (which might be different from the actual rating):
|
||||
this._addAttribute('markerPos', undefined);
|
||||
this._addAttribute("markerPos", undefined);
|
||||
|
||||
// full history of ratings and response times:
|
||||
this._addAttribute('history', []);
|
||||
this._addAttribute("history", []);
|
||||
|
||||
// various graphical components:
|
||||
this._addAttribute('lineAspectRatio', 0.01);
|
||||
this._addAttribute("lineAspectRatio", 0.01);
|
||||
|
||||
// check for attribute conflicts, missing values, etc.:
|
||||
this._sanitizeAttributes();
|
||||
@ -225,8 +250,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Force a refresh of the stimulus.
|
||||
*
|
||||
@ -240,8 +263,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._needMarkerUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reset the slider.
|
||||
*
|
||||
@ -250,7 +271,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
*/
|
||||
reset()
|
||||
{
|
||||
this.psychoJS.logger.debug('reset Slider: ', this._name);
|
||||
this.psychoJS.logger.debug("reset Slider: ", this._name);
|
||||
|
||||
this._markerPos = undefined;
|
||||
this._history = [];
|
||||
@ -262,14 +283,12 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._needUpdate = true;
|
||||
|
||||
// the marker should be invisible when markerPos is undefined:
|
||||
if (typeof this._marker !== 'undefined')
|
||||
if (typeof this._marker !== "undefined")
|
||||
{
|
||||
this._marker.alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the current value of the rating.
|
||||
*
|
||||
@ -290,8 +309,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the response time of the most recent change to the rating.
|
||||
*
|
||||
@ -312,8 +329,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the readOnly attribute.
|
||||
*
|
||||
@ -327,7 +342,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
*/
|
||||
setReadOnly(readOnly = true, log = false)
|
||||
{
|
||||
const hasChanged = this._setAttribute('readOnly', readOnly, log);
|
||||
const hasChanged = this._setAttribute("readOnly", readOnly, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -345,8 +360,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the markerPos attribute.
|
||||
*
|
||||
@ -372,8 +385,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the rating attribute.
|
||||
*
|
||||
@ -393,60 +404,51 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
rating = this._labels[Math.round(rating)];
|
||||
}
|
||||
|
||||
this._setAttribute('rating', rating, log);
|
||||
this._setAttribute("rating", rating, log);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Let `borderColor` alias `lineColor` to parallel PsychoPy */
|
||||
set borderColor(color) {
|
||||
set borderColor(color)
|
||||
{
|
||||
this.lineColor = color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setBorderColor(color) {
|
||||
setBorderColor(color)
|
||||
{
|
||||
this.setLineColor(color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
get borderColor() {
|
||||
get borderColor()
|
||||
{
|
||||
return this.lineColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getBorderColor() {
|
||||
getBorderColor()
|
||||
{
|
||||
return this.getLineColor();
|
||||
}
|
||||
|
||||
|
||||
/** Let `fillColor` alias `markerColor` to parallel PsychoPy */
|
||||
set fillColor(color) {
|
||||
set fillColor(color)
|
||||
{
|
||||
this.markerColor = color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setFillColor(color) {
|
||||
setFillColor(color)
|
||||
{
|
||||
this.setMarkerColor(color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
get fillColor() {
|
||||
get fillColor()
|
||||
{
|
||||
return this.markerColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getFillColor() {
|
||||
getFillColor()
|
||||
{
|
||||
return this.getMarkerColor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -462,18 +464,18 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
{
|
||||
// setup the slider's style (taking into account the Window dimension, etc.):
|
||||
this._setupStyle();
|
||||
|
||||
|
||||
// calculate various values in pixel units:
|
||||
this._tickSize_px = util.to_px(this._tickSize, this._units, this._win);
|
||||
this._fontSize_px = this._getLengthPix(this._fontSize);
|
||||
this._barSize_px = util.to_px(this._barSize, this._units, this._win, true).map(v => Math.max(1, v));
|
||||
this._barSize_px = util.to_px(this._barSize, this._units, this._win, true).map((v) => Math.max(1, v));
|
||||
this._markerSize_px = util.to_px(this._markerSize, this._units, this._win, true);
|
||||
const pos_px = util.to_px(this._pos, this._units, this._win);
|
||||
const size_px = util.to_px(this._size, this._units, this._win);
|
||||
|
||||
// calculate the position of the ticks:
|
||||
const tickPositions = this._ratingToPos(this._ticks);
|
||||
this._tickPositions_px = tickPositions.map(p => util.to_px(p, this._units, this._win));
|
||||
this._tickPositions_px = tickPositions.map((p) => util.to_px(p, this._units, this._win));
|
||||
|
||||
// left, top, right, bottom limits:
|
||||
const limits_px = [0, 0, size_px[0], size_px[1]];
|
||||
@ -490,7 +492,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
|
||||
for (let l = 0; l < this._labels.length; ++l)
|
||||
{
|
||||
const tickPositionIndex = Math.round( l / (this._labels.length - 1) * (this._ticks.length - 1) );
|
||||
const tickPositionIndex = Math.round(l / (this._labels.length - 1) * (this._ticks.length - 1));
|
||||
this._labelPositions_px[l] = this._tickPositions_px[tickPositionIndex];
|
||||
const labelBounds = PIXI.TextMetrics.measureText(this._labels[l].toString(), labelTextStyle);
|
||||
|
||||
@ -515,8 +517,10 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
|
||||
// ensure that that labels are not overlapping:
|
||||
if (prevLabelBounds &&
|
||||
(this._labelPositions_px[l - 1][0] + prevLabelBounds.width + tolerance >= this._labelPositions_px[l][0]))
|
||||
if (
|
||||
prevLabelBounds
|
||||
&& (this._labelPositions_px[l - 1][0] + prevLabelBounds.width + tolerance >= this._labelPositions_px[l][0])
|
||||
)
|
||||
{
|
||||
if (prevNonOverlapOffset === 0)
|
||||
{
|
||||
@ -576,12 +580,10 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._getLengthUnits(position_px.x + limits_px[0]),
|
||||
this._getLengthUnits(position_px.y + limits_px[1]),
|
||||
this._getLengthUnits(limits_px[2] - limits_px[0]),
|
||||
this._getLengthUnits(limits_px[3] - limits_px[1])
|
||||
this._getLengthUnits(limits_px[3] - limits_px[1]),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize the slider attributes: check for attribute conflicts, missing values, etc.
|
||||
*
|
||||
@ -592,9 +594,9 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
_sanitizeAttributes()
|
||||
{
|
||||
// convert potential string styles into Symbols:
|
||||
this._style.forEach( (style, index) =>
|
||||
this._style.forEach((style, index) =>
|
||||
{
|
||||
if (typeof style === 'string')
|
||||
if (typeof style === "string")
|
||||
{
|
||||
this._style[index] = Symbol.for(style.toUpperCase());
|
||||
}
|
||||
@ -606,14 +608,11 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._isCategorical = (this._ticks.length === 0);
|
||||
if (this._isCategorical)
|
||||
{
|
||||
this._ticks = [...Array(this._labels.length)].map( (_, i) => i );
|
||||
this._ticks = [...Array(this._labels.length)].map((_, i) => i);
|
||||
this._granularity = 1.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the current rating.
|
||||
*
|
||||
@ -629,7 +628,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
recordRating(rating, responseTime = undefined, log = false)
|
||||
{
|
||||
// get response time:
|
||||
if (typeof responseTime === 'undefined')
|
||||
if (typeof responseTime === "undefined")
|
||||
{
|
||||
responseTime = this._responseClock.getTime();
|
||||
}
|
||||
@ -640,15 +639,14 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this.setRating(rating, log);
|
||||
|
||||
// add rating and response time to history:
|
||||
this._history.push({rating: this._rating, responseTime});
|
||||
this.psychoJS.logger.debug('record a new rating: ', this._rating, 'with response time: ', responseTime, 'for Slider: ', this._name);
|
||||
this._history.push({ rating: this._rating, responseTime });
|
||||
this.psychoJS.logger.debug("record a new rating: ", this._rating, "with response time: ", responseTime, "for Slider: ", this._name);
|
||||
|
||||
// update slider:
|
||||
this._needMarkerUpdate = true;
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -682,7 +680,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the position of the slider, taking the compactness into account.
|
||||
*
|
||||
@ -693,8 +690,10 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
_getPosition_px()
|
||||
{
|
||||
const position = to_pixiPoint(this.pos, this.units, this.win, true);
|
||||
if (this._compact &&
|
||||
(this._style.indexOf(Slider.Style.RADIO) > -1 || this._style.indexOf(Slider.Style.RATING) > -1))
|
||||
if (
|
||||
this._compact
|
||||
&& (this._style.indexOf(Slider.Style.RADIO) > -1 || this._style.indexOf(Slider.Style.RATING) > -1)
|
||||
)
|
||||
{
|
||||
if (this._isHorizontal())
|
||||
{
|
||||
@ -709,8 +708,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the position of the marker if necessary.
|
||||
*
|
||||
@ -725,9 +722,9 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
this._needMarkerUpdate = false;
|
||||
|
||||
if (typeof this._marker !== 'undefined')
|
||||
if (typeof this._marker !== "undefined")
|
||||
{
|
||||
if (typeof this._markerPos !== 'undefined')
|
||||
if (typeof this._markerPos !== "undefined")
|
||||
{
|
||||
const visibleMarkerPos = this._ratingToPos([this._markerPos]);
|
||||
this._marker.position = to_pixiPoint(visibleMarkerPos[0], this.units, this.win, true);
|
||||
@ -740,8 +737,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the PIXI components of the slider (bar, ticks, labels, marker, etc.).
|
||||
*
|
||||
@ -759,17 +754,15 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
|
||||
this._setupStyle();
|
||||
|
||||
|
||||
// calculate various values in pixel units:
|
||||
this._tickSize_px = util.to_px(this._tickSize, this._units, this._win);
|
||||
this._fontSize_px = this._getLengthPix(this._fontSize);
|
||||
this._barSize_px = util.to_px(this._barSize, this._units, this._win, true).map(v => Math.max(1, v));
|
||||
this._barSize_px = util.to_px(this._barSize, this._units, this._win, true).map((v) => Math.max(1, v));
|
||||
this._markerSize_px = util.to_px(this._markerSize, this._units, this._win, true);
|
||||
const tickPositions = this._ratingToPos(this._ticks);
|
||||
this._tickPositions_px = tickPositions.map(p => util.to_px(p, this._units, this._win));
|
||||
this._tickPositions_px = tickPositions.map((p) => util.to_px(p, this._units, this._win));
|
||||
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
@ -782,7 +775,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._body.interactive = true;
|
||||
this._pixi.addChild(this._body);
|
||||
|
||||
|
||||
// ensure that pointer events will be captured along the slider body, even outside of
|
||||
// marker and labels:
|
||||
if (this._tickType === Slider.Shape.DISC)
|
||||
@ -792,7 +784,8 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
-this._barSize_px[0] / 2 - maxTickSize_px,
|
||||
-this._barSize_px[1] / 2 - maxTickSize_px,
|
||||
this._barSize_px[0] + maxTickSize_px * 2,
|
||||
this._barSize_px[1] + maxTickSize_px * 2);
|
||||
this._barSize_px[1] + maxTickSize_px * 2,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -800,7 +793,8 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
-this._barSize_px[0] / 2 - this._tickSize_px[0] / 2,
|
||||
-this._barSize_px[1] / 2 - this._tickSize_px[1] / 2,
|
||||
this._barSize_px[0] + this._tickSize_px[0],
|
||||
this._barSize_px[1] + this._tickSize_px[1]);
|
||||
this._barSize_px[1] + this._tickSize_px[1],
|
||||
);
|
||||
}
|
||||
|
||||
// central bar:
|
||||
@ -816,8 +810,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._setupMarker();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the central bar.
|
||||
*
|
||||
@ -830,7 +822,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
if (this._barLineWidth_px > 0)
|
||||
{
|
||||
this._body.lineStyle(this._barLineWidth_px, this._barLineColor.int, 1, 0.5);
|
||||
if (typeof this._barFillColor !== 'undefined')
|
||||
if (typeof this._barFillColor !== "undefined")
|
||||
{
|
||||
this._body.beginFill(this._barFillColor.int, 1);
|
||||
}
|
||||
@ -838,17 +830,15 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
Math.round(-this._barSize_px[0] / 2),
|
||||
Math.round(-this._barSize_px[1] / 2),
|
||||
Math.round(this._barSize_px[0]),
|
||||
Math.round(this._barSize_px[1])
|
||||
Math.round(this._barSize_px[1]),
|
||||
);
|
||||
if (typeof this._barFillColor !== 'undefined')
|
||||
if (typeof this._barFillColor !== "undefined")
|
||||
{
|
||||
this._body.endFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the marker, and the associated mouse events.
|
||||
*
|
||||
@ -858,7 +848,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
*/
|
||||
_setupMarker()
|
||||
{
|
||||
/* this is now deprecated and replaced by _body.hitArea
|
||||
/* this is now deprecated and replaced by _body.hitArea
|
||||
// transparent rectangle necessary to capture pointer events outside of marker and labels:
|
||||
const eventCaptureRectangle = new PIXI.Graphics();
|
||||
eventCaptureRectangle.beginFill(0, 0);
|
||||
@ -870,7 +860,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
);
|
||||
eventCaptureRectangle.endFill();
|
||||
this._pixi.addChild(eventCaptureRectangle);
|
||||
*/
|
||||
*/
|
||||
|
||||
// marker:
|
||||
this._marker = new PIXI.Graphics();
|
||||
@ -927,7 +917,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
Math.round(-this._markerSize_px[0] / 2),
|
||||
Math.round(-this._markerSize_px[1] / 2),
|
||||
this._markerSize_px[0],
|
||||
this._markerSize_px[1]
|
||||
this._markerSize_px[1],
|
||||
);
|
||||
this._marker.endFill();
|
||||
|
||||
@ -935,7 +925,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
// this._marker.drawCircle(0, 0, this._markerSize_px[0] / 3);
|
||||
}
|
||||
|
||||
|
||||
// marker mouse events:
|
||||
const self = this;
|
||||
self._markerDragging = false;
|
||||
@ -1001,7 +990,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// (*) slider mouse events outside of marker
|
||||
// note: this only works thanks to eventCaptureRectangle
|
||||
/* not quite right just yet (as of May 2020)
|
||||
@ -1035,8 +1023,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the ticks.
|
||||
*
|
||||
@ -1072,8 +1058,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the PIXI Text Style applied to the PIXI.Text labels.
|
||||
*
|
||||
@ -1084,19 +1068,17 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
_getTextStyle()
|
||||
{
|
||||
this._fontSize_px = this._getLengthPix(this._fontSize);
|
||||
|
||||
|
||||
return new PIXI.TextStyle({
|
||||
fontFamily: this._font,
|
||||
fontSize: Math.round(this._fontSize_px),
|
||||
fontWeight: (this._bold) ? 'bold' : 'normal',
|
||||
fontStyle: (this._italic) ? 'italic' : 'normal',
|
||||
fontWeight: (this._bold) ? "bold" : "normal",
|
||||
fontStyle: (this._italic) ? "italic" : "normal",
|
||||
fill: this.getContrastedColor(this._labelColor, this._contrast).hex,
|
||||
align: 'center',
|
||||
align: "center",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setup the labels.
|
||||
*
|
||||
@ -1121,8 +1103,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Apply a particular style to the slider.
|
||||
*
|
||||
@ -1158,7 +1138,8 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._tickType = Slider.Shape.LINE;
|
||||
this._tickColor = (!skin.TICK_COLOR) ? new Color(this._lineColor) : skin.TICK_COLOR;
|
||||
|
||||
if (this.markerColor === undefined) {
|
||||
if (this.markerColor === undefined)
|
||||
{
|
||||
this.markerColor = skin.MARKER_COLOR;
|
||||
}
|
||||
|
||||
@ -1171,7 +1152,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
|
||||
this._labelOri = 0;
|
||||
|
||||
|
||||
// rating:
|
||||
if (this._style.indexOf(Slider.Style.RATING) > -1)
|
||||
{
|
||||
@ -1184,8 +1164,8 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._markerType = Slider.Shape.TRIANGLE;
|
||||
if (!this._skin.MARKER_SIZE)
|
||||
{
|
||||
this._markerSize = this._markerSize.map(s => s * 2);
|
||||
}
|
||||
this._markerSize = this._markerSize.map((s) => s * 2);
|
||||
}
|
||||
}
|
||||
|
||||
// slider:
|
||||
@ -1194,9 +1174,9 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
this._markerType = Slider.Shape.BOX;
|
||||
if (!this._skin.MARKER_SIZE)
|
||||
{
|
||||
this._markerSize = (this._isHorizontal()) ?
|
||||
[this._size[0] / (this._ticks[this._ticks.length - 1] - this._ticks[0]), this._size[1]] :
|
||||
[this._size[0], this._size[1] / (this._ticks[this._ticks.length - 1] - this._ticks[0])];
|
||||
this._markerSize = (this._isHorizontal())
|
||||
? [this._size[0] / (this._ticks[this._ticks.length - 1] - this._ticks[0]), this._size[1]]
|
||||
: [this._size[0], this._size[1] / (this._ticks[this._ticks.length - 1] - this._ticks[0])];
|
||||
}
|
||||
this._barSize = [this._size[0], this._size[1]];
|
||||
this._barFillColor = this.getContrastedColor(new Color(this.color), 0.5);
|
||||
@ -1235,12 +1215,10 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
|
||||
if (!this._skin.MARKER_SIZE)
|
||||
{
|
||||
this._markerSize = this._markerSize.map(s => s * 0.7);
|
||||
this._markerSize = this._markerSize.map((s) => s * 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert an array of ratings into an array of [x,y] positions (in Slider units, with 0 at the center of the Slider)
|
||||
@ -1260,20 +1238,22 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
// in compact mode the circular markers of RADIO sliders must fit within the width:
|
||||
if (this._compact && this._style.indexOf(Slider.Style.RADIO) > -1)
|
||||
{
|
||||
return ratings.map(v => [
|
||||
((v - this._ticks[0]) / range) * (this._size[0] - this._tickSize[1]*2) -
|
||||
(this._size[0] / 2) + this._tickSize[1],
|
||||
0]);
|
||||
return ratings.map((v) => [
|
||||
((v - this._ticks[0]) / range) * (this._size[0] - this._tickSize[1] * 2)
|
||||
- (this._size[0] / 2) + this._tickSize[1],
|
||||
0,
|
||||
]);
|
||||
}
|
||||
else if (this._style.indexOf(Slider.Style.SLIDER) > -1)
|
||||
{
|
||||
return ratings.map(v => [
|
||||
return ratings.map((v) => [
|
||||
((v - this._ticks[0]) / range - 0.5) * (this._size[0] - this._markerSize[0]),
|
||||
0]);
|
||||
0,
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ratings.map(v => [((v - this._ticks[0]) / range - 0.5) * this._size[0], 0]);
|
||||
return ratings.map((v) => [((v - this._ticks[0]) / range - 0.5) * this._size[0], 0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1281,25 +1261,26 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
// in compact mode the circular markers of RADIO sliders must fit within the height:
|
||||
if (this._compact && this._style.indexOf(Slider.Style.RADIO) > -1)
|
||||
{
|
||||
return ratings.map(v => [0,
|
||||
((v - this._ticks[0]) / range) * (this._size[1] - this._tickSize[0]*2) -
|
||||
(this._size[1] / 2) + this._tickSize[0]]);
|
||||
return ratings.map((v) => [
|
||||
0,
|
||||
((v - this._ticks[0]) / range) * (this._size[1] - this._tickSize[0] * 2)
|
||||
- (this._size[1] / 2) + this._tickSize[0],
|
||||
]);
|
||||
}
|
||||
else if (this._style.indexOf(Slider.Style.SLIDER) > -1)
|
||||
{
|
||||
return ratings.map(v => [
|
||||
return ratings.map((v) => [
|
||||
0,
|
||||
((v - this._ticks[0]) / range - 0.5) * (this._size[1] - this._markerSize[1])]);
|
||||
((v - this._ticks[0]) / range - 0.5) * (this._size[1] - this._markerSize[1]),
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ratings.map(v => [0, (1.0 - (v - this._ticks[0]) / range - 0.5) * this._size[1]]);
|
||||
return ratings.map((v) => [0, (1.0 - (v - this._ticks[0]) / range - 0.5) * this._size[1]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a [x,y] position, in pixel units, relative to the slider, into a rating.
|
||||
*
|
||||
@ -1339,8 +1320,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the slider is horizontal.
|
||||
*
|
||||
@ -1356,8 +1335,6 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
return (this._size[0] > this._size[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the rating once granularity has been taken into account.
|
||||
*
|
||||
@ -1369,7 +1346,7 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
*/
|
||||
_granularise(rating)
|
||||
{
|
||||
if (typeof rating === 'undefined')
|
||||
if (typeof rating === "undefined")
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
@ -1382,10 +1359,8 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
|
||||
return rating;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shape of the marker and of the ticks.
|
||||
*
|
||||
@ -1395,13 +1370,12 @@ export class Slider extends util.mix(VisualStim).with(ColorMixin, WindowMixin)
|
||||
* @public
|
||||
*/
|
||||
Slider.Shape = {
|
||||
DISC: Symbol.for('DISC'),
|
||||
TRIANGLE: Symbol.for('TRIANGLE'),
|
||||
LINE: Symbol.for('LINE'),
|
||||
BOX: Symbol.for('BOX')
|
||||
DISC: Symbol.for("DISC"),
|
||||
TRIANGLE: Symbol.for("TRIANGLE"),
|
||||
LINE: Symbol.for("LINE"),
|
||||
BOX: Symbol.for("BOX"),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Styles.
|
||||
*
|
||||
@ -1411,15 +1385,14 @@ Slider.Shape = {
|
||||
* @public
|
||||
*/
|
||||
Slider.Style = {
|
||||
RATING: Symbol.for('RATING'),
|
||||
TRIANGLE_MARKER: Symbol.for('TRIANGLE_MARKER'),
|
||||
SLIDER: Symbol.for('SLIDER'),
|
||||
WHITE_ON_BLACK: Symbol.for('WHITE_ON_BLACK'),
|
||||
LABELS_45: Symbol.for('LABELS_45'),
|
||||
RADIO: Symbol.for('RADIO')
|
||||
RATING: Symbol.for("RATING"),
|
||||
TRIANGLE_MARKER: Symbol.for("TRIANGLE_MARKER"),
|
||||
SLIDER: Symbol.for("SLIDER"),
|
||||
WHITE_ON_BLACK: Symbol.for("WHITE_ON_BLACK"),
|
||||
LABELS_45: Symbol.for("LABELS_45"),
|
||||
RADIO: Symbol.for("RADIO"),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Skin.
|
||||
*
|
||||
@ -1433,15 +1406,15 @@ Slider.Style = {
|
||||
Slider.Skin = {
|
||||
MARKER_SIZE: null,
|
||||
STANDARD: {
|
||||
MARKER_COLOR: new Color('red'),
|
||||
MARKER_COLOR: new Color("red"),
|
||||
BAR_LINE_COLOR: null,
|
||||
TICK_COLOR: null,
|
||||
LABEL_COLOR: null
|
||||
LABEL_COLOR: null,
|
||||
},
|
||||
WHITE_ON_BLACK: {
|
||||
MARKER_COLOR: new Color('white'),
|
||||
BAR_LINE_COLOR: new Color('black'),
|
||||
TICK_COLOR: new Color('black'),
|
||||
LABEL_COLOR: new Color('black')
|
||||
}
|
||||
MARKER_COLOR: new Color("white"),
|
||||
BAR_LINE_COLOR: new Color("black"),
|
||||
TICK_COLOR: new Color("black"),
|
||||
LABEL_COLOR: new Color("black"),
|
||||
},
|
||||
};
|
||||
|
@ -7,14 +7,13 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import {TextInput} from './TextInput.js';
|
||||
import {ButtonStim} from './ButtonStim.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import * as util from "../util/Util.js";
|
||||
import { ButtonStim } from "./ButtonStim.js";
|
||||
import { TextInput } from "./TextInput.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
// TODO finish documenting all options
|
||||
/**
|
||||
@ -50,122 +49,154 @@ import * as util from '../util/Util.js';
|
||||
*/
|
||||
export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({name, win, pos, anchor, size, units, ori, opacity, depth, text, font, letterHeight, bold, italic, alignment, color, contrast, flipHoriz, flipVert, fillColor, borderColor, borderWidth, padding, editable, multiline, autofocus, clipMask, autoDraw, autoLog} = {})
|
||||
constructor(
|
||||
{
|
||||
name,
|
||||
win,
|
||||
pos,
|
||||
anchor,
|
||||
size,
|
||||
units,
|
||||
ori,
|
||||
opacity,
|
||||
depth,
|
||||
text,
|
||||
font,
|
||||
letterHeight,
|
||||
bold,
|
||||
italic,
|
||||
alignment,
|
||||
color,
|
||||
contrast,
|
||||
flipHoriz,
|
||||
flipVert,
|
||||
fillColor,
|
||||
borderColor,
|
||||
borderWidth,
|
||||
padding,
|
||||
editable,
|
||||
multiline,
|
||||
autofocus,
|
||||
clipMask,
|
||||
autoDraw,
|
||||
autoLog,
|
||||
} = {},
|
||||
)
|
||||
{
|
||||
super({name, win, pos, size, units, ori, opacity, depth, clipMask, autoDraw, autoLog});
|
||||
super({ name, win, pos, size, units, ori, opacity, depth, clipMask, autoDraw, autoLog });
|
||||
|
||||
this._addAttribute(
|
||||
'text',
|
||||
"text",
|
||||
text,
|
||||
'',
|
||||
this._onChange(true, true)
|
||||
"",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'placeholder',
|
||||
"placeholder",
|
||||
text,
|
||||
'',
|
||||
this._onChange(true, true)
|
||||
);
|
||||
"",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'anchor',
|
||||
"anchor",
|
||||
anchor,
|
||||
'center',
|
||||
this._onChange(false, true)
|
||||
"center",
|
||||
this._onChange(false, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipHoriz',
|
||||
"flipHoriz",
|
||||
flipHoriz,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipVert',
|
||||
"flipVert",
|
||||
flipVert,
|
||||
false,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
// font:
|
||||
this._addAttribute(
|
||||
'font',
|
||||
"font",
|
||||
font,
|
||||
'Arial',
|
||||
this._onChange(true, true)
|
||||
"Arial",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'letterHeight',
|
||||
"letterHeight",
|
||||
letterHeight,
|
||||
this._getDefaultLetterHeight(),
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'bold',
|
||||
"bold",
|
||||
bold,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'italic',
|
||||
"italic",
|
||||
italic,
|
||||
false,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'alignment',
|
||||
"alignment",
|
||||
alignment,
|
||||
'left',
|
||||
this._onChange(true, true)
|
||||
"left",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
// colors:
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
color,
|
||||
'white',
|
||||
this._onChange(true, false)
|
||||
"white",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'fillColor',
|
||||
"fillColor",
|
||||
fillColor,
|
||||
'lightgrey',
|
||||
this._onChange(true, false)
|
||||
"lightgrey",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'borderColor',
|
||||
"borderColor",
|
||||
borderColor,
|
||||
this.fillColor,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
// default border width: 1px
|
||||
this._addAttribute(
|
||||
'borderWidth',
|
||||
"borderWidth",
|
||||
borderWidth,
|
||||
util.to_unit([1, 0], 'pix', win, this._units)[0],
|
||||
this._onChange(true, true)
|
||||
util.to_unit([1, 0], "pix", win, this._units)[0],
|
||||
this._onChange(true, true),
|
||||
);
|
||||
// default padding: half of the letter height
|
||||
this._addAttribute(
|
||||
'padding',
|
||||
"padding",
|
||||
padding,
|
||||
this._letterHeight / 2.0,
|
||||
this._onChange(true, true)
|
||||
this._onChange(true, true),
|
||||
);
|
||||
|
||||
this._addAttribute('multiline', multiline, false, this._onChange(true, true));
|
||||
this._addAttribute('editable', editable, false, this._onChange(true, true));
|
||||
this._addAttribute('autofocus', autofocus, true, this._onChange(true, false));
|
||||
// this._setAttribute({
|
||||
// name: 'vertices',
|
||||
// value: vertices,
|
||||
// assert: v => (v != null) && (typeof v !== 'undefined') && Array.isArray(v) )
|
||||
// log);
|
||||
this._addAttribute("multiline", multiline, false, this._onChange(true, true));
|
||||
this._addAttribute("editable", editable, false, this._onChange(true, true));
|
||||
this._addAttribute("autofocus", autofocus, true, this._onChange(true, false));
|
||||
// this._setAttribute({
|
||||
// name: 'vertices',
|
||||
// value: vertices,
|
||||
// assert: v => (v != null) && (typeof v !== 'undefined') && Array.isArray(v) )
|
||||
// log);
|
||||
|
||||
// estimate the bounding box:
|
||||
this._estimateBoundingBox();
|
||||
@ -176,7 +207,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the current text value or sets it back to match the placeholder.
|
||||
*
|
||||
@ -185,13 +215,11 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
reset()
|
||||
{
|
||||
const text = this.editable ? '' : this.placeholder;
|
||||
const text = this.editable ? "" : this.placeholder;
|
||||
|
||||
this.setText(this.placeholder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Clears the current text value.
|
||||
*
|
||||
@ -203,8 +231,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
this.setText();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* For tweaking the underlying input value.
|
||||
*
|
||||
@ -212,9 +238,9 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
* @public
|
||||
* @param {string} text
|
||||
*/
|
||||
setText(text = '')
|
||||
setText(text = "")
|
||||
{
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.text = text;
|
||||
}
|
||||
@ -222,7 +248,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._text = text;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For accessing the underlying input value.
|
||||
*
|
||||
@ -232,7 +257,7 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
getText()
|
||||
{
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
return this._pixi.text;
|
||||
}
|
||||
@ -240,7 +265,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
return this._text;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the size attribute.
|
||||
*
|
||||
@ -253,25 +277,25 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
// test with the size is undefined, or [undefined, undefined]:
|
||||
let isSizeUndefined = (
|
||||
(typeof size === 'undefined') || (size === null) ||
|
||||
( Array.isArray(size) && size.every( v => typeof v === 'undefined' || v === null) )
|
||||
);
|
||||
(typeof size === "undefined") || (size === null)
|
||||
|| (Array.isArray(size) && size.every((v) => typeof v === "undefined" || v === null))
|
||||
);
|
||||
|
||||
if (isSizeUndefined)
|
||||
{
|
||||
size = TextBox._defaultSizeMap.get(this._units);
|
||||
|
||||
if (typeof size === 'undefined')
|
||||
if (typeof size === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'TextBox.setSize',
|
||||
context: 'when setting the size of TextBox: ' + this._name,
|
||||
error: 'no default size for unit: ' + this._units
|
||||
origin: "TextBox.setSize",
|
||||
context: "when setting the size of TextBox: " + this._name,
|
||||
error: "no default size for unit: " + this._units,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const hasChanged = this._setAttribute('size', size, log);
|
||||
const hasChanged = this._setAttribute("size", size, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -283,8 +307,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the default letter height given the stimulus' units.
|
||||
*
|
||||
@ -296,20 +318,18 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
const height = TextBox._defaultLetterHeightMap.get(this._units);
|
||||
|
||||
if (typeof height === 'undefined')
|
||||
if (typeof height === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'TextBox._getDefaultLetterHeight',
|
||||
context: 'when getting the default height of TextBox: ' + this._name,
|
||||
error: 'no default letter height for unit: ' + this._units
|
||||
origin: "TextBox._getDefaultLetterHeight",
|
||||
context: "when getting the default height of TextBox: " + this._name,
|
||||
error: "no default letter height for unit: " + this._units,
|
||||
};
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the TextInput options applied to the PIXI.TextInput.
|
||||
*
|
||||
@ -328,24 +348,24 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
return {
|
||||
input: {
|
||||
fontFamily: this._font,
|
||||
fontSize: letterHeight_px + 'px',
|
||||
fontSize: letterHeight_px + "px",
|
||||
color: new Color(this._color).hex,
|
||||
fontWeight: (this._bold) ? 'bold' : 'normal',
|
||||
fontStyle: (this._italic) ? 'italic' : 'normal',
|
||||
fontWeight: (this._bold) ? "bold" : "normal",
|
||||
fontStyle: (this._italic) ? "italic" : "normal",
|
||||
|
||||
padding: padding_px + 'px',
|
||||
padding: padding_px + "px",
|
||||
multiline,
|
||||
text: this._text,
|
||||
height: multiline ? (height_px - 2 * padding_px) + 'px' : undefined,
|
||||
width: (width_px - 2 * padding_px) + 'px'
|
||||
height: multiline ? (height_px - 2 * padding_px) + "px" : undefined,
|
||||
width: (width_px - 2 * padding_px) + "px",
|
||||
},
|
||||
box: {
|
||||
fill: new Color(this._fillColor).int,
|
||||
rounded: 5,
|
||||
stroke: {
|
||||
color: new Color(this._borderColor).int,
|
||||
width: borderWidth_px
|
||||
}
|
||||
width: borderWidth_px,
|
||||
},
|
||||
/*default: {
|
||||
fill: new Color(this._fillColor).int,
|
||||
rounded: 5,
|
||||
@ -370,12 +390,10 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
width: borderWidth_px
|
||||
}
|
||||
}*/
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -395,14 +413,12 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pos[0] - anchor[0] * this._size[0],
|
||||
this._pos[1] - anchor[1] * boxHeight,
|
||||
this._size[0],
|
||||
boxHeight
|
||||
boxHeight,
|
||||
);
|
||||
|
||||
// TODO take the orientation into account
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -424,13 +440,13 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
this._needPixiUpdate = false;
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
// Get the currently entered text
|
||||
let enteredText = this._pixi !== undefined? this._pixi.text: '';
|
||||
// Create new TextInput
|
||||
let enteredText = this._pixi !== undefined ? this._pixi.text : "";
|
||||
// Create new TextInput
|
||||
this._pixi = new TextInput(this._getTextInputOptions());
|
||||
|
||||
// listeners required for regular textboxes, but may cause problems with button stimuli
|
||||
@ -441,7 +457,7 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
// check if other TextBox instances are already in focus
|
||||
const { _drawList = [] } = this.psychoJS.window;
|
||||
const otherTextBoxWithFocus = _drawList.some(item => item instanceof TextBox && item._pixi && item._pixi._hasFocus());
|
||||
const otherTextBoxWithFocus = _drawList.some((item) => item instanceof TextBox && item._pixi && item._pixi._hasFocus());
|
||||
if (this._autofocus && !otherTextBoxWithFocus)
|
||||
{
|
||||
this._pixi._onSurrogateFocus();
|
||||
@ -452,7 +468,7 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
if (this._editable)
|
||||
{
|
||||
this.text = enteredText;
|
||||
this.text = enteredText;
|
||||
this._pixi.placeholder = this._placeholder;
|
||||
}
|
||||
else
|
||||
@ -479,8 +495,6 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pixi.mask = this._clipMask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert the anchor attribute into numerical values.
|
||||
*
|
||||
@ -493,30 +507,27 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
const anchor = [0.5, 0.5];
|
||||
|
||||
if (this._anchor.indexOf('left') > -1)
|
||||
if (this._anchor.indexOf("left") > -1)
|
||||
{
|
||||
anchor[0] = 0;
|
||||
}
|
||||
else if (this._anchor.indexOf('right') > -1)
|
||||
else if (this._anchor.indexOf("right") > -1)
|
||||
{
|
||||
anchor[0] = 1;
|
||||
}
|
||||
if (this._anchor.indexOf('top') > -1)
|
||||
if (this._anchor.indexOf("top") > -1)
|
||||
{
|
||||
anchor[1] = 0;
|
||||
}
|
||||
else if (this._anchor.indexOf('bottom') > -1)
|
||||
else if (this._anchor.indexOf("bottom") > -1)
|
||||
{
|
||||
anchor[1] = 1;
|
||||
}
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>This map associates units to default letter height.</p>
|
||||
*
|
||||
@ -525,18 +536,17 @@ export class TextBox extends util.mix(VisualStim).with(ColorMixin)
|
||||
* @private
|
||||
*/
|
||||
TextBox._defaultLetterHeightMap = new Map([
|
||||
['cm', 1.0],
|
||||
['deg', 1.0],
|
||||
['degs', 1.0],
|
||||
['degFlatPos', 1.0],
|
||||
['degFlat', 1.0],
|
||||
['norm', 0.1],
|
||||
['height', 0.2],
|
||||
['pix', 20],
|
||||
['pixels', 20]
|
||||
["cm", 1.0],
|
||||
["deg", 1.0],
|
||||
["degs", 1.0],
|
||||
["degFlatPos", 1.0],
|
||||
["degFlat", 1.0],
|
||||
["norm", 0.1],
|
||||
["height", 0.2],
|
||||
["pix", 20],
|
||||
["pixels", 20],
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* <p>This map associates units to default sizes.</p>
|
||||
*
|
||||
@ -545,13 +555,13 @@ TextBox._defaultLetterHeightMap = new Map([
|
||||
* @private
|
||||
*/
|
||||
TextBox._defaultSizeMap = new Map([
|
||||
['cm', [15.0, -1]],
|
||||
['deg', [15.0, -1]],
|
||||
['degs', [15.0, -1]],
|
||||
['degFlatPos', [15.0, -1]],
|
||||
['degFlat', [15.0, -1]],
|
||||
['norm', [1, -1]],
|
||||
['height', [1, -1]],
|
||||
['pix', [500, -1]],
|
||||
['pixels', [500, -1]]
|
||||
["cm", [15.0, -1]],
|
||||
["deg", [15.0, -1]],
|
||||
["degs", [15.0, -1]],
|
||||
["degFlatPos", [15.0, -1]],
|
||||
["degFlat", [15.0, -1]],
|
||||
["norm", [1, -1]],
|
||||
["height", [1, -1]],
|
||||
["pix", [500, -1]],
|
||||
["pixels", [500, -1]],
|
||||
]);
|
||||
|
@ -24,7 +24,7 @@ export class TextInput extends PIXI.Container
|
||||
outline: "none",
|
||||
text: "",
|
||||
transformOrigin: "0 0",
|
||||
lineHeight: "1"
|
||||
lineHeight: "1",
|
||||
},
|
||||
styles.input,
|
||||
);
|
||||
@ -58,7 +58,7 @@ export class TextInput extends PIXI.Container
|
||||
this._restrict_value = "";
|
||||
this._createDOMInput();
|
||||
this.substituteText = !this._multiline;
|
||||
this._setState('DEFAULT');
|
||||
this._setState("DEFAULT");
|
||||
}
|
||||
|
||||
// GETTERS & SETTERS
|
||||
@ -638,7 +638,7 @@ export class TextInput extends PIXI.Container
|
||||
}
|
||||
else if (components.length == 4)
|
||||
{
|
||||
let padding = components.map(component =>
|
||||
let padding = components.map((component) =>
|
||||
{
|
||||
return parseFloat(component);
|
||||
});
|
||||
|
@ -7,14 +7,12 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {VisualStim} from './VisualStim.js';
|
||||
import {Color} from '../util/Color.js';
|
||||
import {ColorMixin} from '../util/ColorMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { Color } from "../util/Color.js";
|
||||
import { ColorMixin } from "../util/ColorMixin.js";
|
||||
import { to_pixiPoint } from "../util/Pixi.js";
|
||||
|
||||
import * as util from "../util/Util.js";
|
||||
import { VisualStim } from "./VisualStim.js";
|
||||
|
||||
/**
|
||||
* @name module:visual.TextStim
|
||||
@ -49,9 +47,34 @@ import { to_pixiPoint } from "../util/Pixi.js";
|
||||
*/
|
||||
export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({name, win, text, font, pos, color, opacity, depth, contrast, units, ori, height, bold, italic, alignHoriz, alignVert, wrapWidth, flipHoriz, flipVert, clipMask, autoDraw, autoLog} = {})
|
||||
constructor(
|
||||
{
|
||||
name,
|
||||
win,
|
||||
text,
|
||||
font,
|
||||
pos,
|
||||
color,
|
||||
opacity,
|
||||
depth,
|
||||
contrast,
|
||||
units,
|
||||
ori,
|
||||
height,
|
||||
bold,
|
||||
italic,
|
||||
alignHoriz,
|
||||
alignVert,
|
||||
wrapWidth,
|
||||
flipHoriz,
|
||||
flipVert,
|
||||
clipMask,
|
||||
autoDraw,
|
||||
autoLog,
|
||||
} = {},
|
||||
)
|
||||
{
|
||||
super({name, win, units, ori, opacity, depth, pos, clipMask, autoDraw, autoLog});
|
||||
super({ name, win, units, ori, opacity, depth, pos, clipMask, autoDraw, autoLog });
|
||||
|
||||
// callback to deal with text metrics invalidation:
|
||||
const onChange = (withPixi = false, withBoundingBox = false, withMetrics = false) =>
|
||||
@ -69,81 +92,80 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
// text and font:
|
||||
this._addAttribute(
|
||||
'text',
|
||||
"text",
|
||||
text,
|
||||
'Hello World',
|
||||
onChange(true, true, true)
|
||||
"Hello World",
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'alignHoriz',
|
||||
"alignHoriz",
|
||||
alignHoriz,
|
||||
'center',
|
||||
onChange(true, true, true)
|
||||
"center",
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'alignVert',
|
||||
"alignVert",
|
||||
alignVert,
|
||||
'center',
|
||||
onChange(true, true, true)
|
||||
"center",
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipHoriz',
|
||||
"flipHoriz",
|
||||
flipHoriz,
|
||||
false,
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'flipVert',
|
||||
"flipVert",
|
||||
flipVert,
|
||||
false,
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'font',
|
||||
"font",
|
||||
font,
|
||||
'Arial',
|
||||
this._onChange(true, true)
|
||||
"Arial",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'height',
|
||||
"height",
|
||||
height,
|
||||
this._getDefaultLetterHeight(),
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'wrapWidth',
|
||||
"wrapWidth",
|
||||
wrapWidth,
|
||||
this._getDefaultWrapWidth(),
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'bold',
|
||||
"bold",
|
||||
bold,
|
||||
false,
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'italic',
|
||||
"italic",
|
||||
italic,
|
||||
false,
|
||||
onChange(true, true, true)
|
||||
onChange(true, true, true),
|
||||
);
|
||||
|
||||
// color:
|
||||
this._addAttribute(
|
||||
'color',
|
||||
"color",
|
||||
color,
|
||||
'white',
|
||||
this._onChange(true, false)
|
||||
"white",
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'contrast',
|
||||
"contrast",
|
||||
contrast,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
|
||||
|
||||
// estimate the bounding box (using TextMetrics):
|
||||
this._estimateBoundingBox();
|
||||
|
||||
@ -153,8 +175,6 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the metrics estimated for the text and style.
|
||||
*
|
||||
@ -166,7 +186,7 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
*/
|
||||
getTextMetrics()
|
||||
{
|
||||
if (typeof this._textMetrics === 'undefined')
|
||||
if (typeof this._textMetrics === "undefined")
|
||||
{
|
||||
this._textMetrics = PIXI.TextMetrics.measureText(this._text, this._getTextStyle());
|
||||
}
|
||||
@ -174,8 +194,6 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
return this._textMetrics;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the default letter height given the stimulus' units.
|
||||
*
|
||||
@ -187,20 +205,18 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
const height = TextStim._defaultLetterHeightMap.get(this._units);
|
||||
|
||||
if (typeof height === 'undefined')
|
||||
if (typeof height === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'TextStim._getDefaultLetterHeight',
|
||||
context: 'when getting the default height of TextStim: ' + this._name,
|
||||
error: 'no default letter height for unit: ' + this._units
|
||||
origin: "TextStim._getDefaultLetterHeight",
|
||||
context: "when getting the default height of TextStim: " + this._name,
|
||||
error: "no default letter height for unit: " + this._units,
|
||||
};
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the default wrap width given the stimulus' units.
|
||||
*
|
||||
@ -212,20 +228,18 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
const wrapWidth = TextStim._defaultWrapWidthMap.get(this._units);
|
||||
|
||||
if (typeof wrapWidth === 'undefined')
|
||||
if (typeof wrapWidth === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'TextStim._getDefaultWrapWidth',
|
||||
context: 'when getting the default wrap width of TextStim: ' + this._name,
|
||||
error: 'no default wrap width for unit: ' + this._units
|
||||
origin: "TextStim._getDefaultWrapWidth",
|
||||
context: "when getting the default wrap width of TextStim: " + this._name,
|
||||
error: "no default wrap width for unit: " + this._units,
|
||||
};
|
||||
}
|
||||
|
||||
return wrapWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -238,11 +252,11 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
// size of the text, irrespective of the orientation:
|
||||
const textMetrics = this.getTextMetrics();
|
||||
const textSize = util.to_unit(
|
||||
const textSize = util.to_unit(
|
||||
[textMetrics.width, textMetrics.height],
|
||||
'pix',
|
||||
"pix",
|
||||
this._win,
|
||||
this._units
|
||||
this._units,
|
||||
);
|
||||
|
||||
// take the alignment into account:
|
||||
@ -251,14 +265,12 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pos[0] - anchor[0] * textSize[0],
|
||||
this._pos[1] - anchor[1] * textSize[1],
|
||||
textSize[0],
|
||||
textSize[1]
|
||||
textSize[1],
|
||||
);
|
||||
|
||||
// TODO take the orientation into account
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the PIXI Text Style applied to the PIXI.Text
|
||||
*
|
||||
@ -270,17 +282,15 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
return new PIXI.TextStyle({
|
||||
fontFamily: this._font,
|
||||
fontSize: Math.round(this._getLengthPix(this._height)),
|
||||
fontWeight: (this._bold) ? 'bold' : 'normal',
|
||||
fontStyle: (this._italic) ? 'italic' : 'normal',
|
||||
fontWeight: (this._bold) ? "bold" : "normal",
|
||||
fontStyle: (this._italic) ? "italic" : "normal",
|
||||
fill: this.getContrastedColor(new Color(this._color), this._contrast).hex,
|
||||
align: this._alignHoriz,
|
||||
wordWrap: (typeof this._wrapWidth !== 'undefined'),
|
||||
wordWrapWidth: (typeof this._wrapWidth !== 'undefined') ? this._getHorLengthPix(this._wrapWidth) : 0
|
||||
wordWrap: (typeof this._wrapWidth !== "undefined"),
|
||||
wordWrapWidth: (typeof this._wrapWidth !== "undefined") ? this._getHorLengthPix(this._wrapWidth) : 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
@ -301,7 +311,7 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
{
|
||||
this._needPixiUpdate = false;
|
||||
|
||||
if (typeof this._pixi !== 'undefined')
|
||||
if (typeof this._pixi !== "undefined")
|
||||
{
|
||||
this._pixi.destroy(true);
|
||||
}
|
||||
@ -326,7 +336,7 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
// update the size attributes:
|
||||
this._size = [
|
||||
this._getLengthUnits(Math.abs(this._pixi.width)),
|
||||
this._getLengthUnits(Math.abs(this._pixi.height))
|
||||
this._getLengthUnits(Math.abs(this._pixi.height)),
|
||||
];
|
||||
|
||||
// refine the estimate of the bounding box:
|
||||
@ -334,12 +344,10 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
this._pos[0] - anchor[0] * this._size[0],
|
||||
this._pos[1] - anchor[1] * this._size[1],
|
||||
this._size[0],
|
||||
this._size[1]
|
||||
this._size[1],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert the alignment attributes into an anchor.
|
||||
*
|
||||
@ -354,36 +362,33 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
|
||||
switch (this._alignHoriz)
|
||||
{
|
||||
case 'left':
|
||||
case "left":
|
||||
anchor.push(0);
|
||||
break;
|
||||
case 'right':
|
||||
case "right":
|
||||
anchor.push(1);
|
||||
break;
|
||||
default:
|
||||
case 'center':
|
||||
case "center":
|
||||
anchor.push(0.5);
|
||||
}
|
||||
switch (this._alignVert)
|
||||
{
|
||||
case 'top':
|
||||
case "top":
|
||||
anchor.push(0);
|
||||
break;
|
||||
case 'bottom':
|
||||
case "bottom":
|
||||
anchor.push(1);
|
||||
break;
|
||||
default:
|
||||
case 'center':
|
||||
case "center":
|
||||
anchor.push(0.5);
|
||||
}
|
||||
|
||||
return anchor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p>This map associates units to default letter height.</p>
|
||||
*
|
||||
@ -392,19 +397,17 @@ export class TextStim extends util.mix(VisualStim).with(ColorMixin)
|
||||
* @private
|
||||
*/
|
||||
TextStim._defaultLetterHeightMap = new Map([
|
||||
['cm', 1.0],
|
||||
['deg', 1.0],
|
||||
['degs', 1.0],
|
||||
['degFlatPos', 1.0],
|
||||
['degFlat', 1.0],
|
||||
['norm', 0.1],
|
||||
['height', 0.2],
|
||||
['pix', 20],
|
||||
['pixels', 20]
|
||||
["cm", 1.0],
|
||||
["deg", 1.0],
|
||||
["degs", 1.0],
|
||||
["degFlatPos", 1.0],
|
||||
["degFlat", 1.0],
|
||||
["norm", 0.1],
|
||||
["height", 0.2],
|
||||
["pix", 20],
|
||||
["pixels", 20],
|
||||
]);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <p>This map associates units to default wrap width.</p>
|
||||
*
|
||||
@ -413,13 +416,13 @@ TextStim._defaultLetterHeightMap = new Map([
|
||||
* @private
|
||||
*/
|
||||
TextStim._defaultWrapWidthMap = new Map([
|
||||
['cm', 15.0],
|
||||
['deg', 15.0],
|
||||
['degs', 15.0],
|
||||
['degFlatPos', 15.0],
|
||||
['degFlat', 15.0],
|
||||
['norm', 1],
|
||||
['height', 1],
|
||||
['pix', 500],
|
||||
['pixels', 500]
|
||||
["cm", 15.0],
|
||||
["deg", 15.0],
|
||||
["degs", 15.0],
|
||||
["degFlatPos", 15.0],
|
||||
["degFlat", 15.0],
|
||||
["norm", 1],
|
||||
["height", 1],
|
||||
["pix", 500],
|
||||
["pixels", 500],
|
||||
]);
|
||||
|
@ -7,12 +7,10 @@
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import * as PIXI from 'pixi.js-legacy';
|
||||
import {MinimalStim} from '../core/MinimalStim.js';
|
||||
import {WindowMixin} from '../core/WindowMixin.js';
|
||||
import * as util from '../util/Util.js';
|
||||
|
||||
import * as PIXI from "pixi.js-legacy";
|
||||
import { MinimalStim } from "../core/MinimalStim.js";
|
||||
import { WindowMixin } from "../core/WindowMixin.js";
|
||||
import * as util from "../util/Util.js";
|
||||
|
||||
/**
|
||||
* Base class for all visual stimuli.
|
||||
@ -36,55 +34,54 @@ import * as util from '../util/Util.js';
|
||||
*/
|
||||
export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
{
|
||||
constructor({name, win, units, ori, opacity, depth, pos, size, clipMask, autoDraw, autoLog} = {})
|
||||
constructor({ name, win, units, ori, opacity, depth, pos, size, clipMask, autoDraw, autoLog } = {})
|
||||
{
|
||||
super({win, name, autoDraw, autoLog});
|
||||
super({ win, name, autoDraw, autoLog });
|
||||
|
||||
this._addAttribute(
|
||||
'units',
|
||||
"units",
|
||||
units,
|
||||
(typeof win !== 'undefined' && win !== null) ? win.units : 'height',
|
||||
this._onChange(true, true)
|
||||
(typeof win !== "undefined" && win !== null) ? win.units : "height",
|
||||
this._onChange(true, true),
|
||||
);
|
||||
this._addAttribute(
|
||||
'pos',
|
||||
"pos",
|
||||
pos,
|
||||
[0, 0]
|
||||
[0, 0],
|
||||
);
|
||||
this._addAttribute(
|
||||
'size',
|
||||
"size",
|
||||
size,
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
this._addAttribute(
|
||||
'ori',
|
||||
"ori",
|
||||
ori,
|
||||
0.0
|
||||
0.0,
|
||||
);
|
||||
this._addAttribute(
|
||||
'opacity',
|
||||
"opacity",
|
||||
opacity,
|
||||
1.0,
|
||||
this._onChange(true, false)
|
||||
this._onChange(true, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'depth',
|
||||
"depth",
|
||||
depth,
|
||||
0,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
this._addAttribute(
|
||||
'clipMask',
|
||||
"clipMask",
|
||||
clipMask,
|
||||
null,
|
||||
this._onChange(false, false)
|
||||
this._onChange(false, false),
|
||||
);
|
||||
|
||||
// bounding box of the stimulus, in stimulus units
|
||||
// note: boundingBox does not take the orientation into account
|
||||
this._addAttribute('boundingBox', PIXI.Rectangle.EMPTY);
|
||||
this._addAttribute("boundingBox", PIXI.Rectangle.EMPTY);
|
||||
|
||||
|
||||
// the stimulus need to be updated:
|
||||
this._needUpdate = true;
|
||||
|
||||
@ -92,8 +89,6 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
this._needPixiUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Force a refresh of the stimulus.
|
||||
*
|
||||
@ -107,8 +102,6 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
this._onChange(true, true)();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the size attribute.
|
||||
*
|
||||
@ -120,7 +113,7 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
setSize(size, log = false)
|
||||
{
|
||||
// size is either undefined, null, or a tuple of numbers:
|
||||
if (typeof size !== 'undefined' && size !== null)
|
||||
if (typeof size !== "undefined" && size !== null)
|
||||
{
|
||||
size = util.toNumerical(size);
|
||||
if (!Array.isArray(size))
|
||||
@ -129,7 +122,7 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
const hasChanged = this._setAttribute('size', size, log);
|
||||
const hasChanged = this._setAttribute("size", size, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
@ -137,8 +130,6 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the orientation attribute.
|
||||
*
|
||||
@ -149,20 +140,17 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
*/
|
||||
setOri(ori, log = false)
|
||||
{
|
||||
const hasChanged = this._setAttribute('ori', ori, log);
|
||||
const hasChanged = this._setAttribute("ori", ori, log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
let radians = -ori * 0.017453292519943295;
|
||||
this._rotationMatrix = [[Math.cos(radians), -Math.sin(radians)],
|
||||
[Math.sin(radians), Math.cos(radians)]];
|
||||
this._rotationMatrix = [[Math.cos(radians), -Math.sin(radians)], [Math.sin(radians), Math.cos(radians)]];
|
||||
|
||||
this._onChange(true, true)();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the position attribute.
|
||||
*
|
||||
@ -174,20 +162,18 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
setPos(pos, log = false)
|
||||
{
|
||||
const prevPos = this._pos;
|
||||
const hasChanged = this._setAttribute('pos', util.toNumerical(pos), log);
|
||||
const hasChanged = this._setAttribute("pos", util.toNumerical(pos), log);
|
||||
|
||||
if (hasChanged)
|
||||
{
|
||||
this._needUpdate = true;
|
||||
|
||||
|
||||
// update the bounding box, without calling _estimateBoundingBox:
|
||||
this._boundingBox.x += this._pos[0] - prevPos[0];
|
||||
this._boundingBox.y += this._pos[1] - prevPos[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether an object is inside the bounding box of the stimulus.
|
||||
*
|
||||
@ -202,12 +188,12 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
// get the position of the object, in pixel coordinates:
|
||||
const objectPos_px = util.getPositionFromObject(object, units);
|
||||
|
||||
if (typeof objectPos_px === 'undefined')
|
||||
if (typeof objectPos_px === "undefined")
|
||||
{
|
||||
throw {
|
||||
origin: 'VisualStim.contains',
|
||||
context: 'when determining whether VisualStim: ' + this._name + ' contains object: ' + util.toString(object),
|
||||
error: 'unable to determine the position of the object'
|
||||
origin: "VisualStim.contains",
|
||||
context: "when determining whether VisualStim: " + this._name + " contains object: " + util.toString(object),
|
||||
error: "unable to determine the position of the object",
|
||||
};
|
||||
}
|
||||
|
||||
@ -215,8 +201,6 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
return this._getBoundingBox_px().contains(objectPos_px[0], objectPos_px[1]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Estimate the bounding box.
|
||||
*
|
||||
@ -227,14 +211,12 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
_estimateBoundingBox()
|
||||
{
|
||||
throw {
|
||||
origin: 'VisualStim._estimateBoundingBox',
|
||||
origin: "VisualStim._estimateBoundingBox",
|
||||
context: `when estimating the bounding box of visual stimulus: ${this._name}`,
|
||||
error: 'this method is abstract and should not be called.'
|
||||
error: "this method is abstract and should not be called.",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the bounding box in pixel coordinates
|
||||
*
|
||||
@ -245,37 +227,35 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
*/
|
||||
_getBoundingBox_px()
|
||||
{
|
||||
if (this._units === 'pix')
|
||||
if (this._units === "pix")
|
||||
{
|
||||
return this._boundingBox.clone();
|
||||
}
|
||||
else if (this._units === 'norm')
|
||||
else if (this._units === "norm")
|
||||
{
|
||||
return new PIXI.Rectangle(
|
||||
this._boundingBox.x * this._win.size[0] / 2,
|
||||
this._boundingBox.y * this._win.size[1] / 2,
|
||||
this._boundingBox.width * this._win.size[0] / 2,
|
||||
this._boundingBox.height * this._win.size[1] / 2
|
||||
this._boundingBox.height * this._win.size[1] / 2,
|
||||
);
|
||||
}
|
||||
else if (this._units === 'height')
|
||||
else if (this._units === "height")
|
||||
{
|
||||
const minSize = Math.min(this._win.size[0], this._win.size[1]);
|
||||
return new PIXI.Rectangle(
|
||||
this._boundingBox.x * minSize,
|
||||
this._boundingBox.y * minSize,
|
||||
this._boundingBox.width * minSize,
|
||||
this._boundingBox.height * minSize
|
||||
this._boundingBox.height * minSize,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Object.assign(response, {error: `unknown units: ${this._units}`});
|
||||
throw Object.assign(response, { error: `unknown units: ${this._units}` });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a callback that prepares updates to the stimulus.
|
||||
* This is typically called in the constructor of a stimulus, when attributes are added with _addAttribute.
|
||||
@ -302,5 +282,4 @@ export class VisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
export * from './ButtonStim.js';
|
||||
export * from './Form.js';
|
||||
export * from './ImageStim.js';
|
||||
export * from './MovieStim.js';
|
||||
export * from './Polygon.js';
|
||||
export * from './Rect.js';
|
||||
export * from './ShapeStim.js';
|
||||
export * from './Slider.js';
|
||||
export * from './TextBox.js';
|
||||
export * from './TextInput.js';
|
||||
export * from './TextStim.js';
|
||||
export * from './VisualStim.js';
|
||||
export * from "./ButtonStim.js";
|
||||
export * from "./Form.js";
|
||||
export * from "./ImageStim.js";
|
||||
export * from "./MovieStim.js";
|
||||
export * from "./Polygon.js";
|
||||
export * from "./Rect.js";
|
||||
export * from "./ShapeStim.js";
|
||||
export * from "./Slider.js";
|
||||
export * from "./TextBox.js";
|
||||
export * from "./TextInput.js";
|
||||
export * from "./TextStim.js";
|
||||
export * from "./VisualStim.js";
|
||||
|
Loading…
Reference in New Issue
Block a user