API

Definitions

Media

Media are the objects that we display. We currently support five types of media:

If you insert a string instead of a media object the player treats it as if it was Plain text. The folowing two media definitions have the same outcome:'Wiki', {word:'Wiki'}

Stimuli

Stimuli are responsible for how we present the media.

{
    handle:'myStim',
    size: {height:25,width:25},
    location: {left:25,top:75},
    css:{color:'red','font-size':'2em'},
    media: {word: 'Your very cool stimulus'},
    data: {myData: 'some info', myOtherData: 'some other info'}
    nolog: false
}

handle: Each trial may have multiple stimuli, and they are refered to by handle. This is how refer to this specific stimulus inside the player (i.e. if we want to hide or show it). If more than one stimulus (per trial) has the same handle, all actions targeted at that handle will affect all stimuli. You can set a stimulus handle either by setting the handle property, or by setting handle into the data object. Alternatively, if a stimulus is inherited from a set, the handle is defined by default as the set that the stimulus was inherited from.

size: The size of the stimulus in percentage of the player canvas. By default, size is set to {height:'auto',width:'auto'}.

location: The location to display the stimulus, in percentage of the player canvas. Where left:20 means that the left border of the stimulus should be 20% from the left of the canvas. You may define any of left/right/top/bottom attributes.

Instead of specifying percentages you may use the keyword center in order to center the stimulus, or the keyword auto in order to override any previous settings. By default, location is set to {left:'center', right:'center',top:'center', bottom:'center'}.

css: Accepts any jquery css object. (see the api for details)

media: Defines the media associated with this stimulus.

touchMedia: An alternative media object to display in case we are on a touch device (by default, the regular media is used).

data: In addition to the basic attributes of the stimulus you may add any attribute you like as meta deta that will be available from within the player

nolog: If this attribute is set to true, this stimulus (and its associated media) will not be logged. By default nolog is set to false.

Trial

Trials are responsible for organizing stimuli and interactions with the user.

{
    data:{my: 'arbitrary',data:'object'},
    layout: [
        stimulus1,
        stimulus2
    ],
    input: [
        {handle:'left',on:'leftTouch'},
        {handle:'right',on:'rightTouch'}
    ],
    stimuli: [
        stimulus3
    ],
    interactions: [
        {
            conditions: [{type:'begin'}],
            actions: [{type:'hideStim',handle:'myStimHandle'}]
        },
        {
            conditions: [{type:'inputEqualsStim',property:'orientation'}],
            actions: [
                {type:'showStim',handle:'myStim'},
                {type:'setInput',input:{handle:'time',on:'timeout',duration:300}}
            ]
        },
        {
            conditions: [
                {type:'inputEqualsStim',property:'orientation',negate:true},
                {type:'inputEquals',value:'time',negate:true}
            ],
            actions: [{type:'endTrial'}]
        },
        {
            conditions: [{type:'inputEquals',value:'time'}],
            actions: [{type:'hideStim',handle:'myStim'}]
        }
    ]
}

layout / stimuli

The layout and stimuli are arrays that list the stimuli associated with this trial. Stimuli in layout will be statically displayed throughout the trial. stimuli within stimuli are not displayed automatically and may be dynamically interacted with during the trial (see interactions).

Input

The input attribute lists the input objects that the player reacts to. Each input object must include both a handle and an on property.

handle: the way we refer to this input element inside the player (e.g., 'rightClick') on: what triggers this input element. for now we have several types of input:

keypressed: Takes a key property that may either be a key code, a one letter string, or an array of keys.

keyup: Takes a key property that may either be a key code, a one letter string, or an array of keys.

click: Takes either a stimulus handle (stimHandle) or an html element (element). The input is activated when the user clicks the stimulus or the html element. In case an element is defined it is presented as soon as the input is activated.

mouseup: Takes a stimulus handle (stimHandle). Triggers each time the mouse key is released over the space of the target object.

mousedown: Takes a stimulus handle (stimHandle). Triggers each time the mouse key is pressed over the space of the target object.

mouseover: Takes a stimulus handle (stimHandle). Triggers each time the mouse enters the space of the target object. (note that this behaviour is meaningless in touch devices)

mouseout: Takes a stimulus handle (stimHandle). Triggers each time the mouse leaves the space of the target object. (note that this behaviour is meaningless in touch devices)

timeout: Takes a duration property and fires after the duration passes

In addition, we have several shortcuts for commonly used inputs:

leftTouch, rightTouch, topTouch and bottomTouch support the property css that will allow you to change the style of the touch area, for example:

