diff --git a/package-lock.json b/package-lock.json
index fa191c1248..802a138858 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "jsPsych",
+ "name": "plugin-drag-and-drop",
"lockfileVersion": 3,
"requires": true,
"packages": {
@@ -10491,7 +10491,7 @@
"node": ">=8"
}
},
- "node_modules/plugin-free-sort-ordered": {
+ "node_modules/plugin-snap-sort": {
"resolved": "packages/plugin-free-sort-ordered",
"link": true
},
@@ -14031,6 +14031,7 @@
}
},
"packages/plugin-free-sort-ordered": {
+ "name": "plugin-snap-sort",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
diff --git a/packages/plugin-free-sort-ordered/README.md b/packages/plugin-free-sort-ordered/README.md
index 3aae816722..d8eee38e7d 100644
--- a/packages/plugin-free-sort-ordered/README.md
+++ b/packages/plugin-free-sort-ordered/README.md
@@ -18,4 +18,4 @@ See [documentation](/packages/plugin-free-sort-ordered/README.md)
## Author / Citation
-[Cherrie Chang](https://github.com/cherriechang)
\ No newline at end of file
+[Cherrie Chang](https://github.com/cherriechang)
diff --git a/packages/plugin-free-sort-ordered/assets/green-circle.png b/packages/plugin-free-sort-ordered/assets/green-circle.png
new file mode 100644
index 0000000000..83111fa885
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/green-circle.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/green-square.png b/packages/plugin-free-sort-ordered/assets/green-square.png
new file mode 100644
index 0000000000..76a2ec2a5f
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/green-square.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/green-triangle.png b/packages/plugin-free-sort-ordered/assets/green-triangle.png
new file mode 100644
index 0000000000..ef15a9b31c
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/green-triangle.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/index.html b/packages/plugin-free-sort-ordered/assets/index.html
new file mode 100644
index 0000000000..cdd7d1e629
--- /dev/null
+++ b/packages/plugin-free-sort-ordered/assets/index.html
@@ -0,0 +1,50 @@
+
+
+
+ jsPsychPluginFreeSortOrdered Example
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/plugin-free-sort-ordered/assets/orange-circle.png b/packages/plugin-free-sort-ordered/assets/orange-circle.png
new file mode 100644
index 0000000000..30588808f2
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/orange-circle.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/orange-square.png b/packages/plugin-free-sort-ordered/assets/orange-square.png
new file mode 100644
index 0000000000..4393a468d2
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/orange-square.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/orange-triangle.png b/packages/plugin-free-sort-ordered/assets/orange-triangle.png
new file mode 100644
index 0000000000..a1b47f112c
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/orange-triangle.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/purple-circle.png b/packages/plugin-free-sort-ordered/assets/purple-circle.png
new file mode 100644
index 0000000000..cb1fa8beb3
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/purple-circle.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/purple-square.png b/packages/plugin-free-sort-ordered/assets/purple-square.png
new file mode 100644
index 0000000000..667a576f45
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/purple-square.png differ
diff --git a/packages/plugin-free-sort-ordered/assets/purple-triangle.png b/packages/plugin-free-sort-ordered/assets/purple-triangle.png
new file mode 100644
index 0000000000..202633a4e5
Binary files /dev/null and b/packages/plugin-free-sort-ordered/assets/purple-triangle.png differ
diff --git a/packages/plugin-free-sort-ordered/examples/index.html b/packages/plugin-free-sort-ordered/examples/index.html
index 01c0ca56cb..811d827d23 100644
--- a/packages/plugin-free-sort-ordered/examples/index.html
+++ b/packages/plugin-free-sort-ordered/examples/index.html
@@ -3,6 +3,7 @@
jsPsychPluginFreeSortOrdered Example
+
@@ -13,27 +14,130 @@
diff --git a/packages/plugin-free-sort-ordered/examples/index_demo.html b/packages/plugin-free-sort-ordered/examples/index_demo.html
new file mode 100644
index 0000000000..187222be4c
--- /dev/null
+++ b/packages/plugin-free-sort-ordered/examples/index_demo.html
@@ -0,0 +1,245 @@
+
+
+
+ jsPsychPluginSnapSort Example
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/plugin-free-sort-ordered/examples/index_min.html b/packages/plugin-free-sort-ordered/examples/index_min.html
new file mode 100644
index 0000000000..24fda45d53
--- /dev/null
+++ b/packages/plugin-free-sort-ordered/examples/index_min.html
@@ -0,0 +1,130 @@
+
+
+
+ jsPsychPluginSnapSort Example
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/plugin-free-sort-ordered/package.json b/packages/plugin-free-sort-ordered/package.json
index b94f167626..19a57ed6ab 100644
--- a/packages/plugin-free-sort-ordered/package.json
+++ b/packages/plugin-free-sort-ordered/package.json
@@ -1,5 +1,5 @@
{
- "name": "plugin-free-sort-ordered",
+ "name": "plugin-snap-sort",
"version": "0.0.1",
"description": "The free sort core plugin, but the images have to be sorted by placing into ordered boxes.",
"type": "module",
diff --git a/packages/plugin-free-sort-ordered/rollup.config.mjs b/packages/plugin-free-sort-ordered/rollup.config.mjs
index f324dcee1c..284f6ba991 100644
--- a/packages/plugin-free-sort-ordered/rollup.config.mjs
+++ b/packages/plugin-free-sort-ordered/rollup.config.mjs
@@ -1,3 +1,3 @@
import { makeRollupConfig } from "@jspsych/config/rollup";
-export default makeRollupConfig("jsPsychPluginFreeSortOrdered");
+export default makeRollupConfig("jsPsychPluginSnapSort");
diff --git a/packages/plugin-free-sort-ordered/src/index.spec.ts b/packages/plugin-free-sort-ordered/src/index.spec.ts
index 5ad9b4bb20..c2c72aa5cf 100644
--- a/packages/plugin-free-sort-ordered/src/index.spec.ts
+++ b/packages/plugin-free-sort-ordered/src/index.spec.ts
@@ -1,6 +1,6 @@
import { startTimeline } from "@jspsych/test-utils";
-import jsPsychPluginFreeSortOrdered from ".";
+import jsPsychPluginSnapSort from ".";
jest.useFakeTimers();
@@ -8,7 +8,7 @@ describe("my plugin", () => {
it("should load", async () => {
const { expectFinished, getHTML, getData, displayElement, jsPsych } = await startTimeline([
{
- type: jsPsychPluginFreeSortOrdered,
+ type: jsPsychPluginSnapSort,
parameter_name: 1,
parameter_name2: "img.png",
},
diff --git a/packages/plugin-free-sort-ordered/src/index.ts b/packages/plugin-free-sort-ordered/src/index.ts
index b755940a5b..1d718996c2 100644
--- a/packages/plugin-free-sort-ordered/src/index.ts
+++ b/packages/plugin-free-sort-ordered/src/index.ts
@@ -6,45 +6,67 @@ import { version } from "../package.json";
import * as Utils from "./utils";
const info = {
- name: "plugin-free-sort-ordered",
+ name: "plugin-snap-sort",
version: version,
parameters: {
- /** Each element of this array is an image path or SVG code. */
stimulus: {
- type: ParameterType.INT | ParameterType.HTML_STRING,
+ type: ParameterType.COMPLEX,
default: undefined,
array: true,
},
- /** The height of the images in pixels. */
- stim_height: {
- type: ParameterType.INT,
- default: 100,
- },
- /** The width of the images in pixels. */
- stim_width: {
- type: ParameterType.INT,
- default: 100,
- },
- /** The correct order of the stimuli. */
- stim_order: {
- type: ParameterType.INT,
+ boxes: {
+ type: ParameterType.COMPLEX,
default: undefined,
array: true,
},
/** How much larger to make the stimulus while moving (1 = no scaling). */
scale_factor: {
type: ParameterType.FLOAT,
- default: 1.5,
+ default: 1.25,
+ },
+ /** The location of the holding area relative to the box grid. */
+ holding_area_location: {
+ type: ParameterType.SELECT,
+ options: ["above", "below", "left", "right"],
+ default: "below",
+ },
+ holding_background_color: {
+ type: ParameterType.STRING,
+ default: "#CCCCCC",
+ },
+ /** Checks if the stimuli are placed in the correct order, as determined by box_colors. */
+ use_correctness: {
+ type: ParameterType.BOOL,
+ default: false,
},
- /** The height of the container that the stimuli start in. */
- holding_area_height: {
+ /** How close to the box does the drag need to be to snap. */
+ snap_margin: {
type: ParameterType.INT,
- default: 700,
+ default: 10,
+ },
+ /** The margin between the boxes in pixels. */
+ box_background_color: {
+ type: ParameterType.STRING,
+ default: "#FFFFFF",
},
- /** The width of the container that the stimuli start in. */
- holding_area_width: {
+ box_margin: {
type: ParameterType.INT,
- default: 700,
+ default: 20,
+ },
+ /** The colour the boxes go when the stimulus is nearby */
+ box_hover_color: {
+ type: ParameterType.STRING,
+ default: "#90EE90",
+ },
+ /** Whether multiple stimuli can be placed in the same box. If true, items in a box with multiple occupants will be scaled down. */
+ allow_multiple_per_box: {
+ type: ParameterType.BOOL,
+ default: false,
+ },
+ // TODO
+ reject_wrong_moves: {
+ type: ParameterType.BOOL,
+ default: false,
},
/** 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: {
@@ -62,16 +84,36 @@ const info = {
type: ParameterType.STRING,
default: "Continue",
},
- /** Whether to display counter indicating how many items are left to be sorted. */
- include_counter: {
+ /** When to show the button */
+ show_button: {
type: ParameterType.BOOL,
default: true,
},
+ use_criteria: {
+ type: ParameterType.STRING,
+ default: ["none"],
+ array: true, // "none", "correct_answers", "all_items_sorted", "all_boxes_used"
+ },
+ /** How long to wait for the participant to make a response before ending the trial in milliseconds. If the participant fails to make a response before this timer is reached, the participant's response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, the trial will wait for a response indefinitely. */
+ trial_duration: {
+ type: ParameterType.INT,
+ default: null,
+ },
+ /** If true, then the trial will end whenever the participant 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 participant to view a stimulus for a fixed amount of time, even if they respond before the time is complete. */
+ response_ends_trial: {
+ type: ParameterType.BOOL,
+ default: false,
+ },
/**
* Text to display when there are one or more items that still need to be placed in a box.
* 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.
*/
+ /** Whether to display counter indicating how many items are left to be sorted. */
+ include_counter: {
+ type: ParameterType.BOOL,
+ default: true,
+ },
counter_text_unfinished: {
type: ParameterType.HTML_STRING,
default: "You still need to place %n% item%s% in a box.",
@@ -104,6 +146,7 @@ const info = {
},
},
},
+ /** An array containing objects representing the final locations of all the stimuli in the sorting area. Each element in the array represents a stimulus, and has a "src", "x", and "y" value. "src" is the image path, and "x" and "y" are the object location. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */
final_locations: {
type: ParameterType.COMPLEX,
array: true,
@@ -130,72 +173,130 @@ const info = {
type Info = typeof info;
/**
- * **plugin-free-sort-ordered**
+ * **plugin-snap-sort**
*
* The free sort core plugin, but the images have to be sorted by placing into ordered boxes.
*
* @author Cherrie Chang
* @see {@link /packages/plugin-free-sort-ordered/README.md}}
*/
-class FreeSortOrderedPlugin implements JsPsychPlugin {
+class SnapSortPlugin implements JsPsychPlugin {
static info = info;
constructor(private jsPsych: JsPsych) {}
trial(display_element: HTMLElement, trial: TrialType) {
var start_time = performance.now();
+ var boxes = trial.boxes;
var stimulus = trial.stimulus;
+ /** Height and width of the holding area depending on the location **/
+ if (trial.holding_area_location === "above" || trial.holding_area_location === "below") {
+ var holding_area_width = 90;
+ var holding_area_height = 35;
+ var box_grid_width = 90;
+ var box_grid_height = 35;
+ var hold_margin = "1em 2em 1em 2em"; // margin for the holding area
+ var grid_margin = "1em 2em 1em 2em"; // margin for the box grid
+ } else {
+ var holding_area_width = 35;
+ var holding_area_height = 70;
+ var box_grid_width = 35;
+ var box_grid_height = 70;
+ var hold_margin = "2em 1em 2em 1em"; // margin for the holding area
+ var grid_margin = "2em 1em 2em 1em"; // margin for the box grid
+ }
+
// holding area
const holding_area_html = `
`;
// container for the target boxes
let box_container_html = `
`;
// create boxes for each stimulus
- for (let i = 0; i < stimulus.length; i++) {
+ let box_order = this.jsPsych.randomization.shuffle(boxes.map((box) => box.id));
+ // stimulus order defaults to array length number of stimuli 0, 1, 2...
+ let stim_order = Array.from({ length: stimulus.length }, (_, i) => i);
+ // get the correct stimulus order based on the box order (i.e., what the inside array needs to match)
+ if (trial.use_correctness && trial.correctness_by !== null) {
+ // if using correctness, we need to get the order of the boxes based on the stimuli
+ stim_order = stimulus.map((stimulus) => box_order.indexOf(stimulus.correct_box_id));
+ }
+ for (let i = 0; i < boxes.length; i++) {
box_container_html += `
`;
}
box_container_html += "
";
// prompt text (and counter if included)
const prompt_counter_html = `
-