From 92b6c2e78e06fa24bd068fcd0e3ee09792b13122 Mon Sep 17 00:00:00 2001 From: "Peter J. Kohler" Date: Sat, 29 Aug 2020 14:55:25 -0400 Subject: [PATCH 01/13] updates to free-sort plugin, new functionality --- plugins/jspsych-free-sort.js | 276 +++++++++++++++++++++++++++-------- 1 file changed, 213 insertions(+), 63 deletions(-) diff --git a/plugins/jspsych-free-sort.js b/plugins/jspsych-free-sort.js index e498d7e3f2..f3af378484 100644 --- a/plugins/jspsych-free-sort.js +++ b/plugins/jspsych-free-sort.js @@ -22,19 +22,25 @@ jsPsych.plugins['free-sort'] = (function() { pretty_name: 'Stimuli', default: undefined, array: true, - description: 'Images to be displayed.' + description: 'items to be displayed.' }, stim_height: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Stimulus height', default: 100, - description: 'Height of images in pixels.' + description: 'Height of items in pixels.' }, stim_width: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Stimulus width', default: 100, - description: 'Width of images in pixels' + description: 'Width of items in pixels' + }, + scale_factor: { + type: jsPsych.plugins.parameterType.FLOAT, + pretty_name: 'Stimulus scaling factor', + default: 1.5, + description: 'How much larger to make the stimulus while moving (1 = no scaling)' }, sort_area_height: { type: jsPsych.plugins.parameterType.INT, @@ -48,6 +54,13 @@ jsPsych.plugins['free-sort'] = (function() { default: 800, description: 'The width of the container that subjects can move the stimuli in.' }, + sort_area_shape: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Sort area shape', + options: ['square','ellipse'], + default: 'ellipse', + description: 'The shape of the sorting area' + }, prompt: { type: jsPsych.plugins.parameterType.STRING, pretty_name: 'Prompt', @@ -64,7 +77,7 @@ jsPsych.plugins['free-sort'] = (function() { button_label: { type: jsPsych.plugins.parameterType.STRING, pretty_name: 'Button label', - default: 'Continue', + default: 'continue', description: 'The text that appears on the button to continue to the next trial.' } } @@ -74,36 +87,91 @@ jsPsych.plugins['free-sort'] = (function() { var start_time = performance.now(); - var html = ""; - // check if there is a prompt and if it is shown above - if (trial.prompt !== null && trial.prompt_location == "above") { - html += trial.prompt; - } - - html += '
'; + 'style="position: relative; width:'+trial.sort_area_width+'px; height:'+trial.sort_area_height+'px; margin: auto; line-height: 0em"'; - // check if prompt exists and if it is shown below - if (trial.prompt !== null && trial.prompt_location == "below") { - html += trial.prompt; + // variable that has the prompt text, counter and button + const html_text = '
' + trial.prompt + + '

You still need to place ' + trial.stimuli.length + ' items inside the arena.

' + + '
' + + // position prompt above or below + if (trial.prompt_location == "below") { + html += html_text + } else { + html = html_text + html } display_element.innerHTML = html; + // another div for border + let border_div = '
( (trial.sort_area_width - trial.stim_width) * .5 ) ) { + //r_coords.push({ x:x, y:y } ) + r_coords.push({ x:x + (trial.sort_area_width) * .5 , y:y }); + } else { + l_coords.push({ x:x - (trial.sort_area_width) * .5 , y:y }); + //l_coords.push({ x:x, y:y } ) + } + } + } + + // repeat coordinates until you have enough coords (may be obsolete) + while ( ( r_coords.length + l_coords.length ) < trial.stimuli.length ) { + r_coords = r_coords.concat(r_coords) + l_coords = l_coords.concat(l_coords) + } + // reverse left coords, so that coords closest to arena is used first + l_coords = l_coords.reverse() + + // shuffle stimuli, so that starting positions are random + trial.stimuli = shuffle(trial.stimuli); + + let inside = [] + for (let i = 0; i < trial.stimuli.length; i++) { + let coords = [] + if ( (i % 2) == 0 ) { + coords = r_coords[Math.floor(i * .5)]; + } else { + coords = l_coords[Math.floor(i * .5)]; + } display_element.querySelector("#jspsych-free-sort-arena").innerHTML += ''+ ''; @@ -112,31 +180,74 @@ jsPsych.plugins['free-sort'] = (function() { "x": coords.x, "y": coords.y }); + inside.push(false); } + // moves within a trial + let moves = []; - display_element.innerHTML += ''; + // are objects currently inside + let cur_in = false - var maxz = 1; + // draggable items + const draggables = display_element.querySelectorAll('.jspsych-free-sort-draggable'); - var moves = []; + // button (will show when all items are inside) and border (will change color) + const border = display_element.querySelector("#jspsych-free-sort-border") + const button = display_element.querySelector('#jspsych-free-sort-done-btn') - var draggables = display_element.querySelectorAll('.jspsych-free-sort-draggable'); - - for(var i=0;i 1 ) { + display_element.querySelector("#jspsych-free-sort-counter").innerHTML = "You still need to place " + (inside.length - inside.filter(Boolean).length) + " items inside the arena." + } else { + display_element.querySelector("#jspsych-free-sort-counter").innerHTML = "You still need to place " + (inside.length - inside.filter(Boolean).length) + " item inside the arena." + } + } } document.addEventListener('mousemove', mousemoveevent); var mouseupevent = function(e){ document.removeEventListener('mousemove', mousemoveevent); + elem.style.transform = "scale(1, 1)"; + if (inside.every(Boolean)) { + border.style.background = "#a1d99b"; + border.style.borderColor = "#a1d99b"; + } else { + border.style.background = "none"; + border.style.borderColor = "#fc9272"; + } moves.push({ "src": elem.dataset.src, "x": elem.offsetLeft, @@ -148,47 +259,86 @@ jsPsych.plugins['free-sort'] = (function() { }); } - display_element.querySelector('#jspsych-free-sort-done-btn').addEventListener('click', function(){ - - var end_time = performance.now(); - var rt = end_time - start_time; - // gather data - // get final position of all objects - var final_locations = []; - var matches = display_element.querySelectorAll('.jspsych-free-sort-draggable'); - for(var i=0; i Date: Sat, 29 Aug 2020 17:08:38 -0400 Subject: [PATCH 02/13] updated free-sort-example --- examples/jspsych-free-sort.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/jspsych-free-sort.html b/examples/jspsych-free-sort.html index 5b91d33f9b..91569bcc1f 100644 --- a/examples/jspsych-free-sort.html +++ b/examples/jspsych-free-sort.html @@ -10,7 +10,11 @@ var trials = { type: 'free-sort', - stimuli: ['img/happy_face_1.jpg','img/happy_face_2.jpg','img/happy_face_3.jpg','img/happy_face_4.jpg'] + stimuli: ['img/happy_face_1.jpg','img/happy_face_2.jpg','img/happy_face_3.jpg','img/happy_face_4.jpg'], + stim_height: 150, + stim_width: 200, + scale_factor: 1.3, + sort_area_shape: "ellipse" }; From c2132ab4d73c3c1160482bf7ed592b517100f274 Mon Sep 17 00:00:00 2001 From: "Peter J. Kohler" Date: Sat, 29 Aug 2020 17:13:05 -0400 Subject: [PATCH 03/13] updated free-sort docs --- docs/plugins/jspsych-free-sort.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/plugins/jspsych-free-sort.md b/docs/plugins/jspsych-free-sort.md index 2064915437..d55ee98845 100644 --- a/docs/plugins/jspsych-free-sort.md +++ b/docs/plugins/jspsych-free-sort.md @@ -15,13 +15,14 @@ Parameter | Type | Default Value | Description stimuli | array | *undefined* | Each element of this array is an image path. stim_height | numeric | 100 | The height of the images in pixels. stim_width | numeric | 100 | The width of the images in pixels. +scale_factor | numeric | 1.5 | How much larger to make the stimulus while moving (1 = no scaling). sort_area_height | numeric | 800 | The height of the container that subjects can move the stimuli in. Stimuli will be constrained to this area. sort_area_width | numeric | 800 | The width of the container that subjects can move the stimuli in. Stimuli will be constrained to this area. +sort_area_shape | string | "ellipse" | The shape of the sorting area, can be "ellipse" or "square". prompt | string | null | This string can contain HTML markup. 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). prompt_location | string | "above" | Indicates whether to show the prompt `"above"` or `"below"` the sorting area. button_label | string | 'Continue' | The text that appears on the button to continue to the next trial. - ## Data Generated In addition to the [default data collected by all plugins](overview#datacollectedbyplugins), this plugin collects the following data for each trial. From 5740d0a316d0147890b81d062635157ffefcd6e5 Mon Sep 17 00:00:00 2001 From: "Peter J. Kohler" Date: Sun, 30 Aug 2020 10:41:19 -0400 Subject: [PATCH 04/13] added my name to contributors --- contributors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contributors.md b/contributors.md index 9b5ad9b350..5651bdbe58 100644 --- a/contributors.md +++ b/contributors.md @@ -5,6 +5,7 @@ The following people have contributed to the development of jsPsych by writing c * Krisitn Diep - https://github.com/kristiyip * Becky Gilbert - https://github.com/becky-gilbert * Jana Klaus - https://github.com/janakl4us +* Peter Jes Kohler - https://github.com/pjkohler * Jonas Lambers * Shane Martin - https://github.com/shamrt * Adrian Oesch - https://github.com/adrianoesch From a1ca6a8406e5d72561c07b9ec25eedfdb2e1a49a Mon Sep 17 00:00:00 2001 From: "Peter J. Kohler" Date: Wed, 18 Nov 2020 19:41:43 -0500 Subject: [PATCH 05/13] fixed above/below --- examples/jspsych-free-sort.html | 3 ++- plugins/jspsych-free-sort.js | 41 ++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/jspsych-free-sort.html b/examples/jspsych-free-sort.html index 91569bcc1f..336d6a7f7d 100644 --- a/examples/jspsych-free-sort.html +++ b/examples/jspsych-free-sort.html @@ -14,7 +14,8 @@ stim_height: 150, stim_width: 200, scale_factor: 1.3, - sort_area_shape: "ellipse" + sort_area_shape: "ellipse", + prompt_location: "below" }; diff --git a/plugins/jspsych-free-sort.js b/plugins/jspsych-free-sort.js index f3af378484..80ff49d8d9 100644 --- a/plugins/jspsych-free-sort.js +++ b/plugins/jspsych-free-sort.js @@ -64,7 +64,7 @@ jsPsych.plugins['free-sort'] = (function() { prompt: { type: jsPsych.plugins.parameterType.STRING, pretty_name: 'Prompt', - default: null, + default: '', description: 'It can be used to provide a reminder about the action the subject is supposed to take.' }, prompt_location: { @@ -87,15 +87,34 @@ jsPsych.plugins['free-sort'] = (function() { var start_time = performance.now(); - var html = + let html = '
'; + // another div for border + html += '
You still need to place ' + trial.stimuli.length + ' items inside the arena.

' + + '

You still need to place ' + trial.stimuli.length + ' items inside the arena.

'+ '
' @@ -106,23 +125,9 @@ jsPsych.plugins['free-sort'] = (function() { html = html_text + html } + console.log(html) display_element.innerHTML = html; - // another div for border - let border_div = '
Date: Thu, 19 Nov 2020 14:40:44 -0800 Subject: [PATCH 06/13] update expected regex to handle plugin modifications --- tests/plugins/plugin-free-sort.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/plugins/plugin-free-sort.test.js b/tests/plugins/plugin-free-sort.test.js index 6f578042a3..a8294cc1aa 100644 --- a/tests/plugins/plugin-free-sort.test.js +++ b/tests/plugins/plugin-free-sort.test.js @@ -59,7 +59,7 @@ describe('free-sort plugin', function(){ auto_preload: false }); - expect(jsPsych.getDisplayElement().innerHTML).toMatch(new RegExp('This is a prompt

')); + expect(jsPsych.getDisplayElement().innerHTML).toMatch(new RegExp('')); }); }); From 7782eb2e3aa37cc85ab7a57525bb38409ac11ba3 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 14:54:19 -0800 Subject: [PATCH 07/13] minor tweaks to wording, remove jQuery dependency --- docs/plugins/jspsych-free-sort.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plugins/jspsych-free-sort.md b/docs/plugins/jspsych-free-sort.md index 1d9ba5bbe4..6a209e5bf9 100644 --- a/docs/plugins/jspsych-free-sort.md +++ b/docs/plugins/jspsych-free-sort.md @@ -1,6 +1,6 @@ # jspsych-free-sort plugin -The free-sort plugin displays a collection of images on the screen that the subject can interact with by clicking and dragging. All of the moves that the subject performs are recorded. +The free-sort plugin displays one or more images on the screen that the participant can interact with by clicking and dragging. All images must be moved into the sorting area before the participant can click a button to end the trial. All of the moves that the participant performs are recorded, as well as the final positions of all images. This plugin could be useful when asking participants to position images based on similarity to one another, or to recall image spatial locations. ## Dependency @@ -16,10 +16,10 @@ stimuli | array | *undefined* | Each element of this array is an image path. stim_height | numeric | 100 | The height of the images in pixels. stim_width | numeric | 100 | The width of the images in pixels. scale_factor | numeric | 1.5 | How much larger to make the stimulus while moving (1 = no scaling). -sort_area_height | numeric | 800 | The height of the container that subjects can move the stimuli in. Stimuli will be constrained to this area. -sort_area_width | numeric | 800 | The width of the container that subjects can move the stimuli in. Stimuli will be constrained to this area. +sort_area_height | numeric | 800 | The height of the container that participants can move the stimuli in. Stimuli will be constrained to this area. +sort_area_width | numeric | 800 | The width of the container that participants can move the stimuli in. Stimuli will be constrained to this area. sort_area_shape | string | "ellipse" | The shape of the sorting area, can be "ellipse" or "square". -prompt | string | null | This string can contain HTML markup. 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). +prompt | string | null | This string can contain HTML markup. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., which key to press). prompt_location | string | "above" | Indicates whether to show the prompt `"above"` or `"below"` the sorting area. button_label | string | 'Continue' | The text that appears on the button to continue to the next trial. @@ -32,7 +32,7 @@ Name | Type | Value init_locations | JSON string | A JSON-encoded object representing the initial locations of all the stimuli in the sorting area. The object is an array with one element per stimulus. Each element in the array has a "src", "x", and "y" value. "src" is the image path, and "x" and "y" are the object location. moves | JSON string | A JSON-encoded object representing all of the moves the participant made when sorting. The object is an array with each element representing a move. Each element in the array has a "src", "x", and "y" value. "src" is the image path, and "x" and "y" are the object location after the move. final_locations | JSON string | A JSON-encoded object representing the final locations of all the stimuli in the sorting area. The object is an array with one element per stimulus. Each element in the array has a "src", "x", and "y" value. "src" is the image path, and "x" and "y" are the object location. -rt | numeric | The response time in milliseconds for the subject to finish all sorting. +rt | numeric | The response time in milliseconds for the participant to finish all sorting. ## Examples From b1b3e7d973d010550229609a7b58ecc7f32483f3 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 15:43:37 -0800 Subject: [PATCH 08/13] remove dependency text --- docs/plugins/jspsych-free-sort.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/plugins/jspsych-free-sort.md b/docs/plugins/jspsych-free-sort.md index 6a209e5bf9..a0b938e25d 100644 --- a/docs/plugins/jspsych-free-sort.md +++ b/docs/plugins/jspsych-free-sort.md @@ -2,10 +2,6 @@ The free-sort plugin displays one or more images on the screen that the participant can interact with by clicking and dragging. All images must be moved into the sorting area before the participant can click a button to end the trial. All of the moves that the participant performs are recorded, as well as the final positions of all images. This plugin could be useful when asking participants to position images based on similarity to one another, or to recall image spatial locations. -## Dependency - -This plugin requires the jQuery UI library, available at [https://jqueryui.com/](https://jqueryui.com/). You must include the library in the `` section of your experiment page. You can use the [Google-hosted version of the library](https://developers.google.com/speed/libraries/#jquery-ui). - ## Parameters Parameters with a default value of *undefined* must be specified. Other parameters can be left unspecified if the default value is acceptable. From 4c0dab012299c14c6748b558369480c0547db837 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 16:07:35 -0800 Subject: [PATCH 09/13] add new border/background color parameters --- docs/plugins/jspsych-free-sort.md | 6 +- plugins/jspsych-free-sort.js | 92 +++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/docs/plugins/jspsych-free-sort.md b/docs/plugins/jspsych-free-sort.md index a0b938e25d..fc4be64e7c 100644 --- a/docs/plugins/jspsych-free-sort.md +++ b/docs/plugins/jspsych-free-sort.md @@ -17,7 +17,11 @@ sort_area_width | numeric | 800 | The width of the container that participants c sort_area_shape | string | "ellipse" | The shape of the sorting area, can be "ellipse" or "square". prompt | string | null | This string can contain HTML markup. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., which key to press). prompt_location | string | "above" | Indicates whether to show the prompt `"above"` or `"below"` the sorting area. -button_label | string | 'Continue' | The text that appears on the button to continue to the next trial. +button_label | string | 'Continue' | The text that appears on the button to continue to the next trial. +change_border_background_color | boolean | true | If `true`, the sort area border color will change while items are being moved in and out of the sort area, and the background color will change once all items have been moved into the sort area. If `false`, the border will remain black and the background will remain white throughout the trial. +border_color_in | string | '#a1d99b' | If `change_border_background_color` is `true`, the sort area border will change to this color when an item is being moved into the sort area, and the background will change to this color when all of the items have been moved into the sort area. +border_color_out | string | '#fc9272' | If `change_border_background_color` is `true`, this will be the color of the sort area border when there are one or more items that still need to be moved into the sort area. +border_width | numeric | null | The width in pixels of the border around the sort area. If `null`, the border width will be 3% of the `sort_area_height`. ## Data Generated diff --git a/plugins/jspsych-free-sort.js b/plugins/jspsych-free-sort.js index 80ff49d8d9..f13d7b294b 100644 --- a/plugins/jspsych-free-sort.js +++ b/plugins/jspsych-free-sort.js @@ -46,13 +46,13 @@ jsPsych.plugins['free-sort'] = (function() { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Sort area height', default: 800, - description: 'The height of the container that subjects can move the stimuli in.' + description: 'The height in pixels of the container that subjects can move the stimuli in.' }, sort_area_width: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Sort area width', default: 800, - description: 'The width of the container that subjects can move the stimuli in.' + description: 'The width in pixels of the container that subjects can move the stimuli in.' }, sort_area_shape: { type: jsPsych.plugins.parameterType.STRING, @@ -77,8 +77,38 @@ jsPsych.plugins['free-sort'] = (function() { button_label: { type: jsPsych.plugins.parameterType.STRING, pretty_name: 'Button label', - default: 'continue', + default: 'Continue', description: 'The text that appears on the button to continue to the next trial.' + }, + change_border_background_color: { + type: jsPsych.plugins.parameterType.BOOL, + pretty_name: 'Change border background color', + default: true, + description: 'If true, the sort area border color will change while items are being moved in and out of '+ + 'the sort area, and the background color will change once all items have been moved into the '+ + 'sort area. If false, the border will remain black and the background will remain white throughout the trial.' + }, + border_color_in: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Border color - in', + default: '#a1d99b', + description: 'If change_border_background_color is true, the sort area border will change to this color '+ + 'when an item is being moved into the sort area, and the background will change to this color '+ + 'when all of the items have been moved into the sort area.' + }, + border_color_out: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Border color - out', + default: '#fc9272', + description: 'If change_border_background_color is true, this will be the color of the sort area border '+ + 'when there are one or more items that still need to be moved into the sort area.' + }, + border_width: { + type: jsPsych.plugins.parameterType.INT, + pretty_name: 'Border width', + default: null, + description: 'The width in pixels of the border around the sort area. If null, the border width '+ + 'defaults to 3% of the sort area height.' } } } @@ -87,6 +117,14 @@ jsPsych.plugins['free-sort'] = (function() { var start_time = performance.now(); + if (trial.change_border_background_color == false) { + trial.border_color_out = "#000000"; + } + + if (trial.border_width == null) { + trial.border_width = trial.sort_area_height*.03; + } + let html = '
You still need to place ' + trial.stimuli.length + ' items inside the arena.

'+ '
' + 'style="display: none; margin: 5px; padding: 5px; text-align: center; font-weight: bold; font-size: 18px; vertical-align:baseline; line-height: 1em">' + + trial.button_label+'
' // position prompt above or below if (trial.prompt_location == "below") { @@ -125,7 +165,6 @@ jsPsych.plugins['free-sort'] = (function() { html = html_text + html } - console.log(html) display_element.innerHTML = html; // store initial location data @@ -176,7 +215,7 @@ jsPsych.plugins['free-sort'] = (function() { 'data-src="'+trial.stimuli[i]+'" '+ 'class="jspsych-free-sort-draggable" '+ 'draggable="false" '+ - 'id="'+i+'" '+ + 'id="jspsych-free-sort-draggable-'+i+'" '+ 'style="position: absolute; cursor: move; width:'+trial.stim_width+'px; height:'+trial.stim_height+'px; top:'+coords.y+'px; left:'+coords.x+'px;">'+ ''; @@ -215,20 +254,25 @@ jsPsych.plugins['free-sort'] = (function() { elem.style.left = Math.min(trial.sort_area_width*1.5 - trial.stim_width, Math.max(-trial.sort_area_width*.5, (e.clientX - x)))+ 'px'; // modify border while items is being moved - if (cur_in) { - border.style.borderColor = "#a1d99b"; - border.style.background = "None"; - } else { - border.style.borderColor = "#fc9272"; - border.style.background = "None"; + if (trial.change_border_background_color) { + if (cur_in) { + border.style.borderColor = trial.border_color_in; + border.style.background = "None"; + } else { + border.style.borderColor = trial.border_color_out; + border.style.background = "None"; + } } - // replace in overall array, grab idx from item id - inside.splice(elem.id, true, cur_in) + // replace in overall array, grab index from item id + var elem_number = elem.id.split("jspsych-free-sort-draggable-")[1]; + inside.splice(elem_number, true, cur_in) // modify text and background if all items are inside if (inside.every(Boolean)) { - border.style.background = "#a1d99b"; + if (trial.change_border_background_color) { + border.style.background = trial.border_color_in; + } button.style.display = "inline-block"; display_element.querySelector("#jspsych-free-sort-counter").innerHTML = "All items placed. Feel free to reposition any item if necessary. Otherwise, click here to " } else { @@ -246,12 +290,14 @@ jsPsych.plugins['free-sort'] = (function() { var mouseupevent = function(e){ document.removeEventListener('mousemove', mousemoveevent); elem.style.transform = "scale(1, 1)"; - if (inside.every(Boolean)) { - border.style.background = "#a1d99b"; - border.style.borderColor = "#a1d99b"; - } else { - border.style.background = "none"; - border.style.borderColor = "#fc9272"; + if (trial.change_border_background_color) { + if (inside.every(Boolean)) { + border.style.background = "#a1d99b"; + border.style.borderColor = "#a1d99b"; + } else { + border.style.background = "none"; + border.style.borderColor = "#fc9272"; + } } moves.push({ "src": elem.dataset.src, From 8cc2454cfd9e5ba47e98e2f3b858be76c0a17470 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 18:22:08 -0800 Subject: [PATCH 10/13] add counter text and stim_starts_inside parameters --- docs/plugins/jspsych-free-sort.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/plugins/jspsych-free-sort.md b/docs/plugins/jspsych-free-sort.md index fc4be64e7c..992176242b 100644 --- a/docs/plugins/jspsych-free-sort.md +++ b/docs/plugins/jspsych-free-sort.md @@ -1,6 +1,6 @@ # jspsych-free-sort plugin -The free-sort plugin displays one or more images on the screen that the participant can interact with by clicking and dragging. All images must be moved into the sorting area before the participant can click a button to end the trial. All of the moves that the participant performs are recorded, as well as the final positions of all images. This plugin could be useful when asking participants to position images based on similarity to one another, or to recall image spatial locations. +The free-sort plugin displays one or more images on the screen that the participant can interact with by clicking and dragging. When the trial starts, the images can be positioned outside or inside the sort area. All images must be moved into the sorting area before the participant can click a button to end the trial. All of the moves that the participant performs are recorded, as well as the final positions of all images. This plugin could be useful when asking participants to position images based on similarity to one another, or to recall image spatial locations. ## Parameters @@ -22,6 +22,9 @@ change_border_background_color | boolean | true | If `true`, the sort area borde border_color_in | string | '#a1d99b' | If `change_border_background_color` is `true`, the sort area border will change to this color when an item is being moved into the sort area, and the background will change to this color when all of the items have been moved into the sort area. border_color_out | string | '#fc9272' | If `change_border_background_color` is `true`, this will be the color of the sort area border when there are one or more items that still need to be moved into the sort area. border_width | numeric | null | The width in pixels of the border around the sort area. If `null`, the border width will be 3% of the `sort_area_height`. +counter_text_unfinished | string | You still need to place %n% item%s% inside the sort area. | Text to display when there are one or more items that still need to be placed in the sort area. If "%n%" is included in the string, it will be replaced with the number of items that still need to be moved inside. If "%s%" is included in the string, a "s" will be included when the number of items remaining is greater than one. +counter_text_finished | string | All items placed. Feel free to reposition items if necessary. | Text that will take the place of the counter_text_unfinished text when all items have been moved inside the sort area. +stim_starts_inside | boolean | false | If `false`, the images will be positioned to the left and right of the sort area when the trial loads. If `true`, the images will be positioned at random locations inside the sort area when the trial loads. ## Data Generated From dc00efd0ea170491d0c7ff517d619cec6423edd3 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 18:24:44 -0800 Subject: [PATCH 11/13] add counter text and stim_starts_inside params, fix missed hardcoded colors --- plugins/jspsych-free-sort.js | 173 ++++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 62 deletions(-) diff --git a/plugins/jspsych-free-sort.js b/plugins/jspsych-free-sort.js index f13d7b294b..6176907125 100644 --- a/plugins/jspsych-free-sort.js +++ b/plugins/jspsych-free-sort.js @@ -45,13 +45,13 @@ jsPsych.plugins['free-sort'] = (function() { sort_area_height: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Sort area height', - default: 800, + default: 700, description: 'The height in pixels of the container that subjects can move the stimuli in.' }, sort_area_width: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Sort area width', - default: 800, + default: 700, description: 'The width in pixels of the container that subjects can move the stimuli in.' }, sort_area_shape: { @@ -109,6 +109,27 @@ jsPsych.plugins['free-sort'] = (function() { default: null, description: 'The width in pixels of the border around the sort area. If null, the border width '+ 'defaults to 3% of the sort area height.' + }, + counter_text_unfinished: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Counter text unfinished', + default: 'You still need to place %n% item%s% inside the sort area.', + description: 'Text to display when there are one or more items that still need to be placed in the sort area. '+ + 'If "%n%" is included in the string, it will be replaced with the number of items that still need to be moved inside. '+ + 'If "%s%" is included in the string, a "s" will be included when the number of items remaining is greater than one.' + }, + counter_text_finished: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Counter text finished', + default: 'All items placed. Feel free to reposition items if necessary.', + description: 'Text that will take the place of the counter_text_unfinished text when all items have been moved inside the sort area.' + }, + stim_starts_inside: { + type: jsPsych.plugins.parameterType.BOOL, + pretty_name: 'Stim starts inside', + default: false, + description: 'If false, the images will be positioned to the left and right of the sort area when the trial loads. '+ + 'If true, the images will be positioned at random locations inside the sort area when the trial loads.' } } } @@ -129,7 +150,7 @@ jsPsych.plugins['free-sort'] = (function() { '
'; + 'style="position: relative; width:'+trial.sort_area_width+'px; height:'+trial.sort_area_height+'px; margin: auto;"
'; // another div for border html += '
You still need to place ' + trial.stimuli.length + ' items inside the arena.

'+ - '
' + // variable that has the prompt text and counter + const html_text = '
' + trial.prompt + + '

'+get_counter_text(trial.stimuli.length)+'

'; // position prompt above or below if (trial.prompt_location == "below") { @@ -164,52 +175,63 @@ jsPsych.plugins['free-sort'] = (function() { } else { html = html_text + html } + // add button + html += '
'; display_element.innerHTML = html; // store initial location data let init_locations = []; - // determine number of rows and colums, must be a even number - let num_rows = Math.ceil(Math.sqrt(trial.stimuli.length)) - if ( num_rows % 2 != 0) { - num_rows = num_rows + 1 - } + if (!trial.stim_starts_inside) { + // determine number of rows and colums, must be a even number + let num_rows = Math.ceil(Math.sqrt(trial.stimuli.length)) + if ( num_rows % 2 != 0) { + num_rows = num_rows + 1 + } - // compute coords for left and right side of arena - let r_coords = []; - let l_coords = []; - for (const x of make_arr(0, trial.sort_area_width - trial.stim_width, num_rows) ) { - for (const y of make_arr(0, trial.sort_area_height - trial.stim_height, num_rows) ) { - if ( x > ( (trial.sort_area_width - trial.stim_width) * .5 ) ) { - //r_coords.push({ x:x, y:y } ) - r_coords.push({ x:x + (trial.sort_area_width) * .5 , y:y }); - } else { - l_coords.push({ x:x - (trial.sort_area_width) * .5 , y:y }); - //l_coords.push({ x:x, y:y } ) + // compute coords for left and right side of arena + var r_coords = []; + var l_coords = []; + for (const x of make_arr(0, trial.sort_area_width - trial.stim_width, num_rows) ) { + for (const y of make_arr(0, trial.sort_area_height - trial.stim_height, num_rows) ) { + if ( x > ( (trial.sort_area_width - trial.stim_width) * .5 ) ) { + //r_coords.push({ x:x, y:y } ) + r_coords.push({ x:x + (trial.sort_area_width) * .5 , y:y }); + } else { + l_coords.push({ x:x - (trial.sort_area_width) * .5 , y:y }); + //l_coords.push({ x:x, y:y } ) + } } } - } - // repeat coordinates until you have enough coords (may be obsolete) - while ( ( r_coords.length + l_coords.length ) < trial.stimuli.length ) { - r_coords = r_coords.concat(r_coords) - l_coords = l_coords.concat(l_coords) - } - // reverse left coords, so that coords closest to arena is used first - l_coords = l_coords.reverse() + // repeat coordinates until you have enough coords (may be obsolete) + while ( ( r_coords.length + l_coords.length ) < trial.stimuli.length ) { + r_coords = r_coords.concat(r_coords) + l_coords = l_coords.concat(l_coords) + } + // reverse left coords, so that coords closest to arena is used first + l_coords = l_coords.reverse() - // shuffle stimuli, so that starting positions are random - trial.stimuli = shuffle(trial.stimuli); + // shuffle stimuli, so that starting positions are random + trial.stimuli = shuffle(trial.stimuli); + } let inside = [] for (let i = 0; i < trial.stimuli.length; i++) { - let coords = [] - if ( (i % 2) == 0 ) { - coords = r_coords[Math.floor(i * .5)]; + var coords; + if (trial.stim_starts_inside) { + coords = random_coordinate(trial.sort_area_width - trial.stim_width, trial.sort_area_height - trial.stim_height); } else { - coords = l_coords[Math.floor(i * .5)]; + if ( (i % 2) == 0 ) { + coords = r_coords[Math.floor(i * .5)]; + } else { + coords = l_coords[Math.floor(i * .5)]; + } } + display_element.querySelector("#jspsych-free-sort-arena").innerHTML += ' 1 ) { - display_element.querySelector("#jspsych-free-sort-counter").innerHTML = "You still need to place " + (inside.length - inside.filter(Boolean).length) + " items inside the arena." - } else { - display_element.querySelector("#jspsych-free-sort-counter").innerHTML = "You still need to place " + (inside.length - inside.filter(Boolean).length) + " item inside the arena." - } + button.style.visibility = "hidden"; + display_element.querySelector("#jspsych-free-sort-counter").innerHTML = get_counter_text(inside.length - inside.filter(Boolean).length); } } document.addEventListener('mousemove', mousemoveevent); @@ -292,11 +327,11 @@ jsPsych.plugins['free-sort'] = (function() { elem.style.transform = "scale(1, 1)"; if (trial.change_border_background_color) { if (inside.every(Boolean)) { - border.style.background = "#a1d99b"; - border.style.borderColor = "#a1d99b"; + border.style.background = trial.border_color_in; + border.style.borderColor = trial.border_color_in; } else { border.style.background = "none"; - border.style.borderColor = "#fc9272"; + border.style.borderColor = trial.border_color_out; } } moves.push({ @@ -338,6 +373,23 @@ jsPsych.plugins['free-sort'] = (function() { jsPsych.finishTrial(trial_data); } }); + + function get_counter_text(n) { + var text_out = ''; + var text_bits = trial.counter_text_unfinished.split("%"); + for (var i=0; i 1) { + text_out += "s"; + } + } + } + return text_out; + } }; // helper functions @@ -379,9 +431,6 @@ jsPsych.plugins['free-sort'] = (function() { return result } - /* - un-used functions (that might be useful for something else) - function random_coordinate(max_width, max_height) { const rnd_x = Math.floor(Math.random() * (max_width - 1)); const rnd_y = Math.floor(Math.random() * (max_height - 1)); @@ -390,6 +439,6 @@ jsPsych.plugins['free-sort'] = (function() { y: rnd_y }; } - */ + return plugin; })(); From a7bed07cf445161d2a0f624b462f6deeb7351327 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 19 Nov 2020 18:25:48 -0800 Subject: [PATCH 12/13] add examples to demo new parameters --- examples/jspsych-free-sort.html | 80 ++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/examples/jspsych-free-sort.html b/examples/jspsych-free-sort.html index 387c09920d..2d2a318a03 100644 --- a/examples/jspsych-free-sort.html +++ b/examples/jspsych-free-sort.html @@ -3,24 +3,92 @@ +