mirror of
https://github.com/psychopy/psychojs.git
synced 2025-05-10 10:40:54 +00:00
fully documented the visual module; various bug fixes
This commit is contained in:
parent
cc9a4202e9
commit
14390697f1
@ -50,7 +50,7 @@ We are constantly adding new Components and are regularly updating this list.
|
||||
|
||||
## Authors
|
||||
|
||||
The PsychoJs library is written and maintained by Ilixa Ltd. (http://www.ilixa.com). The PsychoPy Builder's javascript code generator is built and maintained by the creators of PsychoPy, at the University of Nottingham (https://www.nottingham.ac.uk). Both efforts are generously supported by the Wellcome Trust (https://wellcome.ac.uk).
|
||||
The PsychoJs library is written and maintained by Ilixa Ltd. (http://www.ilixa.com). The PsychoPy Builder's javascript code generator is built and maintained by the creators of PsychoPy at the University of Nottingham (https://www.nottingham.ac.uk). Both efforts are generously supported by the Wellcome Trust (https://wellcome.ac.uk).
|
||||
|
||||
|
||||
## License
|
||||
|
@ -44,7 +44,7 @@ export class MinimalStim extends PsychObject {
|
||||
|
||||
|
||||
/**
|
||||
* Setter for autoDraw attribute.
|
||||
* Setter for the autoDraw attribute.
|
||||
*
|
||||
* @name module:core.MinimalStim#setAutoDraw
|
||||
* @function
|
||||
|
@ -433,7 +433,8 @@ export class ServerManager extends PsychObject {
|
||||
// error: we throw an exception
|
||||
this._resourceQueue.addEventListener("error", event => {
|
||||
self.setStatus(ServerManager.Status.ERROR);
|
||||
throw { ...response, error: 'unable to download resource: ' + event.data.id + ' (' + event.title + ')' };
|
||||
const resourceId = (typeof event.data !== 'undefined')?event.data.id:'UNKNOWN RESOURCE';
|
||||
throw { ...response, error: 'unable to download resource: ' + resourceId + ' (' + event.title + ')' };
|
||||
});
|
||||
|
||||
|
||||
@ -458,7 +459,14 @@ export class ServerManager extends PsychObject {
|
||||
|
||||
|
||||
// (*) start loading non-sound resources:
|
||||
this._resourceQueue.loadManifest(manifest);
|
||||
if (manifest.length > 0)
|
||||
this._resourceQueue.loadManifest(manifest);
|
||||
else {
|
||||
if (this._nbLoadedResources == this._nbResources) {
|
||||
this.setStatus(ServerManager.Status.READY);
|
||||
this.emit(ServerManager.Event.RESOURCE, { message: ServerManager.Event.DOWNLOAD_COMPLETED });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// (*) prepare and start loading sound resources:
|
||||
|
@ -104,7 +104,6 @@ export class ExperimentHandler extends PsychObject {
|
||||
/**
|
||||
* Add the key/value pair.
|
||||
*
|
||||
* <p> This method is typically called by a {@link TrialHandler}. </p>
|
||||
* <p> Multiple key/value pairs can be added to any given entry of the data file. There are
|
||||
* considered part of the same entry until a call to {@link nextEntry} is made. </p>
|
||||
*
|
||||
@ -133,15 +132,15 @@ export class ExperimentHandler extends PsychObject {
|
||||
*/
|
||||
nextEntry() {
|
||||
// fetch data from each (potentially-nested) loop:
|
||||
for (const loop of this._unfinishedLoops) {
|
||||
for (let loop of this._unfinishedLoops) {
|
||||
var attributes = this.getLoopAttributes(loop);
|
||||
for (const a in attributes)
|
||||
for (let a in attributes)
|
||||
if (attributes.hasOwnProperty(a))
|
||||
this._currentTrialData[a] = attributes[a];
|
||||
}
|
||||
|
||||
// add the extraInfo dict to the data:
|
||||
for (const a in this.extraInfo)
|
||||
for (let a in this.extraInfo)
|
||||
if (this.extraInfo.hasOwnProperty(a))
|
||||
this._currentTrialData[a] = this.extraInfo[a];
|
||||
|
||||
@ -177,22 +176,22 @@ export class ExperimentHandler extends PsychObject {
|
||||
|
||||
// data is in the csv format:
|
||||
// build the csv header:
|
||||
var csv = "";
|
||||
var header = this._trialsKeys;
|
||||
for (var l = 0; l < this._loops.length; l++) {
|
||||
var loop = this._loops[l];
|
||||
let csv = "";
|
||||
let header = this._trialsKeys.slice();
|
||||
for (let l = 0; l < this._loops.length; l++) {
|
||||
const loop = this._loops[l];
|
||||
|
||||
var loopAttributes = this.getLoopAttributes(loop);
|
||||
for (var a in loopAttributes)
|
||||
const loopAttributes = this.getLoopAttributes(loop);
|
||||
for (let a in loopAttributes)
|
||||
if (loopAttributes.hasOwnProperty(a))
|
||||
header.push(a);
|
||||
}
|
||||
for (var a in this.extraInfo) {
|
||||
for (let a in this.extraInfo) {
|
||||
if (this.extraInfo.hasOwnProperty(a))
|
||||
header.push(a);
|
||||
}
|
||||
|
||||
for (var h = 0; h < header.length; h++) {
|
||||
for (let h = 0; h < header.length; h++) {
|
||||
if (h > 0)
|
||||
csv = csv + ', ';
|
||||
csv = csv + header[h];
|
||||
@ -200,8 +199,8 @@ export class ExperimentHandler extends PsychObject {
|
||||
csv = csv + '\n';
|
||||
|
||||
// build the records:
|
||||
for (var r = 0; r < this._trialsData.length; r++) {
|
||||
for (var h = 0; h < header.length; h++) {
|
||||
for (let r = 0; r < this._trialsData.length; r++) {
|
||||
for (let h = 0; h < header.length; h++) {
|
||||
if (h > 0)
|
||||
csv = csv + ', ';
|
||||
csv = csv + this._trialsData[r][header[h]];
|
||||
|
@ -1,6 +1,6 @@
|
||||
/** @module sound */
|
||||
/**
|
||||
* @file Sound stimulus
|
||||
* @file Sound stimulus.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
|
239
js/visual/BaseShapeStim.js
Normal file
239
js/visual/BaseShapeStim.js
Normal file
@ -0,0 +1,239 @@
|
||||
/** @module visual */
|
||||
/**
|
||||
* @file Basic Shape Stimulus.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
* @copyright (c) 2018 Ilixa Ltd. ({@link http://ilixa.com})
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import { BaseVisualStim } from './BaseVisualStim';
|
||||
import { Color } from '../util/Color';
|
||||
import { ColorMixin } from '../util/ColorMixin';
|
||||
import * as util from '../util/Util';
|
||||
|
||||
|
||||
/**
|
||||
* <p>This class provides the basic functionalities of shape stimuli.</p>
|
||||
*
|
||||
* @class
|
||||
* @extends BaseVisualStim
|
||||
* @mixes ColorMixin
|
||||
* @param {Object} options
|
||||
* @param {String} options.name - the name used when logging messages from this stimulus
|
||||
* @param {Window} options.win - the associated Window
|
||||
* @param {number} options.lineWidth - the line width
|
||||
* @param {Color} [options.lineColor= Color('white')] the line color
|
||||
* @param {Color} options.fillColor - the fill color
|
||||
* @param {number} [options.opacity= 1.0] - the opacity
|
||||
* @param {Array.<Array.<number>>} [options.vertices= [[-0.5, 0], [0, 0.5], [0.5, 0]]] - the shape vertices
|
||||
* @param {boolean} [options.closeShape= true] - whether or not the shape is closed
|
||||
* @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the shape
|
||||
* @param {number} [options.size= 1.0] - the size
|
||||
* @param {number} [options.ori= 0.0] - the orientation (in degrees)
|
||||
* @param {string} options.units - the units of the stimulus vertices, size and position
|
||||
* @param {number} [options.contrast= 1.0] - the contrast
|
||||
* @param {number} [options.depth= 0] - the depth
|
||||
* @param {boolean} [options.interpolate= true] - whether or not the shape is interpolated
|
||||
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
|
||||
* @param {boolean} [options.autoLog= false] - whether or not to log
|
||||
*/
|
||||
export class BaseShapeStim extends util.mix(BaseVisualStim).with(ColorMixin)
|
||||
{
|
||||
/**
|
||||
* @constructor
|
||||
* @public
|
||||
*/
|
||||
constructor({
|
||||
name,
|
||||
win,
|
||||
lineWidth = 1.5,
|
||||
lineColor = new Color('white'),
|
||||
fillColor,
|
||||
opacity = 1.0,
|
||||
vertices = [[-0.5, 0], [0, 0.5], [0.5, 0]],
|
||||
closeShape = true,
|
||||
pos = [0, 0],
|
||||
size = 1.0,
|
||||
ori = 0.0,
|
||||
units,
|
||||
contrast = 1.0,
|
||||
depth = 0,
|
||||
interpolate = true,
|
||||
autoDraw,
|
||||
autoLog
|
||||
} = {}) {
|
||||
super({ name, win, units, ori, opacity, pos, size, autoDraw, autoLog });
|
||||
|
||||
// the PIXI polygon corresponding to the vertices, in pixel units:
|
||||
this._pixiPolygon_px = undefined;
|
||||
|
||||
this._addAttributes(BaseShapeStim, lineWidth, lineColor, fillColor, vertices, closeShape, contrast, depth, interpolate);
|
||||
|
||||
/*if (autoLog)
|
||||
logging.exp("Created %s = %s" % (self.name, str(self)));*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the line width attribute.
|
||||
*
|
||||
* @public
|
||||
* @param {number} lineWidth - the line width
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setLineWidth(lineWidth, log = false) {
|
||||
this._setAttribute('lineWidth', lineWidth, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the line color attribute.
|
||||
*
|
||||
* @public
|
||||
* @param {Color} lineColor - the line color
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setLineColor(lineColor, log = false) {
|
||||
this._setAttribute('lineColor', lineColor, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the fill color attribute.
|
||||
*
|
||||
* @public
|
||||
* @param {Color} fillColor - the fill color
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setFillColor(fillColor, log = false) {
|
||||
this._setAttribute('fillColor', fillColor, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the vertices attribute.
|
||||
*
|
||||
* @public
|
||||
* @param {Array.<Array.<number>>} vertices - the vertices
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setVertices(vertices, log = false) {
|
||||
this._psychoJS.logger.debug('set the vertices of BaseShapeStim:', this.name);
|
||||
|
||||
this._setAttribute('vertices', vertices, log);
|
||||
/*this._setAttribute({
|
||||
name: 'vertices',
|
||||
value: vertices,
|
||||
assert: v => (v != null) && (typeof v !== 'undefined') && Array.isArray(v) )
|
||||
log);
|
||||
*/
|
||||
|
||||
this._needVertexUpdate = true;
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether this stimulus contains the given object.
|
||||
*
|
||||
* @public
|
||||
* @param {Object} object - the object
|
||||
* @param {string} units - the units
|
||||
* @return {boolean} whether or not the stimulus contains the object
|
||||
*/
|
||||
contains(object, units) {
|
||||
this._psychoJS.logger.debug('test whether BaseShameStim:', this.name, 'contains object: ', ('name' in object) ? object.name : object);
|
||||
|
||||
// get position of object:
|
||||
const objectPos_px = util.getPositionFromObject(object, units);
|
||||
if (typeof objectPos_px === 'undefined')
|
||||
throw { origin : 'BaseShapeStim.contains', context : 'when determining whether BaseShameStim: ' + this._name + ' contains object: ' + util.toString(object), error : 'unable to determine the position of the object' };
|
||||
|
||||
// test for inclusion
|
||||
// note: the vertices are centered around (0, 0) so we need to add to them the stimulus' position
|
||||
const pos_px = util.to_px(this.pos, this.units, this.win);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_updateIfNeeded() {
|
||||
if (!this._needUpdate)
|
||||
return;
|
||||
this._needUpdate = false;
|
||||
|
||||
this._getPolygon(/*true*/); // this also updates _vertices_px
|
||||
|
||||
this._pixi = undefined;
|
||||
|
||||
// no polygon to draw: return immediately
|
||||
if (typeof this._pixiPolygon_px === 'undefined')
|
||||
return;
|
||||
|
||||
// prepare the polygon in the given color and opacity:
|
||||
this._pixi = new PIXI.Graphics();
|
||||
this._pixi.lineStyle(this._lineWidth, this._lineColor.int, this._opacity, 0.5);
|
||||
if (typeof this._fillColor !== 'undefined')
|
||||
this._pixi.beginFill(this._fillColor.int, this._opacity);
|
||||
this._pixi.drawPolygon(this._pixiPolygon_px);
|
||||
if (typeof this._fillColor !== 'undefined')
|
||||
this._pixi.endFill();
|
||||
|
||||
// set polygon position and rotation:
|
||||
this._pixi.position = util.to_pixiPoint(this.pos, this.units, this.win);
|
||||
this._pixi.rotation = this.ori * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the PIXI polygon (in pixel units) corresponding to the vertices.
|
||||
*
|
||||
* @private
|
||||
* @return {Object} the PIXI polygon corresponding to this stimulus vertices.
|
||||
*/
|
||||
_getPolygon(/*force = false*/) {
|
||||
if (!this._needVertexUpdate)
|
||||
return;
|
||||
this._needVertexUpdate = false;
|
||||
|
||||
//if (!force && typeof this._pixiPolygon_px !== 'undefined')
|
||||
// return this._pixiPolygon_px;
|
||||
|
||||
// make sure the vertices in pixel units are available, and flatten the array of arrays:
|
||||
this._getVertices_px(/*force*/);
|
||||
let coords_px = [];
|
||||
for (const vertex_px of this._vertices_px)
|
||||
coords_px.push.apply(coords_px, vertex_px);
|
||||
|
||||
// close the polygon if need be:
|
||||
if (coords_px.length >= 6 && this._closeShape) {
|
||||
// note: we first check whether the vertices already define a closed polygon:
|
||||
const n = coords_px.length;
|
||||
if (coords_px[0] != coords_px[n - 2] || coords_px[1] != coords_px[n - 1]) {
|
||||
coords_px.push(coords_px[0]);
|
||||
coords_px.push(coords_px[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// create the PIXI polygon:
|
||||
this._pixiPolygon_px = new PIXI.Polygon(coords_px);
|
||||
return this._pixiPolygon_px;
|
||||
}
|
||||
|
||||
|
||||
}
|
163
js/visual/BaseVisualStim.js
Normal file
163
js/visual/BaseVisualStim.js
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @file Base class for all visual stimuli.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
* @copyright (c) 2018 Ilixa Ltd. ({@link http://ilixa.com})
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import {MinimalStim} from '../core/MinimalStim';
|
||||
import {WindowMixin} from '../core/WindowMixin';
|
||||
import * as util from '../util/Util';
|
||||
|
||||
|
||||
/**
|
||||
* Base class for all visual stimuli.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim
|
||||
* @class
|
||||
* @extends MinimalStim
|
||||
* @mixes WindowMixin
|
||||
* @param {Object} options
|
||||
* @param {String} options.name - the name used when logging messages from this stimulus
|
||||
* @param {Window} options.win - the associated Window
|
||||
* @param {string} [options.units= "norm"] - the units of the stimulus (e.g. for size, position, vertices)
|
||||
* @param {number} [options.ori= 0.0] - the orientation (in degrees)
|
||||
* @param {number} [options.opacity= 1.0] - the opacity
|
||||
* @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the stimulus
|
||||
* @param {number} [options.size= 1.0] - the size
|
||||
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
|
||||
* @param {boolean} [options.autoLog= false] - whether or not to log
|
||||
*/
|
||||
export class BaseVisualStim extends util.mix(MinimalStim).with(WindowMixin)
|
||||
{
|
||||
constructor({
|
||||
name,
|
||||
win,
|
||||
units = 'norm',
|
||||
ori = 0.0,
|
||||
opacity = 1.0,
|
||||
pos = [0, 0],
|
||||
size,
|
||||
autoDraw,
|
||||
autoLog = false
|
||||
} = {})
|
||||
{
|
||||
super({win, name, autoDraw, autoLog});
|
||||
|
||||
// whether the vertices need to be updated:
|
||||
this._needVertexUpdate = true;
|
||||
// the vertices (in pixel units):
|
||||
this._vertices_px = undefined;
|
||||
|
||||
this._addAttributes(BaseVisualStim, units, ori, opacity, pos, size);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the size attribute.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim#setSize
|
||||
* @public
|
||||
* @param {number} size - the stimulus size
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setSize(size, log = false)
|
||||
{
|
||||
// size is either undefined or a tuple of numbers:
|
||||
if (typeof size !== 'undefined') {
|
||||
size = util.toNumerical(size);
|
||||
if (!Array.isArray(size))
|
||||
size = [size, size];
|
||||
}
|
||||
|
||||
this._setAttribute('size', size, log);
|
||||
|
||||
this._needVertexUpdate = true;
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the orientation attribute.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim#setOri
|
||||
* @public
|
||||
* @param {number} ori - the orientation in degree with 0 as the vertical position, positive values rotate clockwise.
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setOri(ori, log = false)
|
||||
{
|
||||
this._setAttribute('ori', ori, log);
|
||||
|
||||
let radians = ori * 0.017453292519943295;
|
||||
this._rotationMatrix = [[Math.cos(radians), -Math.sin(radians)],
|
||||
[Math.sin(radians), Math.cos(radians)]];
|
||||
|
||||
//this._needVertexUpdate = true ; // need to update update vertices
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the position attribute.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim#setPos
|
||||
* @public
|
||||
* @param {Array.<number>} pos - position of the center of the stimulus, in stimulus units
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setPos(pos, log = false)
|
||||
{
|
||||
this._setAttribute('pos', util.toNumerical(pos), log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the opacity attribute.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim#setOpacity
|
||||
* @public
|
||||
* @param {number} opacity - the opacity: 0 is completely transparent, 1 is fully opaque
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setOpacity(opacity, log = false)
|
||||
{
|
||||
this._setAttribute('opacity', opacity, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get the vertices in pixel units.
|
||||
*
|
||||
* @name module:visual.BaseVisualStim#_getVertices_px
|
||||
* @private
|
||||
* @return {Array.<[number, number]>} the vertices
|
||||
*/
|
||||
_getVertices_px(/*force = false*/)
|
||||
{
|
||||
/*if (!force && typeof this._vertices_px !== 'undefined')
|
||||
return this._vertices_px;*/
|
||||
|
||||
// handle flipping:
|
||||
let flip = [1.0, 1.0];
|
||||
if ('_flipHoriz' in this && this._flipHoriz)
|
||||
flip[0] = -1.0;
|
||||
if ('_flipVert' in this && this._flipVert)
|
||||
flip[1] = -1.0;
|
||||
|
||||
// handle size, flipping, and convert to pixel units:
|
||||
this._vertices_px = this._vertices.map( v => util.to_px([v[0] * this._size[0] * flip[0], v[1] * this._size[1] * flip[1]], this._units, this._win) );
|
||||
|
||||
return this._vertices_px;
|
||||
}
|
||||
|
||||
}
|
281
js/visual/ImageStim.js
Normal file
281
js/visual/ImageStim.js
Normal file
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* @file Image Stimulus.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
* @copyright (c) 2018 Ilixa Ltd. ({@link http://ilixa.com})
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import { BaseVisualStim } from './BaseVisualStim';
|
||||
import { Color } from '../util/Color';
|
||||
import { ColorMixin } from '../util/ColorMixin';
|
||||
import * as util from '../util/Util';
|
||||
|
||||
|
||||
/**
|
||||
* Image Simulus.
|
||||
*
|
||||
* @name module:visual.ImageStim
|
||||
* @class
|
||||
* @extends BaseVisualStim
|
||||
* @mixes ColorMixin
|
||||
* @param {Object} options
|
||||
* @param {String} options.name - the name used when logging messages from this stimulus
|
||||
* @param {Window} options.win - the associated Window
|
||||
* @param {string | HTMLImageElement} options.image - the name of the image resource or HTMLImageElement corresponding to the image
|
||||
* @param {string | HTMLImageElement} options.mask - the name of the mask resource or HTMLImageElement corresponding to the mask
|
||||
* @param {string} [options.units= "norm"] - the units of the stimulus (e.g. for size, position, vertices)
|
||||
* @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the stimulus
|
||||
* @param {string} options.units - the units of the stimulus vertices, size and position
|
||||
* @param {number} options.ori - the orientation (in degrees)
|
||||
* @param {number} options.size - the size
|
||||
* @param {Color} [options.color= Color('white')] the background color
|
||||
* @param {number} [options.opacity= 1.0] - the opacity
|
||||
* @param {number} [options.contrast= 1.0] - the contrast
|
||||
* @param {number} [options.depth= 0] - the depth
|
||||
* @param {number} [options.texRes= 128] - the resolution of the text
|
||||
* @param {boolean} [options.interpolate= false] - whether or not the image is interpolated
|
||||
* @param {boolean} [flipHoriz= false] - whether or not to flip horizontally
|
||||
* @param {boolean} [flipVert= false] - whether or not to flip vertically
|
||||
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
|
||||
* @param {boolean} [options.autoLog= false] - whether or not to log
|
||||
*/
|
||||
export class ImageStim extends util.mix(BaseVisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({
|
||||
name,
|
||||
win,
|
||||
image,
|
||||
mask,
|
||||
pos,
|
||||
units,
|
||||
ori,
|
||||
size,
|
||||
color = new Color('white'),
|
||||
opacity = 1.0,
|
||||
contrast = 1.0,
|
||||
texRes = 128,
|
||||
depth = 0,
|
||||
interpolate = false,
|
||||
flipHoriz = false,
|
||||
flipVert = false,
|
||||
autoDraw,
|
||||
autoLog
|
||||
} = {}) {
|
||||
super({ name, win, units, ori, opacity, pos, size, autoDraw, autoLog });
|
||||
|
||||
this.psychoJS.logger.debug('create a new ImageStim with name: ', name);
|
||||
|
||||
this._addAttributes(ImageStim, image, mask, color, contrast, texRes, interpolate, depth, flipHoriz, flipVert);
|
||||
|
||||
/*if (autoLog)
|
||||
logging.exp("Created %s = %s" % (self.name, str(self)));*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the image attribute.
|
||||
*
|
||||
* @name module:visual.ImageStim#setImage
|
||||
* @public
|
||||
* @param {HTMLImageElement | string} image - the name of the image resource or HTMLImageElement corresponding to the image
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setImage(image, log = false) {
|
||||
let response = { origin: 'ImageStim.setImage', context: 'when setting the image of ImageStim: ' + this._name };
|
||||
|
||||
try {
|
||||
// image is undefined: that's fine but we raise a warning in case this is a sympton of an actual problem
|
||||
if (typeof image === 'undefined') {
|
||||
this.psychoJS.logger.warn('setting the image of ImageStim: ' + this._name + ' with argument: undefined.');
|
||||
this.psychoJS.logger.debug('set the image of ImageStim: ' + this._name + ' as: undefined');
|
||||
}
|
||||
else {
|
||||
// image is a string: it should be the name of a resource, which we load
|
||||
if (typeof image === 'string')
|
||||
image = this.psychoJS.serverManager.getResource(image);
|
||||
|
||||
// image should now be an actual HTMLImageElement: we raise an error if it is not
|
||||
if (!(image instanceof HTMLImageElement))
|
||||
throw 'the argument: ' + image.toString() + ' is not an image" }';
|
||||
|
||||
this.psychoJS.logger.debug('set the image of ImageStim: ' + this._name + ' as: src= ' + image.src + ', size= ' + image.width + 'x' + image.height);
|
||||
}
|
||||
|
||||
this._setAttribute('image', image, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
catch (error) {
|
||||
throw { ...response, error };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the mask attribute.
|
||||
*
|
||||
* @name module:visual.ImageStim#setImage
|
||||
* @public
|
||||
* @param {HTMLImageElement | string} mask - the name of the mask resource or HTMLImageElement corresponding to the mask
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setMask(mask, log = false) {
|
||||
let response = { origin: 'ImageStim.setMask', context: 'when setting the mask of ImageStim: ' + this._name };
|
||||
|
||||
try {
|
||||
// mask is undefined: that's fine but we raise a warning in case this is a sympton of an actual problem
|
||||
if (typeof mask === 'undefined') {
|
||||
this.psychoJS.logger.warn('setting the mask of ImageStim: ' + this._name + ' with argument: undefined.');
|
||||
this.psychoJS.logger.debug('set the mask of ImageStim: ' + this._name + ' as: undefined');
|
||||
}
|
||||
else {
|
||||
// mask is a string: it should be the name of a resource, which we load
|
||||
if (typeof mask === 'string')
|
||||
mask = this.psychoJS.serverManager.getResource(mask);
|
||||
|
||||
// mask should now be an actual HTMLImageElement: we raise an error if it is not
|
||||
if (!(mask instanceof HTMLImageElement))
|
||||
throw 'the argument: ' + mask.toString() + ' is not an image" }';
|
||||
|
||||
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._needUpdate = true;
|
||||
}
|
||||
catch (error) {
|
||||
throw { ...response, error };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the flipVert attribute.
|
||||
*
|
||||
* @name module:visual.ImageStim#setFlipVert
|
||||
* @public
|
||||
* @param {boolean} flipVert - whether or not to flip vertically
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setFlipVert(flipVert, log = false) {
|
||||
this._setAttribute('flipVert', flipVert, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the flipHoriz attribute.
|
||||
*
|
||||
* @name module:visual.ImageStim#setFlipHoriz
|
||||
* @public
|
||||
* @param {boolean} flipHoriz - whether or not to flip horizontally
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setFlipHoriz(flipHoriz, log = false) {
|
||||
this._setAttribute('flipHoriz', flipHoriz, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given object is inside this image.
|
||||
*
|
||||
* @name module:visual.ImageStim#contains
|
||||
* @public
|
||||
* @param {Object} object - the object
|
||||
* @param {string} units - the units
|
||||
* @return {boolean} whether or not the image contains the object
|
||||
*/
|
||||
contains(object, units) {
|
||||
// get position of object:
|
||||
let objectPos_px = util.getPositionFromObject(object, units);
|
||||
if (typeof objectPos_px === 'undefined')
|
||||
throw { origin : 'ImageStim.contains', context : 'when determining whether ImageStim: ' + this._name + ' contains object: ' + util.toString(object), error : 'unable to determine the position of the object' };
|
||||
|
||||
// test for inclusion:
|
||||
// note: since _pixi.anchor is [0.5, 0.5] the image is actually centered on pos
|
||||
let pos_px = util.to_px(this.pos, this.units, this._win);
|
||||
let size_px = util.to_px(this.size, this.units, this._win);
|
||||
const polygon_px = [
|
||||
[pos_px[0] - size_px[0] / 2, pos_px[1] - size_px[1] / 2],
|
||||
[pos_px[0] + size_px[0] / 2, pos_px[1] - size_px[1] / 2],
|
||||
[pos_px[0] + size_px[0] / 2, pos_px[1] + size_px[1] / 2],
|
||||
[pos_px[0] - size_px[0] / 2, pos_px[1] + size_px[1] / 2]];
|
||||
|
||||
return util.IsPointInsidePolygon(objectPos_px, polygon_px);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
* @name module:visual.ImageStim#_updateIfNeeded
|
||||
* @private
|
||||
*/
|
||||
_updateIfNeeded() {
|
||||
if (!this._needUpdate)
|
||||
return;
|
||||
this._needUpdate = false;
|
||||
|
||||
this._pixi = undefined;
|
||||
|
||||
// no image to draw: return immediately
|
||||
if (typeof this._image === 'undefined')
|
||||
return;
|
||||
|
||||
// prepare the image:
|
||||
this._texture = new PIXI.Texture(new PIXI.BaseTexture(this._image));
|
||||
//this._texture = new PIXI.Texture(PIXI.BaseTexture.fromImage(this._image));
|
||||
this._pixi = new PIXI.Sprite(this._texture);
|
||||
this._pixi.zOrder = this.depth;
|
||||
|
||||
// add a mask if need be:
|
||||
if (typeof this._mask !== 'undefined') {
|
||||
this._maskTexture = new PIXI.Texture(new PIXI.BaseTexture(this._mask));
|
||||
this._pixi.mask = new PIXI.Sprite(this._maskTexture); //PIXI.Sprite.fromImage(this._mask);
|
||||
|
||||
// the following is required for the mask to be aligned with the image
|
||||
this._pixi.mask.anchor.x = 0.5;
|
||||
this._pixi.mask.anchor.y = 0.5;
|
||||
this._pixi.addChild(this._pixi.mask);
|
||||
}
|
||||
|
||||
// since _texture.width may not be immedialy available but the rest of the code needs its value
|
||||
// we arrange for repeated calls to _updateIfNeeded until we have a width:
|
||||
if (this._texture.width == 0) {
|
||||
this._needUpdate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this._pixi.alpha = this.opacity;
|
||||
|
||||
// stimulus size:
|
||||
// note: we use the size of the texture if ImageStim has no specified size:
|
||||
let stimSize = this.size;
|
||||
if (typeof stimSize === 'undefined') {
|
||||
const textureSize = [this._texture.width, this._texture.height];
|
||||
stimSize = util.to_unit(textureSize, 'pix', this.win, this.units);
|
||||
}
|
||||
|
||||
// set the scale:
|
||||
const size_px = util.to_px(stimSize, this.units, this.win);
|
||||
var scaleX = size_px[0] / this._texture.width;
|
||||
var scaleY = size_px[1] / this._texture.height;
|
||||
this._pixi.scale.x = this.flipHoriz ? -scaleX : scaleX;
|
||||
this._pixi.scale.y = this.flipVert ? scaleY : -scaleY;
|
||||
|
||||
this._pixi.position = util.to_pixiPoint(this.pos, this.units, this.win);
|
||||
this._pixi.rotation = this.ori * Math.PI / 180;
|
||||
// the image is centered on pos:
|
||||
this._pixi.anchor.x = 0.5;
|
||||
this._pixi.anchor.y = 0.5;
|
||||
}
|
||||
|
||||
|
||||
}
|
122
js/visual/Rect.js
Normal file
122
js/visual/Rect.js
Normal file
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file Rectangular Stimulus.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
* @copyright (c) 2018 Ilixa Ltd. ({@link http://ilixa.com})
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import { BaseShapeStim } from './BaseShapeStim';
|
||||
import { Color } from '../util/Color';
|
||||
|
||||
|
||||
/**
|
||||
* <p>Rectangular visual stimulus.</p>
|
||||
*
|
||||
* @name module:visual.Rect
|
||||
* @class
|
||||
* @extends BaseShapeStim
|
||||
* @param {Object} options
|
||||
* @param {String} options.name - the name used when logging messages from this stimulus
|
||||
* @param {Window} options.win - the associated Window
|
||||
* @param {number} [options.lineWidth= 1.5] - the line width
|
||||
* @param {Color} [options.lineColor= Color('white')] the line color
|
||||
* @param {Color} options.fillColor - the fill color
|
||||
* @param {number} [options.opacity= 1.0] - the opacity
|
||||
* @param {number} [options.width= 0.5] - the width of the rectangle
|
||||
* @param {number} [options.height= 0.5] - the height of the rectangle
|
||||
* @param {Array.<number>} [options.pos= [0, 0]] - the position
|
||||
* @param {number} [options.size= 1.0] - the size
|
||||
* @param {number} [options.ori= 0.0] - the orientation (in degrees)
|
||||
* @param {string} options.units - the units of the stimulus vertices, size and position
|
||||
* @param {number} [options.contrast= 1.0] - the contrast
|
||||
* @param {number} [options.depth= 0] - the depth
|
||||
* @param {boolean} [options.interpolate= true] - whether or not the shape is interpolated
|
||||
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
|
||||
* @param {boolean} [options.autoLog= false] - whether or not to log
|
||||
*/
|
||||
export class Rect extends BaseShapeStim {
|
||||
constructor({
|
||||
name,
|
||||
win,
|
||||
lineWidth = 1.5,
|
||||
lineColor = new Color('white'),
|
||||
fillColor,
|
||||
opacity = 1.0,
|
||||
width = 0.5,
|
||||
height = 0.5,
|
||||
pos = [0, 0],
|
||||
size = 1.0,
|
||||
ori = 0.0,
|
||||
units,
|
||||
contrast = 1.0,
|
||||
depth = 0,
|
||||
interpolate = true,
|
||||
autoDraw,
|
||||
autoLog
|
||||
} = {}) {
|
||||
super({ name, win, lineWidth, lineColor, fillColor, opacity, pos, ori, size, units, contrast, depth, interpolate, autoDraw, autoLog });
|
||||
|
||||
this._psychoJS.logger.debug('create a new Rect with name: ', name);
|
||||
|
||||
this._addAttributes(Rect, width, height);
|
||||
|
||||
this._updateVertices();
|
||||
|
||||
/*if (autoLog)
|
||||
logging.exp("Created %s = %s" % (self.name, str(self)));*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the width attribute.
|
||||
*
|
||||
* @name module:visual.Rect#setWidth
|
||||
* @public
|
||||
* @param {number} width - the rectange width
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setWidth(width, log = false) {
|
||||
this._psychoJS.logger.debug('set the width of Rect: ', this.name, 'to: ', width);
|
||||
|
||||
this._setAttribute('width', width, log);
|
||||
this._updateVertices();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the height attribute.
|
||||
*
|
||||
* @name module:visual.Rect#setHeight
|
||||
* @public
|
||||
* @param {number} height - the rectange height
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setHeight(height, log = false) {
|
||||
this._psychoJS.logger.debug('set the height of Rect: ', this.name, 'to: ', height);
|
||||
|
||||
this._setAttribute('height', height, log);
|
||||
this._updateVertices();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the base shape vertices.
|
||||
*
|
||||
* @name module:visual.Rect#_updateVertices
|
||||
* @private
|
||||
*/
|
||||
_updateVertices() {
|
||||
this._psychoJS.logger.debug('update the vertices of Rect: ', this.name);
|
||||
|
||||
this.setVertices([
|
||||
[-this._width / 2.0, -this._height / 2.0],
|
||||
[this._width / 2.0, -this._height / 2.0],
|
||||
[this._width / 2.0, this._height / 2.0],
|
||||
[-this._width / 2.0, this._height / 2.0]
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
276
js/visual/TextStim.js
Normal file
276
js/visual/TextStim.js
Normal file
@ -0,0 +1,276 @@
|
||||
/**
|
||||
* @file Text Stimulus.
|
||||
*
|
||||
* @author Alain Pitiot
|
||||
* @version 3.0.0b11
|
||||
* @copyright (c) 2018 Ilixa Ltd. ({@link http://ilixa.com})
|
||||
* @license Distributed under the terms of the MIT License
|
||||
*/
|
||||
|
||||
|
||||
import { BaseVisualStim } from './BaseVisualStim';
|
||||
import { Color } from '../util/Color';
|
||||
import { ColorMixin } from '../util/ColorMixin';
|
||||
import * as util from '../util/Util';
|
||||
|
||||
|
||||
/**
|
||||
* @name module:visual.TextStim
|
||||
* @class
|
||||
* @extends BaseVisualStim
|
||||
* @mixes ColorMixin
|
||||
* @param {Object} options
|
||||
* @param {String} options.name - the name used when logging messages from this stimulus
|
||||
* @param {string} [options.text="Hello World"] - the text to be rendered
|
||||
* @param {string} [options.font= "Arial"] - the text font
|
||||
* @param {Array.<number>} [options.pos= [0, 0]] - the position of the center of the text
|
||||
* @param {Color} [options.color= Color('white')] the background color
|
||||
* @param {number} [options.opacity= 1.0] - the opacity
|
||||
* @param {number} [options.contrast= 1.0] - the contrast
|
||||
* @param {string} [options.units= "norm"] - the units of the text size and position
|
||||
* @param {number} options.ori - the orientation (in degrees)
|
||||
* @param {number} [options.height] - the height of the text
|
||||
* @param {boolean} [options.bold= false] - whether or not the text is bold
|
||||
* @param {boolean} [options.italic= false] - whether or not the text is italic
|
||||
* @param {string} [alignHoriz = 'center'] - horizontal alignment
|
||||
* @param {string} [alignVert = 'center'] - vertical alignment
|
||||
* @param {boolean} wrapWidth - whether or not to wrapthe text horizontally
|
||||
* @param {boolean} [flipHoriz= false] - whether or not to flip the text horizontally
|
||||
* @param {boolean} [flipVert= false] - whether or not to flip the text vertically
|
||||
* @param {boolean} [options.autoDraw= false] - whether or not the stimulus should be automatically drawn on every frame flip
|
||||
* @param {boolean} [options.autoLog= false] - whether or not to log
|
||||
*
|
||||
* @todo vertical alignment, and orientation are currently NOT implemented
|
||||
*/
|
||||
export class TextStim extends util.mix(BaseVisualStim).with(ColorMixin)
|
||||
{
|
||||
constructor({
|
||||
name,
|
||||
win,
|
||||
text = 'Hello World',
|
||||
font = 'Arial',
|
||||
pos,
|
||||
color = new Color('white'),
|
||||
opacity,
|
||||
contrast = 1.0,
|
||||
units = 'norm',
|
||||
ori,
|
||||
height,
|
||||
bold = false,
|
||||
italic = false,
|
||||
alignHoriz = 'center',
|
||||
alignVert = 'center',
|
||||
wrapWidth,
|
||||
flipHoriz = false,
|
||||
flipVert = false,
|
||||
autoDraw,
|
||||
autoLog
|
||||
} = {}) {
|
||||
super({ name, win, units, ori, opacity, pos, autoDraw, autoLog });
|
||||
|
||||
this._addAttributes(TextStim, text, font, color, contrast, height, bold, italic, alignHoriz, alignVert, wrapWidth, flipHoriz, flipVert);
|
||||
|
||||
/*if (autoLog)
|
||||
logging.exp("Created %s = %s" % (self.name, str(self)));*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the text attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setText
|
||||
* @public
|
||||
* @param {string} text - the text
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setText(text, log) {
|
||||
this._setAttribute('text', text, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the alignHoriz attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setAlignHoriz
|
||||
* @public
|
||||
* @param {string} alignHoriz - the text horizontal alignment, e.g. 'center'
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setAlignHoriz(alignHoriz, log) {
|
||||
this._setAttribute('alignHoriz', alignHoriz, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the wrapWidth attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setWrapWidth
|
||||
* @public
|
||||
* @param {boolean} wrapWidth - whether or not to wrap the text at the given width
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setWrapWidth(wrapWidth, log) {
|
||||
this._setAttribute('wrapWidth', wrapWidth, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the height attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setHeight
|
||||
* @public
|
||||
* @param {number} height - text height
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setHeight(height, log) {
|
||||
this._setAttribute('height', height, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the italic attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setItalic
|
||||
* @public
|
||||
* @param {boolean} italic - whether or not the text is italic
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setItalic(italic, log) {
|
||||
this._setAttribute('italic', italic, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the bold attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setBold
|
||||
* @public
|
||||
* @param {boolean} bold - whether or not the text is bold
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setBold(bold, log) {
|
||||
this._setAttribute('bold', bold, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the flipVert attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setFlipVert
|
||||
* @public
|
||||
* @param {boolean} flipVert - whether or not to flip vertically
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setFlipVert(flipVert, log) {
|
||||
this._setAttribute('flipVert', flipVert, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setter for the flipHoriz attribute.
|
||||
*
|
||||
* @name module:visual.TextStim#setFlipHoriz
|
||||
* @public
|
||||
* @param {boolean} flipHoriz - whether or not to flip horizontally
|
||||
* @param {boolean} [log= false] - whether of not to log
|
||||
*/
|
||||
setFlipHoriz(flipHoriz, log) {
|
||||
this._setAttribute('flipHoriz', flipHoriz, log);
|
||||
|
||||
this._needUpdate = true;
|
||||
//this._needVertexUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether an object is inside the bounding box of the text.
|
||||
*
|
||||
* @name module:visual.TextStim#contains
|
||||
* @public
|
||||
* @param {Object} object - the object
|
||||
* @param {string} units - the units
|
||||
* @return {boolean} whether or not the object is inside the bounding box of the text
|
||||
*
|
||||
* @todo this is currently NOT implemented
|
||||
*/
|
||||
contains(object, units) {
|
||||
// get position of object:
|
||||
let objectPos_px = util.getPositionFromObject(object, units);
|
||||
if (typeof objectPos_px === 'undefined')
|
||||
throw { origin : 'TextStim.contains', context : 'when determining whether ImageStim: ' + this._name + ' contains object: ' + util.toString(object), error : 'unable to determine the position of the object' };
|
||||
|
||||
// test for inclusion:
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the stimulus, if necessary.
|
||||
*
|
||||
* @name module:visual.TextStim#_updateIfNeeded
|
||||
* @private
|
||||
*
|
||||
* @todo take size into account
|
||||
*/
|
||||
_updateIfNeeded() {
|
||||
if (this._needUpdate) {
|
||||
let height = this._height || 0.1;
|
||||
this._heightPix = this._getLengthPix(height);
|
||||
|
||||
var fontSize = Math.round(this._heightPix);
|
||||
let color = this._getDesiredColor(this._color, this._contrast);
|
||||
var font =
|
||||
(this._bold ? 'bold ' : '') +
|
||||
(this._italic ? 'italic ' : '') +
|
||||
fontSize + 'px ' + this._font;
|
||||
this._pixi = new PIXI.Text(this._text, {
|
||||
font: font,
|
||||
fill: color.hex,
|
||||
align: this._alignHoriz,
|
||||
wordWrap: this._wrapWidth != undefined,
|
||||
wordWrapWidth: this._wrapWidth ? this._getHorLengthPix(this._wrapWidth) : 0
|
||||
});
|
||||
|
||||
this._pixi.anchor.x = 0.5;
|
||||
this._pixi.anchor.y = 0.5;
|
||||
|
||||
this._pixi.scale.x = this._flipHoriz ? -1 : 1;
|
||||
this._pixi.scale.y = this._flipVert ? 1 : -1;
|
||||
|
||||
this._pixi.rotation = this._ori * Math.PI / 180;
|
||||
this._pixi.position = util.to_pixiPoint(this.pos, this.units, this.win);
|
||||
|
||||
this._pixi.alpha = this._opacity;
|
||||
|
||||
this._size = [
|
||||
this._getLengthUnits(Math.abs(this._pixi.width)),
|
||||
this._getLengthUnits(Math.abs(this._pixi.height))];
|
||||
|
||||
this._needUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user