【jsPsych】survey pluginって知ってるかい？

# はじめに
- みなさんjsPsychで質問紙をとるときはどのプラグインを使ってますか？
- jsPsychには以下のようなsurvey系のプラグインが実装されています。
    - survey-likert
    - survey-html-form
    - survey-text
    - survey-multi-select
    - survey-multi-choice

- 基本的にはこれらで色々データを取っていたのだが、紙やgoogle formsとは見た目が全然違う。それはそれで別に問題ないのだが、正直かっこよくはなくて、cssで見た目をいじっていました。
- 最近知ったのだが、survey pluginというのがjsPsychで実装されているらしい。
    - SurveyJSというライブラリから読み込んでいるそうだ。

https://surveyjs.io/

- jsPsychver7.0にはなかったが、ver7.1からあるみたい。
    - 少しずつ開発が進んでいる感がある。


# surveyプラグインでできること

- ひとつのページに複数の質問(形式)を提示することができる。
    - リッカートのすぐ下に自由記述を出す等

- 従来の形式とは異なる見栄えで実行できる。
    - "survey-likert"プラグインと"survey"プラグインの"likert"は見栄えが結構違う。
    - また、"likert-table"というのもあり、結構いい感じである。

- 見栄えに悩んでいた人には朗報である。
- ただし、現在の最新バージョンでもシミュレーションモードには対応していないようなので、開発が現在進行形というのがわかる。
    - もしかすると、別の形式のものとかも今後出てくるのかもしれないね。

# どんな形式があるのか
- html
    - 回答は求めないが、追加で何かしらを提示したりに使う。そのページ全体についての教示だったり、ページ内でセクションが変わることを示すことができる。html形式で記述可能なため、文字だけでなく画像なども貼り付けることができる。
- drop-down
    - ドロップダウン(プルダウン)を表示し、回答をいずれかから選んでもらう。
![スクリーンショット 2023-04-01 16.10.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/45a9ab54-cb9b-56c4-992f-1c94964614f3.png)

- likert 
    - 最小と最大のラベルだけを付与することができる。
![スクリーンショット 2023-04-01 16.53.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/b8ddb557-f289-875e-4458-b8bcc93f77f4.png)
- likert-table
    - 複数の質問項目について表形式で回答を求めることができる。何度もラベルをつけると見栄えが悪くなるので、これは便利。
![スクリーンショット 2023-04-01 16.53.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/9795c05b-93d4-ba6a-0a3b-f40b506eb4c6.png)
- multi-choice
    - 従来の"survey-multi-choice plugin"と基本的には一緒。ボタンが少し大きくなっている。

![スクリーンショット 2023-04-04 12.18.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/c9c011f1-7d48-5255-b8fc-4ac4758c4490.png)

- multi-select
    - 従来の"survey-multi-select plugin"と基本的には一緒。ボタンが少し大きくなっている。

![スクリーンショット 2023-04-04 12.19.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/2db43e62-ca41-c419-03f7-e04cd3a1cc00.png)

- ranking
    - ドラッグ & ドロップでランキングを回答することができる。
    - これぞhtmlという感じがする。もちろんPCでもスマホでもできる。
![ranking.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/7f5bbaa4-347d-74cb-5141-b869318dc5cb.gif)
- text 
    - 自由記述で回答を求めることができる。
    - HTMLの `<input>`要素であるため、いくつかの回答方法を実装できる(色を入力してもらう。日付を入力してもらうなど)。
    - 便利


# 使い方

- 基本的には公式ページを確認してほしい。
    - 本家ページ

https://www.jspsych.org/7.3/plugins/survey/

## pluginを読み込む
- そのほかのプラグインと同様に、surveyプラグインを事前に読み込んでおく必要がある。

```html
<script src="https://unpkg.com/@jspsych/plugin-survey@0.2.1"></script>
```

- また、surveyプラグイン特有のcssが設定されており、プラグインだけでなく、追加のcssも読み込んでおく必要がある。

```html
<link rel="stylesheet" href="https://unpkg.com/@jspsych/plugin-survey@0.2.1/css/survey.css">
```

