🤔

jsPsychを使った心理実験を一部のブラウザでのみ実行可能にする

2020/12/04に公開

はじめに

jsPsych のベースである javascript は,どのブラウザでもだいたい同じように動作しますが,全く同じように動作するわけではありません。そのため,短いトーンが繰り返し提示されるという実験を jsPsych で組んだ際,google chrome や firefox では問題なくトーンが提示されるにもかかわらず,safari ではたまにトーンが提示されないことがありました。

また,実験の内容によってはスマートフォンからの参加は避けたい場合があります。例えば,キー押しによる反応を収集する場合です。もちろん参加者がスマートフォン用の外付けキーボードを持っていればいいかもしれませんが,可能性は低いでしょうし,そんなアイテムを持ってる人は,きっとガジェット好きですから,PC も持っていそうです。

以上のような問題の解決策として,ブラウザを判定して特定のブラウザでのみ実験を開始させるという方法が挙げられます。今回紹介する方法では,PC とスマートフォンのどちらのブラウザかも取得するので,PC だけに限定させることも可能です。

そんなことよりもまず,そもそも jsPsych でどうやって実験を作成すればいいかわからないという方は, こちらにチュートリアルを作成してありますので,ぜひ参考にしてみてください。

ブラウザを判定する

ブラウザを判定する方法はいくつかあります。この記事で紹介されているように,javascript に標準で用意されているnavigatorを使用する方法もあれば,世界の誰かが作ってくれたライブラリを使用する方法もあります。今回は後者の方法で判定していきます。先ほどの記事を見てもらえればわかるように,navigatorを使うのは少しややこしい感じがしたからです。

UAParser というライブラリを使用します。UAParserでは,以下のようにたった数行でアクセスしているブラウザを取得できます。

const parser = new UAParser();
const browser = parser.getBrowser();
console.log(browser.name);

お使いのブラウザに応じて Chrome, Firefox, Edge といった文字列が出力されます。
同様に,OS を取得できます。

const parser = new UAParser(); // もし上のコードに続けて書くのなら要らない
const os = parser.getOS();
console.log(os.name);

お使いのデバイスの OS に応じて,Mac OS, Windows, iOS, Android といった文字列が出力されます。

世の中にはたくさんのブラウザ・OS が存在しているようで,UAParser の Github レポジトリには,どんなブラウザや OS が判定されるかが列挙されています。

さて,実際に実験内でブラウザを判定するためには,上記のコードを実験用の html の<script></script>タグ内に追加するだけではだめです。世界の誰かが作成したライブラリは標準では搭載されていないため,それを使うためには読み込む必要があります。jsPsychでは,実験用 html の<head></head>タグ内に使用するプラグインのパスを指定して実験開始時に読み込んでいますが,それと同様にUAParserが配布されている URL を指定して読み込みます。具体的には以下のようにします。

<!DOCTYPE html>
<html>
  <head>
    <script src="./jspsych-6.1.0/jspsych.js"></script>
    <script src="./jspsych-6.1.0/plugins/jspsych-html-keyboard-response.js"></script>
    <link rel="stylesheet" href="./jspsych-6.1.0/css/jspsych.css" />
    <!-- ↓↓↓↓↓↓ コレ ↓↓↓↓↓↓ -->
    <script src="https://cdn.jsdelivr.net/npm/ua-parser-js@0/dist/ua-parser.min.js"></script>
    <!-- ↑↑↑↑↑↑ コレ ↑↑↑↑↑↑ -->
  </head>
  <body></body>
  <script>
    const parser = new UAParser();
    const browser = parser.getBrowser();
    /*
    実験のコード
    */
  </script>
</html>

ただし,手元の PC 上に保存されている実験用 html にコレを追加してその html をブラウザで開いてもうまく行かない気がします(試してません)。実際に実験を実施するようなサーバー上での動作は確認しています。nodeとかで立てたローカルサーバー上で走らせれば動く気がしますが,これも試してません。いずれにせよ,わざわざ実験作成の序盤からブラウザを判定する必要はないと思うので,実験スクリプトのほとんどが完成しサーバーにアップロードして動作確認を行っている段階で追加するのが良いと思います。

Conditional timeline

さて,直前のセクションでブラウザを判定できるようになりました。ブラウザ・OS 情報に基づいて,特定のブラウザでしか実験に参加できないようにしていきます。具体的には,実験プログラムの適切な動作が確認できているブラウザの場合は何事もなく実験が進行し,それ以外の場合はブラウザを変更するように促す教示が表示されるようにします。

ここ使用するのが conditional timeline です。公式リファレンスには以下のコードが例示されています。

var pre_if_trial = {
  type: 'html-keyboard-response',
  stimulus: 'The next trial is in a conditional statement. Press S to skip it, or V to view it.',
};

var if_trial = {
  type: 'html-keyboard-response',
  stimulus: 'You chose to view the trial. Press any key to continue.',
};