{handle:'bottom', on: 'bottomTouch', css: {background:'blue', width: '50%'}}

Protip: In addition to the preset input types you can create custom input:

    {
        handle: 'myInput',
        on: function(inputObj, canvas, stream){
            var $listener = stream();
            document.addEventListener('click', $listener);
            $listener.end.map(function(){
                document.removeEventListener('click', $listener);
            });
            return $listener;
        },
        off: function(){
            // remove your listener 
        }
    }

Interactions

Interactions are composed of conditions and actions. Every time an event is fired (any input including timeout or the begining of a trial) all the conditions are evaluated. Notably the begin event at the begining of each trial only evaluates interactions that have a {type:'begin'} condition.

The interactions array is composed of interaction objects, each holding an array of conditions and an array of actions. For each interaction object, if all the conditions are true, then all the actions are carried out.

{
    conditions: [
        condition1,
        condition2
    ],
    actions: [
        action1,
        action2
    ]
}

Interactions: conditions

Each condition object has a type property that defines what type of evaluation to perform.

In addition, it has a negate property (false by default) that determines whether to activate the condition when the evaluation is true or when it is false.

It is possible to create complex conditions, the following condition, for instance, is activated in case there is an input that is not equal to trial.data.customAttribute, and the input handle is not "time".

[
    {type:'inputEqualsTrial',property:'customAttribute',negate:true},
    {type:'inputEquals',value:'time',negate:true}
]

begin: Automatically activated at the beginning of the trial, and is never fired again.

inputEquals: Check if the input handle equals to a static value, value may be either a string or an array strings.

inputEqualsTrial: Check if the input handle equals to the property property of trial.data

inputEqualsStim: Check if the input handle equals to the property property of any one of the stimulus.data in this trial. The optional property handle narrows the search down to stimuli fitting the handle

trialEquals: Check if the property property of the trial.data object equals to value.

inputEqualsGlobal Check if the input handle equals to the property property of the global object.

globalEquals: Check if the property property of the global object equals to value.

globalEqualsTrial: Check if the global property globalProp equals to the trial.data property trialProp.

globalEqualsStim: Check if the global property globalProp equals to the stimProp property of any one of the stimulus.data in this trial. The optional property handle narrows the search down to stimuli fitting the handle

inputEqualsCurrent Check if the input handle equals to the property property of the current object.

currentEquals: Check if the property property of the current object equals to value.

currentEqualsTrial: Check if the current property currentProp equals to the trial.data property trialProp.

currentEqualsStim: Check if the current property currentProp equals to the stimProp property of any one of the stimulus.data in this trial. The optional property handle narrows the search down to stimuli fitting the handle

function: This options is deprecated. use custom instead.

custom: It is also possible to create a custom condition:

{type:'custom', fn:function(condtion, inputData, trial){
    // do your mojo here and return true or false
}}

Interactions: actions

If all the conditions in a row of interactions are true, its actions will be executed.

showStim: Display a stimulus, takes a stimulus handle. Use 'All' for all stimuli.

hideStim: Hide a stimulus, takes a stimulus handle. Use 'All' for all stimuli.

setStimAttr: Set a stimulus.data attribute, takes a stimulus handle and a setter object or function. Any attributes in the setter object will be coppied to the stimulus.data object.

setTrialAttr: Set a trial.data attribute, takes a setter object or function. Any attributes in the setter object will be coppied to the trial.data object.

setGlobalAttr: Set a global object property, takes a setter object or function. Any attributes in the setter object will be coppied into the global object.

trigger: Activate the input handle. If duration is set, the activation happens after the duration. By default the input handle is triggered immediately.

setInput: Set input listener (useful for adding timeouts), takes an input object.

removeInput: Remove input listener, takes an input handle or an array of input handles. The special keyword All removes all listeners. Warning you must add listeners after using removeInput:All, or else the player will get stuck. This command removes triggers as well as regular input listeners.

resetTimer: Resets trial timer. The latency of any events from here on (including the current one) will be calculated back to the reset instead of the begining of the trial.

endTrial: Speaks for itself (note that any actions that come after this is called may not work properly).

canvas: Change canvas style using any of the following properties (see settings): background, canvasBackground, borderColor, borderWidth.

startMouseTracking: Starts mouse tracking. Mouse tracking logs all measurements into an array in data. It stops when you call the stopMouseTracking action or automatically at the end of the trial. Calling startMouseTracking when it is already running does not do anything.

property description
logAs Set the property within data to which the tracking data is logged (default: 'mousetracking').
logRate The minmum time between measurements in miliseconds (default: 15).
logStimulusLocation An array of stimulus handles for which location data should be logged. You can use this to save the location of the stimuli you're using as response options.

