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