var if_node = {
  timeline: [if_trial],
  conditional_function: function () {
    // get the data from the previous trial,
    // and check which key was pressed
    var data = jsPsych.data.get().last(1).values()[0];
    if (data.key_press == jsPsych.pluginAPI.convertKeyCharacterToKeyCode('s')) {
      return false;
    } else {
      return true;
    }
  },
};

var after_if_trial = {
  type: 'html-keyboard-response',
  stimulus: 'This is the trial after the conditional.',
};

jsPsych.init({
  timeline: [pre_if_trial, if_node, after_if_trial],
  on_finish: function () {
    jsPsych.data.displayData();
  },
});

ここではpre_if_trial, if_trial, after_if_trial の 3 つの試行が設定されています。どの試行も単に文字列を提示するもので,choicesが指定されていないのでデフォルトの設定となり,いずれかのキーを入力することで試行が終了します。どのように実験が進行するのかを確認するためにjsPsych.inittimelineを見てみると,そこにif_trialは直接指定されておらず,代わりにif_nodeが指定されています。そこで,if_nodeの定義を見てみるとif_nodetimelineif_trialが指定されています。

さらに,if_nodeにはconditional_functionという設定が用意されています(今回のポイント)。ここにはtruefalseのどちらか一方を返す関数を設定することで,その関数がtrueを返す場合はtimelineで指定された試行を実施させ,falseを返す場合は何もせずそのままスキップさせる事ができます。上記のコードの関数では,一つ前の試行のデータを取ってきて jsPsych.data.get().last(1).values()[0],記録されているキー入力key_presssかどうかを判定し,もしそうならfalseを返し,それ以外の場合はtrueを返します。一つ前の試行とはpre_if_trialのことなので,この試行の画面のときにsを押すとif_trialはスキップされ,すぐafter_if_trialが実行されます。それ以外のキーを押すとif_trialが表示されます。

このconditional functionを利用して,取得したブラウザ・OS 情報次第では実験を開始しないようにします。つまり,指定したブラウザ以外では実験を終了するようにします。

const parser = new UAParser();
const browser = parser.getBrowser();

// durationのかなり短い試行を設定し,試行の終了時に実験を強制終了させる
const finish_exp = {
  type: 'html-keyboard-response',
  stimulus: '',
  trial_duration: 100, // 何でも構わないですが,短いほうが良いと思います
  on_finish: function () {
    jsPsych.endExperiment('Google Chrome, FireFox, Microsoft Edge のいずれかのブラウザで開き直してください');
  },
};

// ブラウザがchrome, firefox, edge 以外ならfinish_exp が実行される
const check_browser = {
  timeline: [finish_exp],
  conditional_function: function () {
    if (browser.name === 'Chrome' || browser.name === 'Firefox' || browser.name === 'Edge') {
      return false;
    }
    return true;
  },
};

const lets_start = {
  type: 'html-keyboard-response',
  stimulus: '実験を始めます',
};

/*
その他実験のコード
*/

jsPsych.init({
  timeline: [check_browser, lets_start],
  on_finish: function () {
    jsPsych.data.displayData();
  },
});

実験を終了させるためのダミーの試行finish_expとブラウザ次第でダミー試行を実施させるブロックcheck_browserを作成し,jsPsych.inittimelineの最初に指定します。公式リファレンスの例のキー入力の代わりに,ブラウザの名前によってconditional_functionの関数はtruefalseを返し,trueの場合はfinish_expが実行されます。finish_expは 100 ミリ秒で終了する試行で,その終了時に実験全体を終了させる関数jsPsych.endExperiment()が実行されます。引数に文字列を指定することで,実験終了時にメッセージを表示できます。conditional_functionの関数がfalseを返す,つまり指定のブラウザで実験を開始していた場合は,finish_expは実行されず,そのまま実験が進行します。

同様の方法で一部の OS だけで実験を実施させることができます。今回は紹介しませんが,ご自身で挑戦してみてもらえればと思います。

おわりに

今回はUAParserを用いたブラウザの判定方法と,それを利用して一部のブラウザでのみ実験を実施させる方法を紹介しました。OS の判定・分岐については紹介しませんでしたが,「OS による分岐」という記事もありますので,こちらが参考になるかもしれません。この記事では,今回紹介したUAParserではなくplatform.jsというライブラリを使用しています。どちらもブラウザ・OS を判定できるので,挙動が少し異なります。といっても,ブラウザや OS の判定程度であれば同じ結果を返しているようです。2 つのライブラリの違いについてはこの比較記事が参考になります。私はこの記事の内容や,それぞれのライブラリのドキュメントの豊富さを比較して,UAParserを選択しました(UAParserのほうがドキュメントが豊富)。

Conditional timeline は今回のような場面以外でも役に立つことがあります。例えば,直前の試行の反応時間が一定時間よりも遅い場合のみ「もっと速くして!!」という教示を提示させたりすることができます。作れる実験の幅が広がるので,ぜひ利用を検討してみてください。

不定期にはなりますが,今後も引き続き心理学実験・研究法に関する Tips を共有していきます。いいね・サポートをいただけると大変励みになりますので,ぜひそちらもよろしくお願いします。

Discussion