The tracking data is logged as an array of Objects with the following structure:

property description
time Time in ms from the initiation of mouseTracking.
mouseX The horizontal location of the mouse relative to the canvas.
mouseY The vertical location of the mouse relative to the canvas.
<handle>h;X (optional) The horizontal location of the <handle>h; elment relative to the canvas.
<handle>h;Y (optional) The vertical location of the <handle>h; elment relative to the canvas.
<handle>h;Width (optional) The width of the <handle>h; elment.
<handle>h;Height (optional) The height of the <handle>h; elment.

Note that each row in the log represents a mouse movement, and not a point in time. This means that if the mouse does not move, there can be long stretches of time without movement recording. When analyzing the data, make sure you use the time property in order to identify movement timing, and do not assume that measurements occur at a pretedermined frequency.

stopMouseTracking: Stops ongoing mousetracking.

log: Log this action. Pushes this action into the logging stack so that it is later sent to the server (you can set how the player logs an action using the logger settings)

custom Run a custom function. This action is intended to for use by experienced users that want to tinker with the inner workings of the player - use at your own risk! The fn property takes a custom function. The function takes three arguments: action is the action object itself, the eventData is an object holding information about the triggering event, trial is an the implementation of the trial object.

You can checkout some examples of the syntax in the plaer code.

goto: Responsible for the next trial we go to. This action will be executed only after the trial ends, you will probably want to follow it with an endTrial action.

The destination property defines what type of goto this is (default is "next").

The properties property is an object to compare to the trial data. Note that the properties will only compare to properties present in the raw sequence before inheritance!

Inheritance

Each element in the miTime (trial/stimulus/media) can inherit its attributes from an element set.

Sets

The element sets are defined in the main task script under trialSets/stimulusSets/mediaSets. Or using using the API using addMediaSets/addStimulusSets/addTrialSets.

Each set is simply an array of elements that can later be referred to as a base for new elements. Note that the name that you give the set (in the example, default or IAT) is the handle that you later use to refer to it.

The examples here use trials as an example, the same principles apply to stimuli and media elements.

var task = {
    // these are the trial sets
    trialSets: {
        // This is the first set, it has only one trial
        default : [
            defaultTrial
        ],

        // This is the second set it has three trials
        // The first trial explicitly inherits the default trial and adds some data to it
        IAT : [
            {inherit:{set:default},data:{block:1}},
            block02Trials,
            block03Trials
        ]
    },

    // these are the stimulus and media sets
    stimulusSets : stimulusSets,
    mediaSets : mediaSets
}

Inheriting

When inheriting an element the new element starts out with all of the parent's attributes and extends them with its own. This means that we use the parent element as a base and then copy in any properties that the child has, overwriting any existing properties. The only exception to this rule is their data objects which we attempt to merge (giving precedence again to the child).

Follow this pseudo code:

// The parent trial
{
    data: {name: 'jhon', family:'doe'}
    stimuli: [
        stim1,
        stim2
    ]
}

// The child trial which attempts to inherit the parent
{
    inherit: 'parent',
    data: {name: 'jack'}
    stimuli: [
        stim1
    ]
}

// The result would be:
{
    data: {name: 'jack', family:'doe'}  // the child kept its own name but inherited the family name
    stimuli: [                          // the stimuli array was completely overwritten
        stim1
    ]
}

In order for an element to inherit another element it must use the inherit property of the inheriting element.

{
    inherit: inheritObject
}

The inherit object has a set property defining which element set it should inherit from. It also has a type property that defines what type of inheritance we should use.

We have implemented several types of inheritance:

random: Randomly picks an element from the set. Note that this is the default inheritance type and so it is not obligatory to use the type property. You can also use a short cut and set the set using a simple string instead of an object (see example below).

exRandom: Picks a random element without repeating the same element until we've gone through the whole set

bySequence: Picks the elements by the order they were inserted into the set

byData: Picks a specific element from the set. We compare the data property to the element.data property and if data is a subset of element.data it picks the element (this means that if all properties of data property equal to the properties of the same name in element.data it is a fit). This function will pick only the first element to fit the data. If the data property is set as a string, we assume it refers to the element handle.

function: You may also use a custom function to pick your element.

{set: 'setName', type: function(definitions){
    // definitions is the inherit object (including  set, type, and whatever other properties you'd like to use)
    // the context ("this") is the element collection, it is a Backbone.html collection of the elements in the set
}}

Customization

