jpPsychとp5js(ver7)汎用バージョン
以前、p5jsとjsPsychを組み合わせて使う方法は喜田くんに記事を書いてもらったんですが、今回はjsPsych ver7.xとp5.jsを組み合わせて、あとp5.jsのsketchをパラメータとして渡せるようにするプラグインを作ったので、メモ代わりに公開しておきます。
p5 ver 1.4.2
jsPsych 7.3
demo01.html: ダウンロードしてブラウザで開けば動くと思います。
demo01.js: 実験例javascriptファイル
jspsych-p5.js: プラグインのファイル
使い方ですが、例えばjsPsychのhtml-keyboard-responseだと、文章等をパラメータとして渡して表示させると思うんですが、あれのパラメータにp5.jsの関数を渡してp5.jsのvisualizationをまるっと刺激として使う感じです。
まずはプラグインのjsファイルの内容です。以下の内容をjspsych-p5.jsとして保存しておきましょう。プラグイン開発に興味ない限りは、このファイルの中身は気にしないでいいと思います。
code:javascript
var jsPsychP5 = (function (jspsych) {
"use strict";
let jsPsychP5_p5;
const info = {
name: "p5",
parameters: {
trial_duration: {
type: jspsych.ParameterType.INT,
default: null,
},
sketch: {
type: jspsych.ParameterType.FUNCTION,
default: undefined,
},
end_trial: {
type: jspsych.ParameterType.FUNCTION,
default: null,
}
}
};
/**
* ** p5 **
*
* plugin for use p5.js
*
* @author @kohske
*/
class jsPsychP5Plugin {
constructor(jsPsych) {
this.jsPsych = jsPsych;
}
trial(display_element, trial) {
let end_trial = function() {
jsPsych.pluginAPI.clearAllTimeouts();
display_element.innerHTML = "";
jsPsychP5_p5.remove();
jsPsych.finishTrial();
};
trial.end_trial = end_trial;
if (trial.trial_duration !== null) {
jsPsych.pluginAPI.setTimeout(function () {
end_trial();
}, trial.trial_duration);
};
trial.sketch.trial = trial;
let s = trial.sketch;
jsPsychP5_p5 = new p5(s, display_element);
};
}
jsPsychP5Plugin.info = info;
return jsPsychP5Plugin;
})(jsPsychModule);
使用例です。以下の実験では、2種類の調整法課題を3試行ずつ実施してます。やってみればわかります。
この内容を、demo01.jsとしておきましょう。
code:javascript
var jsPsych = initJsPsych(
{
on_finish: function() {
jsPsych.data.displayData();
}
}
);
// スケッチ関数。中身はp5.jsのエディタの中身でOK。
// p5.jsのオブジェクトにはprefixでp.を付ける必要があります。
// 1個目
let s_luminance = function (p) {
// これはおまじないとして入れておく。
let trial = jsPsych.getCurrentTrial();
// これはタイムラインのデータを拾う(使い方はjsPsychのサイトを参照)。
let bg = jsPsych.timelineVariable("bg", true)
let button, slider;
p.setup = function () {
p.createCanvas(400, 400);
p.createP("背景と同じ色にしてクリック");
button = p.createButton('決定');
button.mousePressed(
function(){
// 保存するデータはここで。
trial.data.response = slider.value();
trial.data.stimulus = bg;
// アクションでトライアルを終わらせる場合は、こうする。
trial.end_trial();
}
);
slider = p.createSlider(0, 255, 100);
slider.style('width', '80px');
};
p.draw = function () {
p.background(bg)
p.noStroke();
p.rectMode(p.CENTER);
p.fill(255, 0, 0);
p.rect(200, 200, 70);
p.fill(slider.value());
p.rect(200, 200, 50);
};
} // end sketch
// p5のトライアル定義
let p5_trial_luminance = {
type: jsPsychP5,
// trial_duration: 1000, // 時間で終わらせるなら、時間指定。
sketch: s_luminance, // このトライアル用のスケッチ(関数)を指定
data: {
response: null,
}
}
// 2個目
let s_angle = function (p) {
// これはおまじないとして入れておく。
let trial = jsPsych.getCurrentTrial();
// これはタイムラインのデータを拾う(使い方はjsPsychのサイトを参照)。
let angle = jsPsych.timelineVariable("angle", true)
let x;
let button, slider;
p.setup = function () {
p.createCanvas(400, 400);
p.createP("同じ傾きにしてクリック");
button = p.createButton('決定');
button.mousePressed(
function(){
// 保存するデータはここで。
trial.data.response = slider.value();
trial.data.stimulus = angle;
// アクションでトライアルを終わらせる場合は、こうする。
trial.end_trial();
}
);
slider = p.createSlider(-45, 45, 0);
slider.style('width', '80px');
};
p.draw = function () {
p.background(255)
p.stroke(0);
p.strokeWeight(5);
p.push();
p.translate(300, 200);
p.rotate(p.PI*slider.value()/180);
p.line(0, -50, 0, 50);
p.pop();
p.push();
p.translate(100, 200);
p.rotate(p.PI*angle/180);
p.line(0, -50, 0, 50);
p.pop();
};
} // end sketch
let p5_trial_angle = {
type: jsPsychP5,
sketch: s_angle, // このトライアル用のスケッチ(関数)を指定
data: {
response: null,
}
}
// タイムライン
let luminance_block = {
// 0~2 の配列をシャッフル、ループに合わせて type に配列を順番に代入
return { bg: d };
}),
repetitions: 1,
randomize_order: true,
};
// タイムライン
let angle_block = {
timeline_variables: [...-5, 0, 5].map((d) => { return { angle: d };
}),
repetitions: 1,
randomize_order: true,
};
最後にHTMLファイル。demo01.htmlとします(ファイル名は何でも良いですが)。
code:html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My experiment</title>
<script src="jspsych-p5.js"></script>
<script src="demo01.js"></script>
</head>
<body></body>
Enjoy!!