Skip to content

Commit

Permalink
merge main into v8
Browse files Browse the repository at this point in the history
  • Loading branch information
jadeddelta committed Jan 29, 2025
2 parents d99177a + 2fed803 commit df7748e
Show file tree
Hide file tree
Showing 19 changed files with 218 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Update README list of plugins and extensions
run: npm run update-readme.js
run: npm run update-readme

74 changes: 42 additions & 32 deletions README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { updateUnpkgLinks } from "@jspsych/config/gulp";

export { default as updateReadme } from "./update-readme.js";
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"test:watch": "npm test -- --watch",
"build": "npm run build -ws",
"update-unpkg-links": "gulp updateUnpkgLinks",
"update-readme": "node ./update-readme.js",
"update-readme": "gulp updateReadme",
"prepare": "husky install",
"changeset": "changeset",
"changeset:version": "changeset version && npm install && npm run update-unpkg-links && npm run update-readme",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>Experiment</title>
<script src="https://unpkg.com/jspsych@8"></script>
<script src="https://unpkg.com/@jspsych-contrib/[email protected]"></script>
<script src="https://unpkg.com/@jspsych-contrib/plugin-rdk@1.1.0"></script>
<script src="https://unpkg.com/@jspsych-contrib/plugin-rdk@1.2.0"></script>
<script src="https://unpkg.com/@jspsych/plugin-html-keyboard-response@2"></script>
<script src="https://unpkg.com/@jspsych/[email protected]"></script>
<script src="../index.js"></script>
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-html-swipe-response/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @jspsych-contrib/plugin-html-swipe-response

## 1.1.3

### Patch Changes

- [#136](https://github.com/jspsych/jspsych-contrib/pull/136) [`1e135ea6ccef00a8b8bb9b166ff01a1d8a80bb74`](https://github.com/jspsych/jspsych-contrib/commit/1e135ea6ccef00a8b8bb9b166ff01a1d8a80bb74) Thanks [@Emily-ejag](https://github.com/Emily-ejag)! - the patch ensures that both the container (`#jspsych-html-swipe-response-stimulus-container`) and the stimulus (`#jspsych-html-swipe-response-stimulus`) move together when dragged, providing a unified and seamless interaction.

## 1.1.2

### Patch Changes
Expand Down
4 changes: 3 additions & 1 deletion packages/plugin-html-swipe-response/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ This plugin displays HTML content and records responses generated by swipe gestu

Setting the `stimulus_duration` parameter while using the swipe modality can result in a user experience issue, wherein the user must swipe a stimulus div tag that has been hidden after the stimulus duration has elapsed. To solve this, this plugin wraps the stimulus div tag in another tag with the ID `#jspsych-html-swipe-response-stimulus-container`. This div tag can then be styled so that they user has some visual representation of the stimulus even after the `#jspsych-html-swipe-response-stimulus-container` div has been hidden.

The plugin now ensures that both the container (`#jspsych-html-swipe-response-stimulus-container`) and the stimulus (`#jspsych-html-swipe-response-stimulus`) move together when dragged, providing a unified and seamless interaction.

## Loading

```js
<script src="https://unpkg.com/@jspsych-contrib/[email protected].2"></script>
<script src="https://unpkg.com/@jspsych-contrib/[email protected].3"></script>
```

## Compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This plugin displays HTML content and records responses generated by swipe gestu

Setting the `stimulus_duration` parameter while using the swipe modality can result in a user experience issue, wherein the user must swipe a stimulus div tag that has been hidden after the stimulus duration has elapsed. To solve this, this plugin wraps the stimulus div tag in another tag with the ID `#jspsych-html-swipe-response-stimulus-container`. This div tag can then be styled so that they user has some visual representation of the stimulus even after the `#jspsych-html-swipe-response-stimulus-container` div has been hidden.

The plugin now ensures that both the container (`#jspsych-html-swipe-response-stimulus-container`) and the stimulus (`#jspsych-html-swipe-response-stimulus`) move together when dragged, providing a unified and seamless interaction.

## Parameters

In addition to the [parameters available in all plugins](https://www.jspsych.org/latest/overview/plugins/#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of *undefined* must be specified. Parameters can be left unspecified if the default value is acceptable.
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-html-swipe-response/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jspsych-contrib/plugin-html-swipe-response",
"version": "1.1.2",
"version": "1.1.3",
"description": "This plugin collects responses to an arbitrary HTML string using swipe gestures and keyboard responses.",
"type": "module",
"main": "dist/index.cjs",
Expand Down
30 changes: 30 additions & 0 deletions packages/plugin-html-swipe-response/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { clickTarget, pressKey, simulateTimeline, startTimeline } from "@jspsych/test-utils";
import interact from "interactjs";

import htmlSwipeResponse from ".";

Expand Down Expand Up @@ -292,6 +293,34 @@ describe("plugin-html-swipe-response", () => {
expect(element.getAttribute("disabled")).toBe("disabled");
});
});