Each trial/stimulus/media can also have a customize method, this method is called once the element is inherited but before it is activated. It accepts two arguments: the source object on which it is called (in this case the appropriate trial object), and the global object. The source object is also the context for the function. The example shows how you can use customize to push a stimulus into the trial, this allows us to generate stim1 dynamicaly.

{
    inherit: 'something',
    stimuli: [], // note that their are no stimuli yet!
    customize : function(trialSource, globalObject){
        // push a stimulus into the stimulus array
        trialSource.stimuli.push(stim1);
    }
}

The sequence

The sequence is an ordered list of the trials that you want to present consequently to the users.

task = {
    trialSets: trialSets,
    stimulusSets : stimulusSets,
    mediaSets : mediaSets,
    sequence: [
        trial1,
        trial2,
        trial3
    ]

}

This is all you really need to know in order to run a task. In addition the sequencer provides several mixing options that allow for powerful randomization of your task.

Mixing

The mixer allows wrapping sub sequences in objects that allow you to manipulate the way in which they appear. You may insert such an object at any place within the sequence and it will be replaced by the appropriate trials.

The basic structure of a mixer object is:

{
    mixer: 'functionType',
    data: [trial1, trial2]
}

The mixer property holds the mixer type.

The data property holds an array of elements (either trials or mixer objects).

A sequence can look something like this (don't get scared it's simpler than it looks):

[
    // The first trial to present.
    firstTrial,

    // Repeat the structure inside 10 time (so we get 40 trials)
    {
        mixer: 'repeat',
        times: 10,
        data: [
            // Delay the mixing of these elements until after the `repeat`.
            {
                mixer: 'wrapper',
                data: [
                    trial1,
                    // Randomize the order of the trials within.
                    {
                        mixer: 'random',
                        data: [
                            trial2,
                            // Keep trial 3 and 4 together.
                            {
                                mixer: 'wrapper',
                                data: [
                                    trial3,
                                    trial4
                                ]
                            }
                        ]
                    } // end random
                ]
            } // end wrapper
        ]
    }, // end repeat

    // the last trial to present
    lastTrial
]

This sequence has an opening and ending trial (firstTrial and lastTrial). Between them them we repeat a set of four trials ten times. The order of the four trials is randomized, so that trial1 always comes first and the order of the following trials are randomized but trial3 and trial4 are wrapped together and therefore always stay consecutive.

We support several mixer types.

repeat: Repeats the element in data times times.

random: Randomizes the order of elements in data.

weightedRandom: Picks a single element using a weighted random algorithm. Each element in data is given the appropriate weight from weights. In the following example trial2 has four times the probability of being picked as trial1.

choose: Picks n random elements from data (by default the chooser picks one element).

wrapper: The wrapper mixer serves a sort of parenthesis for the mixer. It has two primary functions; first, in case you want to keep a set of elements as a block (when randomizing) simply wrap them and they'll stay together. Second, when repeating a random mixer, the mixer first randomizes the content of the inner mixer and only then repeats it. If you want the randomization to be deferred until after the repeat all you have to do is wrap it in a wrapper.

Changing Settings

Settings that apply to the whole task may be changed using API.addSettings (see documentation). Following are the available settings.

Logger

logger: {
    url: 'your/target/url',
    pulse: 3,
    fullpath: false,
    logger: function(){
        // do your mojo here :)
    }
}

The logger section is responsible for logging options.

url: Is the url to which we send the logged data (ask your IT team what it should be). You should set this if you want to log your data...

pulse: After how many rows should we send data to the server. In case the number of rows is reached during a trial, the player waits until the end of the trial and sends all the log rows it gathered at once. Regardless of pulse, the player sends all remaining log rows at the end of the task. This means that it is possible to get pulses holding more or less than "pulse" rows. If pulse is not set (or is set to 0) the player will send all data at the end of the task.

fullpath: When using the media path to log media elements (for images and templates), should we use the full path or just the filename (false by default)

meta: An object that is used to extend each logged row. This is useful in case you want to add some global data to the posts (such as server generated user id, or task name).

