From 0a2dc874967a94dd1aecda9813cc075ed3b8be2c Mon Sep 17 00:00:00 2001 From: Daiichiro Kuroki Date: Wed, 19 Nov 2025 14:22:14 +0900 Subject: [PATCH] Extension for the SD Method --- docs/demos/jspsych-survey-likert-demo3.html | 61 +++++++++++++ docs/plugins/survey-likert.md | 56 +++++++++++- examples/jspsych-survey-sd.html | 57 +++++++++++++ packages/plugin-survey-likert/src/index.ts | 95 +++++++++++++++++++-- 4 files changed, 260 insertions(+), 9 deletions(-) create mode 100644 docs/demos/jspsych-survey-likert-demo3.html create mode 100644 examples/jspsych-survey-sd.html diff --git a/docs/demos/jspsych-survey-likert-demo3.html b/docs/demos/jspsych-survey-likert-demo3.html new file mode 100644 index 0000000000..a997f544d2 --- /dev/null +++ b/docs/demos/jspsych-survey-likert-demo3.html @@ -0,0 +1,61 @@ + + + + + + + + + + + + + diff --git a/docs/plugins/survey-likert.md b/docs/plugins/survey-likert.md index 5dcc0e47eb..d8557cc371 100644 --- a/docs/plugins/survey-likert.md +++ b/docs/plugins/survey-likert.md @@ -2,7 +2,7 @@ Current version: 2.1.0. [See version history](https://github.com/jspsych/jsPsych/blob/main/packages/plugin-survey-likert/CHANGELOG.md). -The survey-likert plugin displays a set of questions with Likert scale responses. The participant responds by selecting a radio button. +The survey-likert plugin displays a set of questions with Likert scale responses. The participant responds by selecting a radio button. Furthermore, this plugin can also be used to collect responses on image impressions using the SD method. ## Parameters @@ -10,12 +10,19 @@ In addition to the [parameters available in all plugins](../overview/plugins.md# Parameter | Type | Default Value | Description ----------|------|---------------|------------ -questions | array | *undefined* | An array of objects, each object represents a question that appears on the screen. Each object contains a prompt, labels and required parameter that will be applied to the question. See examples below for further clarification.`prompt`: Type string, default value is *undefined*. The strings are the question that will be associated with a slider. `labels`: Type array, default value is *undefined*. Each array element is an array of strings. The innermost arrays contain a set of labels to display for an individual question. If you want to use blank responses and only label the end points or some subset of the options, just insert a blank string for the unlabeled responses.`required`: Type boolean, default value is false. Makes answering questions required. `name`: Name of the question. Used for storing data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions. +questions | array | *undefined* | An array of objects, each object represents a question that appears on the screen. Each object contains a prompt, labels and required parameter that will be applied to the question. See examples below for further clarification.`prompt`: Type string, default value is *undefined*. The strings are the question that will be associated with a slider. `labels`: Type array, default value is *undefined*. Each array element is an array of strings. The innermost arrays contain a set of labels to display for an individual question. If you want to use blank responses and only label the end points or some subset of the options, just insert a blank string for the unlabeled responses.`required`: Type boolean, default value is false. Makes answering questions required. `name`: Name of the question. Used for storing data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions. `left_anchor`: The string displayed at the left end in the SD method. `right_anchor`: The string displayed at the right end in the SD method. randomize_question_order | boolean | `false` | If true, the display order of `questions` is randomly determined at the start of the trial. In the data object, `Q0` will still refer to the first question in the array, regardless of where it was presented visually. preamble | string | empty string | HTML formatted string to display at the top of the page above all the questions. scale_width | numeric | null | The width of the likert scale in pixels. If left `null`, then the width of the scale will be equal to the width of the widest content on the page. button_label | string | 'Continue' | Label of the button. autocomplete | boolean | false | This determines whether or not all of the input elements on the page should allow autocomplete. Setting this to true will enable autocomplete or auto-fill for the form. +stimulus | string | null | The file name of the image. When using the SD method, it will be displayed on the left side of the screen. This image is not automatically preloaded, but this should not be an issue for most surveys. If preloading is necessary, please use [the preload plugin](./preload.md) together. +image_caption | string | null | The string displayed below the image. +image_width | numeric | 500 | The width of the image. If it differs from the actual width, the image will be scaled up or down while maintaining its aspect ratio. +scale_area_height | numeric | 300 | The height of the area where the scale is displayed when an image is presented. If there are many question items, a scrollbar will appear. The position of the image remains fixed. +left_anchor_width | numeric | 200 | The width of the left anchor. +right_anchor_width | numeric | 200 | The width of the right anchor. +line_position | numeric | 20 | A numeric value used to adjust the vertical position of anchors so they align with the horizontal line. ## Data Generated @@ -26,6 +33,7 @@ Name | Type | Value response | object | An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. | rt | numeric | The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. | question_order | array | An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. | +stimulus | string | The path of the image that was displayed. ## Install @@ -110,4 +118,48 @@ import surveyLikert from '@jspsych/plugin-survey-likert'; Open demo in new tab +???+ example "SD method" + === "Code" + + ```javascript + var trial = { + type: jsPsychSurveyLikert, + stimulus: "img/happy_face_1.jpg", + preamble: "PREAMBLE", + image_caption: "CAPTION", + questions: [ + { + prompt: "How friendly or unfriendly does this person appear to you?", + left_anchor: "Friendly", + right_anchor: "Unfriendly", + name: 'Friendly', + labels: scale, + required: true + }, + { + prompt: "How trustworthy or untrustworthy does this person seem?", + left_anchor: "Trustworthy", + right_anchor: "Untrustworthy", + name: 'Trustworthy', + labels: scale, + required: true + }, + { + prompt: "How attractive or unattractive do you find this person?", + left_anchor: "Attractive", + right_anchor: "Unattractive", + name: 'Attractive', + labels: scale, + required: true + } + ] + }; + ``` + + === "Demo" +
+ +
+ + Open demo in new tab diff --git a/examples/jspsych-survey-sd.html b/examples/jspsych-survey-sd.html new file mode 100644 index 0000000000..b928b8204a --- /dev/null +++ b/examples/jspsych-survey-sd.html @@ -0,0 +1,57 @@ + + + + + + + + + + diff --git a/packages/plugin-survey-likert/src/index.ts b/packages/plugin-survey-likert/src/index.ts index 888744ed69..67e1be5d65 100644 --- a/packages/plugin-survey-likert/src/index.ts +++ b/packages/plugin-survey-likert/src/index.ts @@ -32,6 +32,16 @@ const info = { type: ParameterType.STRING, default: "", }, + /** The string displayed at the left end in the SD method. */ + left_anchor: { + type: ParameterType.HTML_STRING, + default: "", + }, + /** The string displayed at the right end in the SD method. */ + right_anchor: { + type: ParameterType.HTML_STRING, + default: "", + }, }, }, /** If true, the order of the questions in the 'questions' array will be randomized. */ @@ -59,6 +69,41 @@ const info = { type: ParameterType.BOOL, default: false, }, + /** The path of the image file to be displayed. */ + stimulus: { + type: ParameterType.IMAGE, + default: null + }, + /** The string displayed below the image. */ + image_caption: { + type: ParameterType.HTML_STRING, + default: null, + }, + /** The width of the image. */ + image_width: { + type: ParameterType.INT, + default: 500 + }, + /** The height of the area where the scale is displayed. */ + scale_area_height: { + type: ParameterType.INT, + default: 300 + }, + /** The width of the left anchor. */ + left_anchor_width: { + type: ParameterType.INT, + default: 200 // If neither left_anchor nor right_anchor is specified, the value defaults to 0. + }, + /** The width of the right anchor. */ + right_anchor_width: { + type: ParameterType.INT, + default: 200 // If neither left_anchor nor right_anchor is specified, the value defaults to 0. + }, + /** A numeric value for adjusting the position of the anchors and the horizontal alignment. */ + line_position: { + type: ParameterType.INT, + default: 20 + }, }, data: { /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */ @@ -74,6 +119,10 @@ const info = { type: ParameterType.INT, array: true, }, + /** The path of the image file to be displayed. */ + stimulus: { + type: ParameterType.STRING, + }, }, // prettier-ignore citations: '__CITATIONS__', @@ -101,6 +150,12 @@ class SurveyLikertPlugin implements JsPsychPlugin { } var html = ""; + if (trial.stimulus !== null) { + var custom_css = `.sd-container { display: flex; } + #right-side { width: 100%; height: ${trial.scale_area_height}px; overflow-y: scroll}`; + } else { + var custom_css = ""; + } // inject CSS for trial html += '"; @@ -123,6 +179,16 @@ class SurveyLikertPlugin implements JsPsychPlugin { ""; } + if (trial.stimulus !== null){ + html += `
`; + html += `
`; + if (trial.image_caption !== null) { + html += `
${trial.image_caption}
`; + } + html += `
`; // left-side + html += '
'; + } + if (trial.autocomplete) { html += '
'; } else { @@ -146,12 +212,19 @@ class SurveyLikertPlugin implements JsPsychPlugin { html += '"; // add options var width = 100 / question.labels.length; - var options_string = - '
    '; + if (question.left_anchor === "" && question.right_anchor === "") { + var options_string = + '
      '; + } else { + var options_string = `
      +

      ${question.left_anchor}

      +
        `; + } for (var j = 0; j < question.labels.length; j++) { options_string += '
      • " + question.labels[j] + "
      • "; } - options_string += "
      "; + options_string += `
    `; + if (!(question.left_anchor === "" && question.right_anchor === "")) { + options_string += `

    ${question.right_anchor}

`; + } html += options_string; } @@ -178,6 +254,10 @@ class SurveyLikertPlugin implements JsPsychPlugin { html += ""; + if (trial.stimulus !== null){ + html += "
"; // right-side + html += ""; // sd-container + } display_element.innerHTML = html; display_element.querySelector("#jspsych-survey-likert-form").addEventListener("submit", (e) => { @@ -216,6 +296,7 @@ class SurveyLikertPlugin implements JsPsychPlugin { rt: response_time, response: question_data, question_order: question_order, + stimulus: trial.stimulus, }; // next trial