- surveyプラグインを利用する際のhtmlファイルのテンプレートは以下のようになる
```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>My experiment</title>
    <script src="https://unpkg.com/jspsych@7.3.1"></script>
    <script src="https://unpkg.com/@jspsych/plugin-survey@0.2.1"></script>
    <link href="https://unpkg.com/jspsych@7.3.1/css/jspsych.css" rel="stylesheet" type="text/css" />
    <link href="https://unpkg.com/@jspsych/plugin-survey@0.2.1/css/survey.css" rel="stylesheet" />
</head>

<body></body>
<script>
    var jsPsych = initJsPsych({
            on_finish: function () {
                jsPsych.data.displayData();
            }
    });

    var timeline = [];
    var trial = {
        type: jsPsychSurvey,
        pages: [
            []
        ]
    };

    timeline.push(trial);
    jsPsych.run(timeline);
</script>
</html>

```


## 全体で設定するもの
- それぞれの形式で設定できるものが異なるが、もちろん全ての形式で共通で設定するものがある。
- pages
    - ページごとに何を提示するのかを配列で指定する。
    - [[1ページ目の１つ目の質問, 1ページ目の2つ目の質問], [2ページの1つ目の質問, 2ページ目の2つ目の質問]]のようにする。
    - 実際の書き方は後ほど記述する
- button_label_next
    - 2ページ以上の構成の場合で、次のページに進むためのボタンに表示する文字を設定する
    - 文字列を指定する
    - デフォルトは「Continue」
- buton_label_back
    - 2ページ以上の構成の場合で、前のページに戻るためのボタンに表示する文字を設定する
    - 文字列を指定する
    - デフォルトは「Back」

- button_label_finish
    - 質問全て(ページにかかわらず)に回答し終え、回答を送信してもらう際のボタンに表示する文字を設定する
    - 文字列を指定する
    - デフォルトは「Finish」
- autocomplete
    - オートコンプリートを適用するかどうかを設定する
    - デフォルトはfalse
    - オートコンプリートとは

https://e-words.jp/w/autocomplete%E5%B1%9E%E6%80%A7.html
    
- show_question_numbers
    - 質問形式ごとに通し番号をつけるかを指定する
    - それぞれの質問のpromptの横に表示される
    - 文字列で"on"か"off"のいずれかを指定できる
    - デフォルトは"off"
- title
    - ページ上部にタイトルをつけることができる。
    - ページを遷移しても表示され続ける。
    - 文字列で指定する
    - デフォルトは何もなし。
- required_error
    - 回答必須のものに回答していない場合にテキスト表示することができる
    - その際の文字を指定することができる。
    - 文字列で指定する
    - デフォルトは"Please answer the question."
    - 回答必須にするかどうかは質問形式ごとに指定することができる。必須項目の仕方は後述
- required_question_label
    - 回答必須のpromptの横に目印をつけることができる。
    - 文字列で指定する
    - デフォルトは"*"
        - 触ってみたところlikert-tableには現状つかない。バグっぽい。

- 以下のようにしてtrial全体に共通するものを指定する。

```javascript
var trial = {
        type: jsPsychSurvey,
        pages: [[]],
        show_question_numbers: "on",
        title: "タイトルだよー"
    };
```

- pagesの中に1つあるいは複数の質問形式について記述していく。
- 単純に書くとしたら以下のようになる

```javascript
    var trial2 = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'html',
                    prompt: '以下の質問を読んで回答しておくれ。ここに画像だったりを貼り付けることもできる。',
                },
                {
                    type: 'drop-down',
                    prompt: "これがdrop-downや",
                    options: ["A", "B"]
                },
                {
                    type: 'likert',
                    prompt: 'これがlikert',
                    likert_scale_min_label: 'めっちゃ使えそう！',
                    likert_scale_max_label: '全然使えなさそう。'
                }
            ]
        ],
        show_question_numbers: "on",
        title: "タイトルだよー",
    };
```
- これで1ページの中に、html, drop-down, likertが含まれるものを提示することができる。
- 2ページにわたるものを作る場合は以下のようにする
    - **鉤括弧( [] )の位置に注意してください**。