logger: Accepts a function to replace the existing logging function. (don't touch this if you don't realy know what you're doing). The logger function is called each time a log action is triggered (see interactions: actions log). It is responsible for adding a logging row to be sent to the server.

function(trialData, inputData, actionData,logStack){
    // trialData: the data object from this trial
    // inputData: the input object that triggered this action
    // actionData: the action object that was triggered (it should look like {type:'log', your:'custom property'})
    // logStack: an array with all previously logged rows

    // the context for this function ("this") is the original trial object

    // the function should return an object to be pushed into the trial stack, and later be sent to the server
}

This is what the default logger looks like:

function(trialData, inputData, actionData,logStack){
    var stimList = this._stimulus_collection.get_stimlist();
    var mediaList = this._stimulus_collection.get_medialist();

    return {
        log_serial : logStack.length,
        trial_id: this._id,
        name: this.name(),
        responseHandle: inputData.handle,
        latency: Math.floor(inputData.latency),
        stimuli: stimList,
        media: mediaList,
        data: trialData
    };
};

Canvas

The canvas is the visable part of the player. This section in the settings controls the shape and appearance of the canvas.

canvas: {
    maxWidth: 800,
    proportions : 0.8
}

By default Minno attempts to keep the canvas size proportional so that the relationship between stimuli stays consistent. Therefore it attempts to take up as much screen space as posible while staying true to the proportion.

proportions: The proportion settings describes the relationship between the height and width of the canvas (proportion = height/width). You can set it either directly as a number (i.e. 0.8) or more explicitly as an object (i.e. {width:5,height:4}).
By default it is set to 0.8.

maxWidth: The maximum width (in pixels) that the canvas may reach. This value must be a plain number (i.e. 800 and not '800px'). Note that if width is set, then this property is ignored and the canvas size stays static.

width: If width is set, then the canvas size is set to a constant width (control the hight using the proportions property). This value must be a plain number (i.e. 800 and not '800px').

textSize: Controls the default font size in the canvas. It takes a single number that represents font size in percentage of the canvas height (similar to the CSS3 vh unit). By default it is set to 3. Any stimulus that sets font-size using a relative unit (percent/em) will be relative to this size. Any stimulus that sets font-size using an absolute unit (px/pt) will be displayed according to the absolute unit.

background: Controls the background color of the whole screen.

canvasBackground: Controls the background color of the player canvas.

borderWidth: Controls the width of the player canvas borders (in pixels).

borderColor: Controls the color of the player canvas borders.

css: Allows you to add any custom css to the canvas (using the jquery css API).

Base_url

The base_url section is responsible for loading images and templates. It allows the user to pick a base url from which to load all images and templates. It accepts either an object setting the base url for images and templates or a string that will be used for both images and templates:

// object notation
base_url: {
    image: "images",
    template: "templates/"
}

// string notation
base_url: "media/"

Redirect

The redirect setting decides where to redirect the player at the end of the task. By default, the player simply refreshes the current page. This option is not used if the endTask hook is set.

redirect: '//my.domain.edu'

Hooks

This option is deprecated, please use onEnd instead.

onEnd

A function to be called at the end of the task. For example, the following setting logs the task logs to the console.

API.addSettings(`onEnd`, function(){
    console.log(API.getCurrent().logs);
});

Meta data

Meta data is data that should be returned with every request to the server. Any key value pair in the meta data is added to every post the player makes to the server. In order to create a post with three keys: json, session_id and task_id - you would write something like this:

metaData: {
    session_id: 9872356,
    task_id: '43BTW78'
}

(the json field is the field that holds the player data it is created automaticaly)

preloadImages

There are times when you want to preload images manually, without relying on minno-time to recognize all your media automatically. This can be if you are using complex html type media that include images, or if you are using templates to set images. In these cases there is a convenience setting that allows you to add your images to the preloading queue.

API.addSettings('preloadImages', ['img1.jpg', 'img2.jpg', 'img3.jpg']);

Logging

The player sends all the data it has gathered to the url defined in the settings logger. The data is sent as an ajax POST where the only field is "json" (unless you added something using metadata). The field includes a json array including all logs created. each log is an object including the following fields:

Field Description
log_serial the serial number for this log row (starts at 1)
trial_id a unique identifier for this trial
name the name of this trial - an alias if one is set, otherwise the set the trial inherited
block the block attribute of trial.data (it is up to the user to set this attribute, usually in the trial definitions)
responseHandle the handle for the input that triggered this log
score the score attribute of trial.data (it is up to the user to set this attribute, usually using setTrialAttr)
latency the latency of the response from the beginning of the trial
stimuli a json including the stimuli used in this trial (we use an alias if one is set, otherwise the stimulus set, otherwise the stimulus handle otherwise stim#)
media a json including the media used in this trial (we use an alias if one is set, otherwise the media set, otherwise media#)
data a json including the data property of this trial

You can control the names that the different elements get by adding an alias property to the element itslef or to its data. If the alias isn't set, then the player attempts to choose a meaningful name on its own (using the inherited set, or whatever is appropriate).


License: Apache 2. © Project Implicit. · Current version [version]