jsPsychのプラグインをカスタマイズ - 参加者の回答を制限する方法

[jsPsych](https://www.jspsych.org/7.2/)を使っていると、公式プラグインをほんの少し変更したいという状況に直面することがあります。そういうときはプラグインを自分用にカスタマイズすればよいのですが、慣れないうちはハードルが高いと思います。今回の記事ではプラグインのカスタマイズをなるべく分かりやすくご紹介したいと思います。

私がよく相談を受けるものとして、**テキストボックスに入力できる内容を制限したい** という要望があります。今回は、survey-textをカスタマイズしてこれを実現させてみましょう。

# jsPsychのパッケージ一式をダウンロードする

jsPsychはバージョンが7になってから、基本的にパッケージをダウンロードせずに利用できるようになりました。しかしカスタマイズをしたいときにはパッケージのダウンロードが必要になります。

[The Basics: Hello Worldのチュートリアルの Option 2: Download and host jsPsych](https://www.jspsych.org/7.2/tutorials/hello-world/#option-2-download-and-host-jspsych) に詳細が書かれています。ここから jspsych.zip をダウンロードしてください。ダウンロードしたファイルは、zip形式になっていますので「すべて展開」をします。

![jspsych1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495823/9078bad7-dc79-ac00-4ece-b8e13e869a71.png)

# jspsych-survey-text デモを動かしてみよう

展開したフォルダの中身を見ると、dist, examplesという名前の2つのフォルダ、そしていくつかのファイルが見えると思います。まずはデモプログラムを動かしてみましょう。

examplesを開いて、jspsych-survey-textをダブルクリックしてください。お使いのPCのデフォルトのウェブブラウザでプログラムが動くと思います。

年齢と出身地をたずねる画面が表示されます。ちなみに、年齢と出身地をたずねる順序（上下の関係）はデモプログラムを動かすたびに変更されるように設定されています。

Continueボタンを押して回答を決定すると、今日の調子を自由記述する画面に変わります。これに回答するとプログラムが終了します。

# 自分のプラグインを読み込ませる

まずはカスタマイズはほとんどせずに、自分用のプラグインを作成してそれを読み込ませてみましょう。jspsych-survey-textデモをテキストエディタで開くと上部に以下のように書かれていると思います。

```javascript
<script src="../dist/plugin-survey-text.js"></script>
```
これはdistフォルダにある、plugin-survey-text.jsを読み込むという意味です。

今度はプラグインファイル plugin-survey-text.js をテキストエディタで開いてみましょう。

開いたら、このファイルを別名で保存します。場所はdistフォルダで大丈夫です。ファイル名は何でも構わないのですが、今回は年齢の欄に入力された内容をチェックしたいと思いますので、plugin-survey-text-age-check.js としてみます。拡張子がjsになっている点に注意してください。

自分のファイルが読み込まれているのを確認するため、以下のようにして、`console.log("Customized by DK")`を加えてください。`console.log`はjavascriptコンソールに文字列を表示するための命令（関数）です。表示する文字列はなんでもかまいません。ちなみにDKは私のイニシャルです。

```javascript
var jsPsychSurveyText = (function (jspsych) {
  'use strict';

  console.log("Customized by DK")
```

変更を終えたらファイルを保存します。さらに、jspsych-survey-textデモに戻り、自作したファイルを読み込むように変更します。一応、変更前のプラグインも読み込むようにしています。

```javascript
<script src="../dist/plugin-survey-text.js"></script>
<script src="../dist/plugin-survey-text-age-check.js"></script>
```

もし、Cognitionを使ってjsPsychを動かそうとしている場合には、

https://qiita.com/kurokida/items/5d75c8b13786ec22b294

の Source code の説明を見て、External JS のところから自作のプラグインファイル（plugin-survey-text-age-check.js）をアップロードしてください。

# JavaScriptコンソールを開く

上で説明したように`console.log`で出力された内容はJavaScriptコンソールでしか確認ができません。ここではChromeを使って確認する方法を説明します。以下の図を参考に、右上にある、点が３つ並んだところから、「その他のツール」→「デベロッパーツール」と開きます。

![javascriptコンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495823/e1e6ce6a-530d-5188-1831-6ec4fedd4201.png)

Console（コンソール）を見ると、指定した文字列が表示がされているのを確認できるはずです。ファイル名も変更したものになっていますね。

![javascriptコンソール2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495823/2275bd43-9478-673e-37c2-552ad4a12f6f.png)

これで、自分用のファイルをプラグインとして読み込めるようになりました。

# 年齢の回答として数字のみを受け付ける

いよいよカスタマイズの本番です。もともとのデモプログラムでは年齢のところに abc のような文字列を入力してもエラーになりません。しかし、年齢の回答としては明らかに不適切です。ですので、整数しか入力できないようにしてみましょう。ちなみに[本記事とは別の解決方法](https://qiita.com/kurokida/items/d8805805a217278f1e85)を以前にご紹介していますので、そちらもご参照ください。

まず、プラグインファイルの先頭行にある名称を変更します。この部分は、デモプログラムにおいて、typeとして参照されます。AgeCgeckを付け加えました。

```javascript
var jsPsychSurveyTextAgeCheck = (function (jspsych) {
```

ここからは経験と勘が必要になりますが、回答を決定したときにその入力内容をチェックすればよいのではないか、と推測できます。そこで、以下のコードを見つけてください。私のファイルでは209行目でした。

```javascript
// save data
var trialdata = {
    rt: response_time,
    response: question_data,
};
```

question_dataが反応として保存されているので、これをコンソールで確認してみることにします。save dataのコメントの直前に、`console.log(question_data)`を書きます。プラグインファイルを上書き保存してください。

次にデモプログラムに戻って、次のようにtypeを変更します。

```javascript
var survey_page1 = {
    type: jsPsychSurveyTextAgeCheck,
```

デモプログラムを実行してJavaScriptコンソールを確認します。

![javascriptコンソール3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495823/a44eb0c8-c436-28d3-91e5-68df82fc59d2.png)

コンソールに表示された内容から、question_dataはオブジェクトであり、AgeとBirthLocationの2つのプロパティを持っていることが分かります。年齢のデータは、`question_data.Age`として参照することが可能です。

ここは見落としやすいポイントなのですが、21がシングルクオーテーションでくくられており、数値ではなく文字列として保存されていることが分かります。`Number(question_data.Age)`とすることで、文字列から数値に変換できます。

ここまでくると、ある変数が整数かどうかを調べる関数があれば便利なのにな、という発想にいたります。ウェブで検索すると、ありました！　それは`Number.isInteger`です。（私も知らない関数でした・・・）

以上の情報を使って、参加者の回答が整数かどうかを判断することができます。具体的には、以下のように記述します。

```javascript
console.log(question_data) // question_dataの中身を確認
const resp_age = Number(question_data.Age); // 文字列から数値へ変換
if (!Number.isInteger(resp_age)) { // 年齢のデータが整数かを判断　ビックリマーク(!)が入っていることに注意
    alert("年齢は半角の数字で入力してください。") // 警告を表示
    return // これ以上プログラムを先に進めない
}

// save data
var trialdata = {
    rt: response_time,
    response: question_data,
};
```

このままでもエラーはないのですが、私の環境だと警告文が文字化けしました。その場合は、デモプログラム側を少し変更するとよいようです。How old are you?を「年齢を入力してください。」に変更したら文字化けが解消されました。

```javascript
var survey_page1 = {
    type: jsPsychSurveyTextAgeCheck,
    questions: [
        {prompt: '年齢を入力してください。', columns: 3, required: true, name: 'Age'},
        {prompt: 'Where were you born?', placeholder: 'City, State/Province, Country', columns: 50, name: 'BirthLocation'}
    ],
    randomize_question_order: true
};
```

これで、参加者の回答をチェックして、年齢のデータが整数でないときには警告を表示してプログラムを先に進めないようにすることができました。

応用として、特定の年代の人しか実験に参加してもらいたくないときには、次のように記述をすればよいでしょう。

```javascript
const resp_age = Number(question_data.Age);
if (!Number.isInteger(resp_age)) {
    alert("年齢は半角の数字で入力してください。")
    return
}

if (resp_age < 10 || resp_age >= 20) {
    alert("この実験には10代のかたしか参加することができません。")
    return
}
```

このように条件は複数記述することができます。

説明は以上です。自分でもプラグインの変更できそう！と思ってもらえたのなら、うれしいです。