Skip to content

Commit

Permalink
Merge pull request #1174 from becky-gilbert/fix-consecutive-images
Browse files Browse the repository at this point in the history
add render_on_canvas option, fix maintain_aspect_ratio - #891 #969 #1172
  • Loading branch information
becky-gilbert committed Nov 25, 2020
2 parents bbef9ef + 32cdeae commit 39c128c
Show file tree
Hide file tree
Showing 20 changed files with 668 additions and 164 deletions.
2 changes: 1 addition & 1 deletion docs/plugins/jspsych-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ frame_isi | numeric | 0 | If greater than 0, then a gap will be shown between ea
sequence_reps | numeric | 1 | How many times to show the entire sequence. There will be no gap (other than the gap specified by `frame_isi`) between repetitions.
choices | array of keycodes | `jsPsych.ALL_KEYS` | This array contains the keys that the subject is allowed to press in order to respond to the stimulus. Keys can be specified as their [numeric key code](http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes) or as characters (e.g., `'a'`, `'q'`). The default value of `jsPsych.ALL_KEYS` means that all keys will be accepted as valid responses. Specifying `jsPsych.NO_KEYS` will mean that no responses are allowed.
prompt | string | null | This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the subject is supposed to take (e.g., which key(s) to press).

render_on_canvas | boolean | true | If true, the images will be drawn onto a canvas element. This prevents a blank screen (white flash) between consecutive images in some browsers, like Firefox and Edge. If false, the image will be shown via an img element, as in previous versions of jsPsych.

## Data Generated

Expand Down
1 change: 1 addition & 0 deletions docs/plugins/jspsych-categorize-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ sequence_reps | numeric | 1 | How many times to show the entire sequence.
allow_response_before_complete | boolean | false | If true, the subject can respond before the animation sequence finishes.
prompt | string | null | This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the subject is supposed to take (e.g., which key to press).
feedback_duration | numeric | 2000 | How long to show the feedback (milliseconds).
render_on_canvas | boolean | true | If true, the images will be drawn onto a canvas element. This prevents a blank screen (white flash) between consecutive images in some browsers, like Firefox and Edge. If false, the image will be shown via an img element, as in previous versions of jsPsych.

## Data Generated

