recommit of previous commit since nothing was changed...

jspsych-similarity.js : fixed data storage so that generic data object
was included in the block's data.

jspsych-storybook.js: included generic data object in data storage,
included path to image in data storage.

jspsych.js: cosmetic adjustment to code in finishExperiment() method.

NEW:

added call-function plugin, which calls a user-specified function.
useful for saving data before completion.

added paint plugin - displays a canvas element superimposed on an image
and allows subjects to draw on the image to indicate areas of interest.
This commit is contained in:
Josh de Leeuw 2012-07-12 13:22:06 -04:00
parent ef9a605cd8
commit 39846f1754
5 changed files with 230 additions and 9 deletions

40
jspsych-call-function.js Normal file
View File

@ -0,0 +1,40 @@
/** July 2012. Josh de Leeuw
This plugin gives the user the ability to execute an arbitrary function
during an experiment. It can be used to save data in the middle of an
experiment, for example.
Params:
"type" is "call_function"
"func" is the function that will be called
"args" is an array of arguments to pass to the function. (optional)
Data:
The return value of the function will be stored in the data.
**/
(function( $ ) {
jsPsych.call_function = (function(){
var plugin = {};
plugin.create = function(params) {
var trials = new Array(1);
trials[0] = {
"type": "call_function",
"func": params["func"],
"args": params["args"] || []
}
}
plugin.trial = function($this, block, trial, part)
{
block.data[block.trial_idx] = trial.func.apply({}, trial.args);
block.next();
}
return plugin;
})();
})(jQuery);

186
jspsych-paint.js Normal file
View File

@ -0,0 +1,186 @@
(function( $ ) {
jsPsych.paint = (function(){
var plugin = {};
// private functions
function colorPixel(ctx, x, y, fresh)
{
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "rgba(0,0,0, 1.0)";
//ctx.fillRect(x,y,10,10);
//ctx.arc(x,y,10,0,Math.Pi*2,true);
//ctx.fill();
ctx.lineWidth = 30;
ctx.lineCap = ctx.lineJoin = 'round';
ctx.strokeStyle = "rgba(0,0,0,1.0)";
if(fresh){
ctx.beginPath();
ctx.moveTo(x+0.01,y);
}
ctx.lineTo(x,y);
ctx.stroke();
}
plugin.create = function(params) {
stims = params["stimuli"];
trials = new Array(stims.length);
for(var i = 0; i < trials.length; i++)
{
trials[i] = {};
trials[i]["type"] = "paint";
trials[i]["a_path"] = stims[i];
trials[i]["height"] = params["height"];
trials[i]["width"] = params["width"];
trials[i]["timing"] = params["timing"];
if(params["data"]!=undefined){
trials[i]["data"] = params["data"][i];
}
if(params["prompt"]!=undefined){
trials[i]["prompt"] = params["prompt"];
}
}
return trials;
}
plugin.trial = function($this, block, trial, part)
{
switch(part){
case 1:
p1_time = (new Date()).getTime();
$this.append($('<div>', {
"id": 'paintbox',
"class": 'paint'}));
$('#paintbox').css({
'position': 'relative',
'width': trial.width,
'height': trial.height});
$('#paintbox').append($('<img>', {
"src": trial.a_path,
"class": 'paint',
"css": {
'width':trial.width,
'height':trial.height,
'position': 'absolute',
'top': '0',
'left': '0',
'z-index': '0'
}
}));
$('#paintbox').append($('<canvas>', {
"id": "paintcanvas",
"class": "paint",
"css": {
'position': 'absolute',
'top': '0',
'left': '0',
'z-index': '1',
'cursor': 'crosshair'
}
}));
$('#paintcanvas').attr('width',trial.width);
$('#paintcanvas').attr('height',trial.height);
var canvas = document.getElementById('paintcanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = "rgba(0,0,0,0.8)";
ctx.fillRect(0,0,trial.width,trial.height);
var paint = false;
document.onselectstart = function(){
return false;
}
$('#paintcanvas').mousedown(function(e){
var mouseX = e.pageX - $('#paintbox').offset().left;
var mouseY = e.pageY - $('#paintbox').offset().top;
paint = true;
colorPixel(ctx, mouseX, mouseY, true);
});
$('#paintcanvas').mousemove(function(e){
var mouseX = e.pageX - $('#paintbox').offset().left;
var mouseY = e.pageY - $('#paintbox').offset().top;
if(paint){
colorPixel(ctx, mouseX, mouseY, false);
}
});
$(document).mouseup(function(e){
paint = false;
});
$this.append($('<button>',{
'id':'done',
'class':'paint'}));
$('#done').html('Done');
$('#done').click(function(){
plugin.trial($this,block,trial,part+1);
});
$this.append($('<button>',{
'id':'reset',
'class':'paint'}));
$('#reset').html('Reset');
$('#reset').click(function(){
ctx.clearRect(0,0,trial.width,trial.height);
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "rgba(0,0,0,0.8)";
ctx.fillRect(0,0,trial.width,trial.height);
});
if(trial.prompt){
$this.append(trial.prompt);
}
break;
case 2:
var canvas = document.getElementById('paintcanvas');
var ctx = canvas.getContext('2d');
var img = ctx.getImageData(0,0,trial.width,trial.height);
var pix = img.data;
var tdata = new Array(trial.width*trial.height);
var data_string = "";
//tdata[0] = new Array();
for(var i=0, j=0, n=pix.length; i<n; i+=4, j++)
{
tdata[j] = (pix[i+3] == 0)
if(pix[i+3] == 0)
{
data_string = data_string+"1";
} else {
data_string = data_string+"0";
}
}
block.data[block.trial_idx] = $.extend({},{"a_path": trial.a_path,"pixels": data_string},trial.data);
$this.html('');
setTimeout(function(){block.next();}, trial.timing[0]);
break;
}
}
return plugin;
})();
})(jQuery);

View File

@ -73,7 +73,7 @@
case 4:
// get data
var score = $("#slider").slider("value");
block.data[block.trial_idx] = {"score": score, "a_path": trial.a_path, "b_path": trial.b_path}
block.data[block.trial_idx] = $.extend({},{"score": score, "a_path": trial.a_path, "b_path": trial.b_path},trial.data);
// goto next trial in block
$('.sim').remove();
setTimeout(function(){block.next();}, trial.timing[0]);

View File

@ -55,8 +55,9 @@
{
var click_loc_data = {"click_locations": click_locations};
var click_time_data = {"click_times": click_times};
var img = {"img": trial.a_path };
// save data
block.data[block.trial_idx] = $.extend({}, click_loc_data, click_time_data);
block.data[block.trial_idx] = $.extend({}, img, click_loc_data, click_time_data, trial.data);
plugin.trial($this, block, trial, part + 1);
}

View File

@ -125,13 +125,7 @@
function finishExperiment()
{
var all_data = [];
for(var i=0;i<exp_blocks.length;i++)
{
all_data[i] = exp_blocks[i].data;
}
opts["finish"].apply((new Object()), [all_data]);
opts["finish"].apply((new Object()), [core.data()]);
}
function do_trial(block, trial)