```javascript

    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'drop-down',
                    prompt: "これがdrop-downや",
                    options: ["A", "B"]
                }
            ],
            [
                {
                    type: 'likert',
                    prompt: 'これがlikert',
                    likert_scale_min_label: 'めっちゃ使えそう！',
                    likert_scale_max_label: '全然使えなさそう。'
                }
            ]
        ],
        show_question_numbers: "on",
        title: "タイトルだよー",
    };
```

## 質問形式にかかわらず設定するもの
- pagesの中で色々設定していくのですが、質問形式によらず設定できるものがいくつかある。
- jsPsychの基本と一緒ですね。
    - 以下を設定できる
- type
    - 質問形式の種類を指定する。以下のいずれかを必ず指定する。
        - "drop-down"
        - "html"
        - "likert"
        -  "likert-table"
        -   "multi-choice" 
        -   "multi-select"
        -    "ranking" 
        -    "rating"
        -    "text"
- prompt
    - 質問形式ごとにpromptをつけることができる。
    - それぞれの質問のタイトルや教示などを文字列で指定する。    
    - typeを"html"にした場合もここに文字入力する
        - しかし、"html"の場合だけ、文字列だがhtmlフォーマットで入力するので注意。

```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'html',
                    prompt: '<p style="color: red;">htmlタグのpタグなどを使えば色の指定などができる</p>',
                },
                {
                    type: 'likert',
                    prompt: 'タグなどは付けず、そのまま文字を入力。'
                }
            ]
        ]
    };
```
- required
    - 必須項目にするかどうかを指定する
    - true か false
    - デフォルトではfalse

- name
    - データ保存時にそれぞれの回答ごとにわかりやすいように名前をつけることができる
    - デフォルトではP0_Q0, P0_Q1などで出力される
    - 説明しにくいので実際に試してください。

# type別に設定できるもの
- それぞれのtypeごとに設定できるものが異なります。likertとtextでは見栄えが全然違うしそりゃ指定できるものも変わってきます。

## html
- prompt
    - 上述したようにpromptの部分にhtmlフォーマットで記述する。
    - 文字のサイズ、色の設定などなどを設定できる。
    - 以下が例

```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'html',
                    prompt: '<p style="color: red;">以下の質問を読んで回答してください。ここに画像だったりを貼り付けることもできる。</p>',
                },
            ]
        ]
    };
```

## drop-down
- options
    - 表示する文字列の選択肢を配列で指定する
    - 以下のようにする


- option_reorder
    - 表示する選択肢の順番を指定する
    - "none", "asc", "desc", "random"のいずれか
        - "none"にするとoptionsで指定した順番で表示される
        - "asc", "desc"で昇順か降順かになる
        - "random"にすると順番がランダムになる
    - デフォルトは"none"

- correct_response
    - optionsで指定した選択肢の中から正解の選択肢を設定することができる
    - 指定するとデータにcorrect列ができ、正解だったらtrue、不正解ならfalseが入力される
- 以下が例


```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'drop-down',
                    prompt: 'これがdrop-downや',
                    options: ["選択肢1", "選択肢2"]
                }
            ]
        ]
    };
```

## likert
- likert_scale_values
    - スケールのラベルと保存される値を指定することができます。
    - 配列で指定します。


- likert_scale_min
    - 前述したlikert_scale_valuesが指定されていない場合に使われます。
    - スケールの最小を選択したときのデータに出力するときの最小の値です。
    - 数値で指定します
    - デフォルトは1です。
- likert_scale_max
    - 前述したlikert_scale_valuesが指定されていない場合に使われます。
    - スケールの最大を選択肢たときのデータに出力するときの最大の値です。
    - 数値で指定します
    - デフォルトは5です。
- likert_scale_stepsize
    - 前述したlikert_scale_valuesが指定されていない場合に使われます。
    - 最小値と最大値のステップサイズを指定します。
    - 数値で指定します。
    - デフォルトは1です。
- likert_scale_min_label
    - スケールの最小値のラベルを指定します。
    - 最小値のボタンに表示したい文字列を指定します。
    - デフォルトでは何も入っていません。
- likert_scale_max_label
    - スケールの最大値のラベルを指定します。
    - 最大値のボタンに表示したい文字列を指定します。
    - デフォルトでは何も入っていません。

