1
0
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:
Sotiri Bakagiannis 2021-07-09 14:07:04 +01:00
parent 61fb7744a1
commit c9cb3c8412
13 changed files with 917 additions and 1002 deletions

View File

@ -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]);
}
}

View File

@ -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",
};

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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],
]);
}
}

View File

@ -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],
],
};

View File

@ -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"),
},
};

View File

@ -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]],
]);

View File

@ -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);
});

View File

@ -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],
]);

View File

@ -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)
}
};
}
}

View File

@ -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";