test("should move container and stimulus together during drag", async () => {
const { displayElement } = await startTimeline([
{
type: htmlSwipeResponse,
stimulus: "this is html",
swipe_animation_duration: 0,
},
]);

const container = displayElement.querySelector<HTMLElement>(
"#jspsych-html-swipe-response-stimulus-container"
);
const stimulus = displayElement.querySelector<HTMLElement>(
"#jspsych-html-swipe-response-stimulus"
);

// Simulate drag event manually using interact.js drag events
interact(container).fire({
type: "dragmove",
target: container,
delta: { x: 100, y: 50 },
});

// Now test if the transforms are applied correctly
expect(container.style.transform).toBe("translate3D(100px, 50px, 0)");
expect(stimulus.style.transform).toBe("translate3D(100px, 50px, 0) rotate(20deg)");
});
});

describe("html-swipe-response simulation", () => {
Expand Down Expand Up @@ -347,6 +376,7 @@ describe("html-swipe-response simulation", () => {
const buttonResponse = getData().values()[0].button_response;
const keyboardResponse = getData().values()[0].keyboard_response;
const responseSource = getData().values()[0].response_source;

expect(getData().values()[0].rt).toBeGreaterThan(0);
if (responseSource == "keyboard") {
expect(typeof keyboardResponse).toBe("string");
Expand Down
91 changes: 55 additions & 36 deletions packages/plugin-html-swipe-response/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
source: null,
};

// References to container and stimulus
const container_div = document.getElementById("jspsych-html-swipe-response-stimulus-container");
const stimulus_div = document.getElementById("jspsych-html-swipe-response-stimulus");

let position = {
Expand All @@ -211,26 +213,35 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
const setPosition = (coordinates) => {
const { x = 0, y = 0, rotation = 0 } = coordinates;
position = { x, y, rotation };
container_div.style.transform = `translate3D(${x}px, ${y}px, 0)`;
stimulus_div.style.transform = `translate3D(${x}px, ${y}px, 0) rotate(${rotation}deg)`;
};

// Reset the position of the stimulus and container
const resetPosition = async () => {
stimulus_div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
for (const div of [container_div, stimulus_div]) {
div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
}
setPosition({ x: 0, y: 0, rotation: 0 });
stimulus_div.style.transition = null;
for (const div of [container_div, stimulus_div]) {
div.style.transition = null;
}
};

// Handle drag movement of the stimulus and container together
const dragMoveListener = (event) => {
const x = position.x + event.delta.x;
const y = position.y + event.delta.y;
let rotation = 0;
if (position.x > 0) {
rotation = Math.min(trial.swipe_animation_max_rotation, position.x / 4);

if (x > 0) {
rotation = Math.min(trial.swipe_animation_max_rotation, x / 4);
} else {
rotation = Math.max(-trial.swipe_animation_max_rotation, position.x / 4);
rotation = Math.max(-trial.swipe_animation_max_rotation, x / 4);
}

setPosition({ x: x, y: y, rotation });
};

Expand All @@ -249,9 +260,11 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
}

const sendCardToLeft = async () => {
stimulus_div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
for (const div of [container_div, stimulus_div]) {
div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
}
setPosition({
x: -trial.swipe_offscreen_coordinate,
y: position.y,
Expand All @@ -260,9 +273,11 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
};

const sendCardToRight = async () => {
stimulus_div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
for (const div of [container_div, stimulus_div]) {
div.style.transition = `${trial.swipe_animation_duration / 1000}s ease-in-out, ${
trial.swipe_animation_duration / 1000
}s ease-in`;
}
setPosition({
x: trial.swipe_offscreen_coordinate,
y: position.y,
Expand Down Expand Up @@ -321,29 +336,31 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
}
};

interact(stimulus_div).draggable({
inertia: false,
autoScroll: true,
modifiers: [
interact.modifiers.restrictRect({
endOnly: true,
}),
],
listeners: {
move: dragMoveListener,
end: () => {
if (position.x < -trial.swipe_threshold) {
sendCardToLeft();
after_swipe_response("left");
} else if (position.x > trial.swipe_threshold) {
sendCardToRight();
after_swipe_response("right");
} else {
resetPosition();
}
for (const div of [stimulus_div, container_div]) {
interact(div).draggable({
inertia: false,
autoScroll: true,
modifiers: [
interact.modifiers.restrictRect({
endOnly: true,
}),
],
listeners: {
move: dragMoveListener,
end: () => {
if (position.x < -trial.swipe_threshold) {
sendCardToLeft();
after_swipe_response("left");
} else if (position.x > trial.swipe_threshold) {
sendCardToRight();
after_swipe_response("right");
} else {
resetPosition();
}
},
},
},
});
});
}

// function to handle responses by the participant
const after_keyboard_response = (info) => {
Expand Down Expand Up @@ -422,7 +439,9 @@ class HtmlSwipeResponsePlugin implements JsPsychPlugin<Info> {
this.jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener);
}

interact(stimulus_div).unset();
for (const div of [stimulus_div, container_div]) {
interact(div).unset();
}

// gather the data to store for the trial
const trial_data = {
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-rdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @jspsych-contrib/plugin-rdk

## 1.2.0

### Minor Changes

- [#147](https://github.com/jspsych/jspsych-contrib/pull/147) [`7c775983b5852b5c44949f4bcd5bd7d45b048b3b`](https://github.com/jspsych/jspsych-contrib/commit/7c775983b5852b5c44949f4bcd5bd7d45b048b3b) Thanks [@Hoboki](https://github.com/Hoboki)! - If you want coherent dots to change their directions during a trial, you can set `flip_timestamps` and flip their directions as much as you want.

## 1.1.0

### Minor Changes
Expand Down
15 changes: 8 additions & 7 deletions packages/plugin-rdk/docs/jspsych-rdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ In addition to the [parameters available in all plugins](https://www.jspsych.org
| choices | array of strings | jsPsych.ALL_KEYS | The valid keys that the participant can press as a response. Must be an array of strings. If left unspecified, any key is a valid key. |
| correct_choice | array of strings | *undefined* | Array containing the key(s) that are considered the correct response for that particular trial. This needs to be linked with the `coherent_direction` parameter (see Examples section below for an illustration). This is used to determine whether the participant chose the correct response. The boolean indicating whether or not the participant chose the correct response is returned in the `correct` key of the data object. |
| trial_duration | numeric | 500 | The amount of time that the stimulus is displayed on the screen in ms. If -1, the stimulus will be displayed until the participant keys in a valid response. (`choices` parameter must contain valid keys or else the stimuli will run indefinitely). |
| flip_timestamps | array of numerics | [] | Timestamps to flip the direction of coherent dots. |
| response_ends_trial | boolean | true | If `true`, then the participant's response will end the trial. If `false`, the stimuli will be presented for the full `trial_duration` (the response will be recorded as long as the participant responds within the trial duration). |
| number_of_apertures | numeric | 1 | The number of apertures or RDKs on the screen. If set to more than one, remember to set the location (i.e., aperture_center_x and aperture_center_y) parameters to separate them. <br>In addition, each aperture can be customized individually by passing in an array of values as the parameter (see example below). If a single value (not an array) is passed as the parameter, then all apertures will have the same parameter. |
| number_of_dots | numeric | 300 | Number of dots per set. Equivalent to number of dots per frame. |
Expand Down Expand Up @@ -82,19 +83,19 @@ In addition to the [default data collected by all plugins](https://www.jspsych.o

```javascript
var trial = {
type: jsPsychRdk,
type: jsPsychRdk,
coherent_direction: 0,
correct_choice: ["p"]
};
```
```

See `examples/example2.html` for a demo.

### "Displaying a trial with 2 choices and 1 correct choice"

```javascript
var trial = {
type: jsPsychRdk,
type: jsPsychRdk,
post_trial_gap: 0,
number_of_dots: 200,
RDK_type: 3,
Expand All @@ -103,7 +104,7 @@ var trial = {
coherent_direction: 180,
trial_duration: 1000
};
```
```

See `examples/example3.html` for a demo.

Expand All @@ -112,7 +113,7 @@ See `examples/example3.html` for a demo.

```javascript
var trial = {
type: jsPsychRdk,
type: jsPsychRdk,
number_of_apertures: 3, //This needs to be set if more than one aperture
trial_duration: 10000,
correct_choice: ["a"],
Expand All @@ -121,7 +122,7 @@ var trial = {
number_of_dots: [50, 200, 100], //Different parameter for each aperture. Array length must equal number_of_apertures
aperture_center_x: [(window.innerWidth/2)-300,window.innerWidth/2,(window.innerWidth/2)+300] //Separate the apertures on the screen (window.innerWidth/2 is the middle of the screen)
};
```
```

See `examples/example4.html` for a demo.

Loading

0 comments on commit df7748e

Please sign in to comment.