- likert_scale_valuesを指定した際はそのほかをいじる必要はなさそうです。
- 例えば、以下に指定する際の例と出力例を示します。
    - データにはvalueが保存されます。
```javascript
var trial = {
        type: jsPsychSurvey,
        pages: [[
            {
                type: "likert",
                prompt: "教示",
                likert_scale_values: [
                    { value: 1, text: "まったく" },
                    { value: 2, text: "少し" },
                    { value: 3, text: "とても" }
                ]
            }
        ]]
    };
```

![スクリーンショット 2023-04-01 18.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2251263/834c8335-f813-5667-17fb-63ce406446af.png)


## likert-table
- statements
    - リッカートの尺度項目を1つ以上指定します。
    - オブジェクトの配列で指定します。
    - 尺度項目をprompt, データに出力する際のnameを指定することができます。
    - nameはデフォルトでは"S0", "S1"のようになります。
- options
    - 選択肢を指定します。
    - 文字列の配列で指定します。

- randomize_statement_order
    -  上述したstatementsの順番をランダムにするかどうかを指定します。
    -  true か falseで指定します。
    -  デフォルトはfalseです。
-  以下が例

```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'likert-table',
                    prompt: 'これがlikert-table',
                    statements: [
                        { prompt: 'htmlは使えそうだと思う。', name: 'html' },
                        { prompt: 'drop-downは使えそうだと思う。', name: 'drop-down' },
                        { prompt: 'likertは使えそうだと思う', name: 'likert' },

                    ],
                    options: ['全然使えなさそう', '使えなさそう。', 'どちらでもない', '使えそう', 'めっちゃ使えそう'],
                },
            ]
        ]
    };
```

## multi-choice
- options
    - 選択肢を指定します。
    - 文字列の配列で指定します。
- option_reorder
    - 表示する選択肢の順番を指定します。
    - "none", "asc", "desc", "random"のいずれか
        - "none"にするとoptionsで指定した順番で表示される
        - "asc", "desc"で昇順か降順かになる
        - "random"にすると順番がランダムになる
    - デフォルトは"none"

- columns
    - 表示される選択の列を指定します。
    - 数値を指定します。
        - 1とすると1列で選択肢が表示される(縦に並ぶ)
        - 0とすると1行で選択肢が表示される(横に並ぶ)
        - 1より大きい値を指定すれば複数の列にして表示することができる
- correct_response
    - optionsで指定した選択肢の中から正解の選択肢を設定することができる
    - 指定するとデータにcorrect列ができ、正解だったらtrue、不正解ならfalseが入力される
- 以下が例
```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'multi-choice',
                    prompt: 'これがmulti-choice',
                    options: [1,2,3,4],
                    columns: 2

                },
            ]
        ]
    };
```

## multi-select
- multi-choiceと同じ
    - 割愛します。

## ranking
- options
    - 順位づけしてもらう選択肢を指定します。
    - 文字列の配列で指定します。
- option_reorder
    - 表示する選択肢の順番を指定します。
    - "none", "asc", "desc", "random"のいずれか
        - "none"にするとoptionsで指定した順番で表示される
        - "asc", "desc"で昇順か降順かになる
        - "random"にすると順番がランダムになる
    - デフォルトは"none"
- correct_response
    - optionsで指定した選択肢の中から正解の選択肢を設定することができる
    - 指定するとデータにcorrect列ができ、正解だったらtrue、不正解ならfalseが入力される
- 以下が例

```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'ranking',
                    prompt: "使えそうな順番に並び替えてください。",
                    options: ['drop-down', 'likert', 'likert-table', 'ranking']
                },
            ]
        ]
    };
```

## text
- placeholder
    - テキストボックスの中に表示したい文字列を指定する
- textbox_rows
    - テキストボックスの行数(高さ)を指定することができる
    - 数値で指定する
    - デフォルトは1

- textbox_columnss
    - テキストボックスの列数(幅)を指定することができる
    - 数値で指定する
    - デフォルトは40