Expand Down
1 change: 1 addition & 0 deletions docs/plugins/jspsych-image-button-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ trial_duration | numeric | null | How long to wait for the subject to make a res
margin_vertical | string | '0px' | Vertical margin of the button(s).
margin_horizontal | string | '8px' | Horizontal margin of the button(s).
response_ends_trial | boolean | true | If true, then the trial will end whenever the subject makes a response (assuming they make their response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force the subject to view a stimulus for a fixed amount of time, even if they respond before the time is complete.
render_on_canvas | boolean | true | If true, the image will be drawn onto a canvas element. This prevents a blank screen (white flash) between consecutive image trials in some browsers, like Firefox and Edge. If false, the image will be shown via an img element, as in previous versions of jsPsych.

## Data Generated

Expand Down
1 change: 1 addition & 0 deletions docs/plugins/jspsych-image-keyboard-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ prompt | string | null | This string can contain HTML markup. Any content here w
stimulus_duration | numeric | null | How long to show the stimulus for in milliseconds. If the value is null, then the stimulus will be shown until the subject makes a response.
trial_duration | numeric | null | How long to wait for the subject to make a response before ending the trial in milliseconds. If the subject fails to make a response before this timer is reached, the subject's response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, then the trial will wait for a response indefinitely.
response_ends_trial | boolean | true | If true, then the trial will end whenever the subject makes a response (assuming they make their response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force the subject to view a stimulus for a fixed amount of time, even if they respond before the time is complete.
render_on_canvas | boolean | true | If true, the image will be drawn onto a canvas element. This prevents a blank screen (white flash) between consecutive image trials in some browsers, like Firefox and Edge. If false, the image will be shown via an img element, as in previous versions of jsPsych.

## Data Generated

Expand Down
1 change: 1 addition & 0 deletions docs/plugins/jspsych-image-slider-response.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ prompt | string | null | This string can contain HTML markup. Any content here w
stimulus_duration | numeric | null | How long to show the stimulus for in milliseconds. If the value is null, then the stimulus will be shown until the subject makes a response.
trial_duration | numeric | null | How long to wait for the subject to make a response before ending the trial in milliseconds. If the subject fails to make a response before this timer is reached, the subject's response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, then the trial will wait for a response indefinitely.
response_ends_trial | boolean | true | If true, then the trial will end whenever the subject makes a response (assuming they make their response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force the subject to view a stimulus for a fixed amount of time, even if they respond before the time is complete.
render_on_canvas | boolean | true | If true, the image will be drawn onto a canvas element. This prevents a blank screen (white flash) between consecutive image trials in some browsers, like Firefox and Edge. If false, the image will be shown via an img element, as in previous versions of jsPsych.

## Data Generated

Expand Down
6 changes: 5 additions & 1 deletion examples/jspsych-animation.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
<body></body>
<script>

// If render_on_canvas is false, the images will be shown via an <img> rather than <canvas> element.
// In some browsers, the first time the images are shown, the <img> method (render_on_canvas: false) will produce a brief
// blank screen (white flash) between images when frame_isi is 0.
var animation_trial = {
type: 'animation',
stimuli: ['img/happy_face_1.jpg', 'img/happy_face_2.jpg', 'img/happy_face_3.jpg', 'img/happy_face_4.jpg'],
sequence_reps: 3,
frame_time: 300,
prompt: '<p>Watch the faces.</p>'
prompt: '<p>Watch the faces.</p>',
//render_on_canvas: false
};


Expand Down
10 changes: 9 additions & 1 deletion examples/jspsych-categorize-animation.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,29 @@
img {
width: 300px;
}
#jspsych-categorize-animation-stimulus {
width: 300px;
height: 225px;
}
</style>
</head>
<body></body>
<script>

// If render_on_canvas is false, the images will be shown via an <img> rather than <canvas> element.
// In some browsers, the first time the images are shown, the <img> method (render_on_canvas: false) will produce a brief
// blank screen (white flash) between images.
var trials = {
type: 'categorize-animation',
stimuli: ['img/happy_face_1.jpg', 'img/sad_face_3.jpg'],
key_answer: 68,
choices: [68, 83],
text_answer: 'different',
feedback_duration: 500,
feedback_duration: 1000,
correct_text: "<p>Correct. The faces had %ANS% expressions.</p>",
incorrect_text: "<p>Incorrect. The faces had %ANS% expressions.</p>",
prompt: "<p>Press D if the faces had different emotional expressions. Press S if the faces had the same emotional expression.</p>",
//render_on_canvas: false
};

jsPsych.init({
Expand Down
38 changes: 35 additions & 3 deletions examples/jspsych-image-button-response.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,37 @@
<script src="../jspsych.js"></script>
<script src="../plugins/jspsych-image-button-response.js"></script>
<link rel="stylesheet" href="../css/jspsych.css">
<style>
img { width: 300px; }
</style>
</head>
<body></body>
<script>

var timeline = [];

// If render_on_canvas is false, the images will be shown via an <img> rather than <canvas> element.
// In some browsers, the first time the images are shown, the <img> method (render_on_canvas: false) will produce a brief
// blank screen (white flash) between images that are presented consecutively with no post_trial_gap between them.
var trial = {
type: 'image-button-response',
stimulus: jsPsych.timelineVariable('stim'),
trial_duration: 1000,
choices: ['Happy', 'Sad'],
prompt: '<p>What emotion is this person showing?</p><p>(Consecutive images with no post_trial_gap)</p>',
stimulus_width: 400,
maintain_aspect_ratio: true,
post_trial_gap: 0,
//render_on_canvas: false
}

timeline.push({
timeline: [trial],
timeline_variables: [
{stim: 'img/happy_face_1.jpg'},
{stim: 'img/happy_face_2.jpg'},
{stim: 'img/happy_face_3.jpg'},
{stim: 'img/happy_face_4.jpg'}
]
});

timeline.push({
type: 'image-button-response',
stimulus: 'img/happy_face_1.jpg',
Expand All @@ -39,8 +61,18 @@
prompt: "<p>What emotion is this person showing? (trial ends after 2s)</p>"
});

timeline.push({
type: 'image-button-response',
stimulus: 'img/happy_face_4.jpg',
choices: ['Happy', 'Sad'],
stimulus_width: 400,
maintain_aspect_ratio: false,
prompt: '<p>What emotion is this person showing?</p><p>(Stimulus_width set to a smaller value and maintain_aspect_ratio set to false.)</p>'
});

jsPsych.init({
timeline: timeline,
preload_images: ['img/happy_face_1.jpg','img/happy_face_2.jpg','img/happy_face_3.jpg','img/happy_face_4.jpg'],
on_finish: function(){jsPsych.data.displayData();}
});

Expand Down
48 changes: 39 additions & 9 deletions examples/jspsych-image-keyboard-response.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,36 @@
<script src="../jspsych.js"></script>
<script src="../plugins/jspsych-image-keyboard-response.js"></script>
<link rel="stylesheet" href="../css/jspsych.css">
<style>
img {
width: 300px;
}
</style>
</head>
<body></body>
<script>

// If render_on_canvas is false, the images will be shown via an <img> rather than <canvas> element.
// In some browsers, the first time the images are shown, the <img> method (render_on_canvas: false) will produce a brief
// blank screen (white flash) between images that are presented consecutively with no post_trial_gap between them.
var trial = {
type: 'image-keyboard-response',
stimulus: jsPsych.timelineVariable('stim'),
trial_duration: 300,
choices: jsPsych.NO_KEYS,
prompt: '<p>Watch the faces.</p>',
stimulus_width: 400,
maintain_aspect_ratio: true,
post_trial_gap: 0,
//render_on_canvas: false
}

var trial_proc = {
timeline: [trial],
timeline_variables: [
{stim: 'img/happy_face_1.jpg'},
{stim: 'img/happy_face_2.jpg'},
{stim: 'img/happy_face_3.jpg'},
{stim: 'img/happy_face_4.jpg'}
],
repetitions: 3
}

var trial_1 = {
type: 'image-keyboard-response',
stimulus: 'img/happy_face_1.jpg',
Expand All @@ -35,13 +56,22 @@
trial_duration: 2000,
prompt: '<p>No response allowed. 2s wait.</p>'
}


var trial_4 = {
type: 'image-keyboard-response',
stimulus: 'img/happy_face_4.jpg',
choices: ['y','n'],
stimulus_width: 400,
maintain_aspect_ratio: false,
prompt: '<p>Have you seen this face before? Y or N.</p><p>(Stimulus_width set to a smaller value and maintain_aspect_ratio set to false.)</p>'
}

jsPsych.init({
timeline: [trial_1, trial_2, trial_3],
timeline: [trial_proc, trial_1, trial_2, trial_3, trial_4],
preload_images: ['img/happy_face_1.jpg','img/happy_face_2.jpg','img/happy_face_3.jpg','img/happy_face_4.jpg'],
on_finish: function() {
jsPsych.data.displayData();
},
default_iti: 250
}
});
</script>

Expand Down
39 changes: 31 additions & 8 deletions examples/jspsych-image-slider-response.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,44 @@
<script src="../jspsych.js"></script>
<script src="../plugins/jspsych-image-slider-response.js"></script>
<link rel="stylesheet" href="../css/jspsych.css">
<style>
img {
width: 300px;
}
</style>
</head>
<body></body>
<script>

// If render_on_canvas is false, the images will be shown via an <img> rather than <canvas> element.
// In some browsers, the first time the images are shown, the <img> method (render_on_canvas: false) will produce a brief
// blank screen (white flash) between images that are presented consecutively with no post_trial_gap between them.
var trial = {
type: 'image-slider-response',
stimulus: jsPsych.timelineVariable('stim'),
trial_duration: 1000,
labels: ['1 (least happy)', '100 (most happy)'],
prompt: '<p>How happy is this person on a scale of 1-100?</p><p>(Consecutive images with no post_trial_gap)</p>',
response_ends_trial: false,
slider_width: 500,
stimulus_width: 400,
maintain_aspect_ratio: true,
post_trial_gap: 0,
//render_on_canvas: false
}

var trial_proc = {
timeline: [trial],
timeline_variables: [
{stim: 'img/happy_face_1.jpg'},
{stim: 'img/happy_face_2.jpg'},
{stim: 'img/happy_face_3.jpg'},
{stim: 'img/happy_face_4.jpg'}
]
}

var trial_1 = {
type: 'image-slider-response',
stimulus: 'img/happy_face_1.jpg',
labels: ['1 (least happy)', '100 (most happy)'],
slider_width: 500,
require_movement: true,
prompt: '<p>How happy is this person on a scale of 1-100?</p>'
prompt: '<p>How happy is this person on a scale of 1-100? (Interaction with slider is required)</p>'
}

var trial_2 = {
Expand All @@ -34,15 +56,16 @@

var trial_3 = {
type: 'image-slider-response',
stimulus: 'img/happy_face_2.jpg',
stimulus: 'img/happy_face_3.jpg',
labels: ['1 (least happy)', '100 (most happy)'],
slider_width: 500,
prompt: '<p>How happy is this person on a scale of 1-100? (1s stimulus duration)</p>',
stimulus_duration: 1000
}

jsPsych.init({
timeline: [trial_1, trial_2, trial_3],
timeline: [trial_proc, trial_1, trial_2, trial_3],
preload_images: ['img/happy_face_1.jpg','img/happy_face_2.jpg','img/happy_face_3.jpg','img/happy_face_4.jpg'],
on_finish: function() {
jsPsych.data.displayData();
},
Expand Down
51 changes: 43 additions & 8 deletions plugins/jspsych-animation.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ jsPsych.plugins.animation = (function() {
pretty_name: 'Prompt',
default: null,
description: 'Any content here will be displayed below stimulus.'
},
render_on_canvas: {
type: jsPsych.plugins.parameterType.BOOL,
pretty_name: 'Render on canvas',
default: true,
description: 'If true, the images will be drawn onto a canvas element (prevents blank screen between consecutive images in some browsers).'+
'If false, the image will be shown via an img element.'
}
}
}
Expand All @@ -66,9 +73,27 @@ jsPsych.plugins.animation = (function() {
var responses = [];
var current_stim = "";

if (trial.render_on_canvas) {
// first clear the display element (because the render_on_canvas method appends to display_element instead of overwriting it with .innerHTML)
if (display_element.hasChildNodes()) {
// can't loop through child list because the list will be modified by .removeChild()
while (display_element.firstChild) {
display_element.removeChild(display_element.firstChild);
}
}
var canvas = document.createElement("canvas");
canvas.id = "jspsych-animation-image";
canvas.style.margin = 0;
canvas.style.padding = 0;
display_element.insertBefore(canvas, null);
var ctx = canvas.getContext("2d");
}

var animate_interval = setInterval(function() {
var showImage = true;
display_element.innerHTML = ''; // clear everything
if (!trial.render_on_canvas) {
display_element.innerHTML = ''; // clear everything
}
animate_frame++;
if (animate_frame == trial.stimuli.length) {
animate_frame = 0;
Expand All @@ -85,9 +110,23 @@ jsPsych.plugins.animation = (function() {
}, interval_time);

function show_next_frame() {
// show image
display_element.innerHTML = '<img src="'+trial.stimuli[animate_frame]+'" id="jspsych-animation-image"></img>';

if (trial.render_on_canvas) {
display_element.querySelector('#jspsych-animation-image').style.visibility = 'visible';
var img = new Image();
img.src = trial.stimuli[animate_frame];
canvas.height = img.naturalHeight;
canvas.width = img.naturalWidth;
ctx.drawImage(img,0,0);
if (trial.prompt !== null & animate_frame == 0 & reps == 0) {
display_element.insertAdjacentHTML('beforeend', trial.prompt);
}
} else {
// show image
display_element.innerHTML = '<img src="'+trial.stimuli[animate_frame]+'" id="jspsych-animation-image"></img>';
if (trial.prompt !== null) {
display_element.innerHTML += trial.prompt;
}
}
current_stim = trial.stimuli[animate_frame];

// record when image was shown
Expand All @@ -96,10 +135,6 @@ jsPsych.plugins.animation = (function() {
"time": performance.now() - startTime
});

if (trial.prompt !== null) {
display_element.innerHTML += trial.prompt;
}

if (trial.frame_isi > 0) {
jsPsych.pluginAPI.setTimeout(function() {
display_element.querySelector('#jspsych-animation-image').style.visibility = 'hidden';
Expand Down

0 comments on commit 39c128c

Please sign in to comment.