- validation
    - バリデーションチェックをする際の文字列を指定します。
    - 特定の文字を入力してほしい時(メールアドレスなど)、「@」など特定の文字が入力されていないと受け付けないようにしたい場合があります。
    - その際に用います(ごめんなさい。多分)。
    - 正規表現で指定します。
- input_type
    - HTMLには <input>要素というものがあります。
    - 単純なtextの入力だけではなく、日付を入力してもらうボックスなどがあります。
    - どのようなボックスを表示するのかを指定することができます。
    - 以下のいずれかを指定することができます。
        -  "color"
        -  "date"
        -  "datetime-local"
        -  "email"
        -  "month"
        -  "number"
        -  "password"
        -  "range"
        -  "tel"
        -  "text"
        -  "time"
        -  "url"
        -  "week"
- 以下が例

```javascript
    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'text',
                    prompt: "好きな色を回答してください。",
                    input_type: "color"
                }
            ]
        ]
    };
```

- どのようなボックスなのかは以下のサイトが参考になります。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/input

- これ結構すごい

# 終わりに
- なかなか便利そうです。
- 結構感動しています。
- 個人的にはlikert-tableはよく使いそうだし、drop-down, rankingはおしゃれでとても良いです。
    - textでは様々な回答方法があるのも感動しています。
- ただし、surveyプラグインで出力される文字はデフォルトがグレーになっているので、黒にする場合はcssで変える必要があります。
    - なんでグレー固定なんだろう。
    - classとはなんぞやという方はこちらの記事をご参考に(宣伝)。

https://qiita.com/takato_oyama/items/860a5d5c7813d26a6cca

- 最後にsurveyプラグインの例を載せておきます。
    - 以下のURLでは1ページ目にhtml, likertとlikert-table, 2ページ目にdrop-downとranking, text(colorの選択)を回答してもらうようになっています。
    - 下記コードは以下で体験できます。
    - いつまでたっても読み込んでいる場合は、一度タブを閉じて再度開いてみてください。

https://takat0-ch.github.io/jsPsych-survey/
    
```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>My experiment</title>
    <script src="https://unpkg.com/jspsych@7.3.1"></script>
    <script src="https://unpkg.com/@jspsych/plugin-survey@0.2.1"></script>
    <link href="https://unpkg.com/jspsych@7.3.1/css/jspsych.css" rel="stylesheet" type="text/css" />
    <link href="https://unpkg.com/@jspsych/plugin-survey@0.2.1/css/survey.css" rel="stylesheet" />
</head>

<body></body>
<script>
    /* initialize jsPsych */
    const jsPsych = initJsPsych({
        on_finish: function () {
            jsPsych.data.displayData();
        }
    });

    var timeline = [];

    var trial = {
        type: jsPsychSurvey,
        pages: [
            [
                {
                    type: 'html',
                    prompt: '<p style="color: red;">以下の質問を読んで回答してください。ここに画像だったりを貼り付けることもできる。</p>',
                },
                {
                    type: 'likert',
                    prompt: 'これがlikert',
                    likert_scale_min_label: 'めっちゃ使えそう！',
                    likert_scale_max_label: '全然使えなさそう。'

                },
                {
                    type: 'likert-table',
                    prompt: 'これがlikert-table',
                    statements: [
                        { prompt: 'htmlは使えそうだと思う。', name: 'html' },
                        { prompt: 'drop-downは使えそうだと思う。', name: 'drop-down' },
                        { prompt: 'likertは使えそうだと思う', name: 'likert' },

                    ],

                    options: ['全然使えなさそう', '使えなさそう。', 'どちらでもない', '使えそう', 'めっちゃ使えそう'],
                }],
            [
                {
                    type: 'drop-down',
                    prompt: 'これがdrop-downや',
                    options: ["A", "B"]
                },
                {
                    type: 'ranking',
                    prompt: "使えそうな順番に並び替えてください。",
                    options: ['drop-down', 'likert', 'likert-table', 'ranking']
                },
                {
                    type: 'text',
                    prompt: "好きな色を回答してください。",
                    input_type: "color"
                }
            ]
        ],
        show_question_numbers: "on",
        title: "タイトルだよー"
    };

    timeline.push(trial);
    jsPsych.run(timeline);

</script>
</html>
```