init
python
This commit is contained in:
859
PCSurvey/survey.js
Normal file
859
PCSurvey/survey.js
Normal file
@@ -0,0 +1,859 @@
|
||||
"use strict";
|
||||
|
||||
var urlvar = jsPsych.data.urlVariables();
|
||||
var user_agent_string = navigator.userAgent;
|
||||
|
||||
function saveData(name, data) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "PCstatic/write_data.php");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(JSON.stringify({ filename: name, filedata: data }));
|
||||
}
|
||||
|
||||
var string_final = urlvar.campaign + urlvar.worker + urlvar.randkey;
|
||||
var verification = "mw-" + sha256(string_final);
|
||||
|
||||
// definiting two different response scales that can be used on the rating scales.
|
||||
var comp_option = ["No", "Small", "Visible", "Large", "Huge"];
|
||||
var total_option = ["Bad", "Poor", "Fair", "Good", "Excellent"];
|
||||
var better_option = ["Left", "Similar", "Right"];
|
||||
|
||||
var no_data = {
|
||||
type: "html-keyboard-response",
|
||||
stimulus:
|
||||
"<p>This task is only available with a valid workerID and campaignID.</p>",
|
||||
choices: jsPsych.NO_KEYS,
|
||||
};
|
||||
var full_data = {
|
||||
type: "html-keyboard-response",
|
||||
stimulus:
|
||||
"<p>We are sorry, the maximum amount of workers for this task has already been reached.</p>",
|
||||
choices: jsPsych.NO_KEYS,
|
||||
};
|
||||
var small_screen = {
|
||||
type: "html-keyboard-response",
|
||||
stimulus:
|
||||
"<p>Your browser screen size is only " +
|
||||
$(window).width() +
|
||||
"x" +
|
||||
$(window).height() +
|
||||
" pixels. For this study is must be at least 920x680 pixels. Try to switch your browser to fullscreen (press F11) or increase your screen resolution. Then reload this page.</p>",
|
||||
choices: jsPsych.NO_KEYS,
|
||||
};
|
||||
function checkSize() {
|
||||
if ($(window).width() < 920 || $(window).height() < 680) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The if's check that preconditions are met before the study can be started.
|
||||
var start_if = {
|
||||
timeline: [no_data],
|
||||
conditional_function: function () {
|
||||
if (urlvar.worker == null || urlvar.campaign == null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
var start_if2 = {
|
||||
timeline: [full_data],
|
||||
conditional_function: function () {
|
||||
return false;
|
||||
},
|
||||
}
|
||||
var start_if3 = {
|
||||
timeline: [small_screen],
|
||||
conditional_function: function () {
|
||||
return checkSize();
|
||||
},
|
||||
}
|
||||
// Predefined element position coordinates for each stimulus needed for evaluation block generation
|
||||
const positions_bremen = [[13, 13.5, 17], [31, 50, 2], [-65, -7, 9], [-40, -68, 3], [-35, 64, 4], [-5, 76, 1], [-18, 30, 0],[-15, -27, 0]];
|
||||
const positions_randersacker = [[-6, -7, 0.6],[-4.5, -18, 4],[-13, -33, -0.5],[-6, -14.5, -0.5], [8, -0.4, 1], [1.7, -8, 7.3]];
|
||||
|
||||
|
||||
// Build all possible test blocks, which are chosen dynamically later and actually used
|
||||
// Functions create based on tested condition jsTimelineObjects here: sequential with one element for each cloud
|
||||
const TQ0001 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q01", "bremen", twoRandomPositions(positions_bremen));
|
||||
const TQ0002 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q02", "bremen", twoRandomPositions(positions_bremen));
|
||||
const TQ0003 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q03", "bremen", twoRandomPositions(positions_bremen));
|
||||
const TQ0004 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q04", "bremen", twoRandomPositions(positions_bremen));
|
||||
const TQ0005 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q05", "bremen", twoRandomPositions(positions_bremen));
|
||||
const TQ0006 = generate_test_data_for_pointclouds_sequentiell("Q00", "Q06", "bremen", twoRandomPositions(positions_bremen));
|
||||
|
||||
const TQ1001 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q11", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
const TQ1002 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q12", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
const TQ1003 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q13", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
const TQ1004 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q14", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
const TQ1005 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q15", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
const TQ1006 = generate_test_data_for_pointclouds_sequentiell("Q10", "Q16", "randersacker", twoRandomPositions(positions_randersacker));
|
||||
|
||||
|
||||
/*
|
||||
// Example objects when testing for two elements
|
||||
const TQ0001 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "bremen", fourRandomPositions(positions_bremen));
|
||||
const TQ0002 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q02", "bremen", fourRandomPositions(positions_bremen));
|
||||
const TQ0003 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q03", "bremen", fourRandomPositions(positions_bremen));
|
||||
const TQ0004 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q04", "bremen", fourRandomPositions(positions_bremen));
|
||||
const TQ0005 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q05", "bremen", fourRandomPositions(positions_bremen));
|
||||
const TQ0006 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q06", "bremen", fourRandomPositions(positions_bremen));
|
||||
|
||||
const TQ1001 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
const TQ1002 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
const TQ1003 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
const TQ1004 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
const TQ1005 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
const TQ1006 = generate_test_data_for_pointclouds_sequentiell_2_elements("Q00", "Q01", "randersacker", fourRandomPositions(positions_randersacker));
|
||||
|
||||
|
||||
// Example objects when testing for three elements
|
||||
const TQ0001 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "bremen", sixRandomPositions(positions_bremen));
|
||||
const TQ0002 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q02", "bremen", sixRandomPositions(positions_bremen));
|
||||
const TQ0003 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q03", "bremen", sixRandomPositions(positions_bremen));
|
||||
const TQ0004 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q04", "bremen", sixRandomPositions(positions_bremen));
|
||||
const TQ0005 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q05", "bremen", sixRandomPositions(positions_bremen));
|
||||
const TQ0006 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q06", "bremen", sixRandomPositions(positions_bremen));
|
||||
|
||||
const TQ1001 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
const TQ1002 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
const TQ1003 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
const TQ1004 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
const TQ1005 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
const TQ1006 = generate_test_data_for_pointclouds_sequentiell_3_elements("Q00", "Q01", "randersacker", sixRandomPositions(positions_randersacker));
|
||||
*/
|
||||
|
||||
|
||||
// Functions that output evaluation blocks based on input. Input follows rules (see example inputs above).
|
||||
function generate_test_data_for_pointclouds_paired(cloudLeft, cloudRight, type, positions) {
|
||||
const letter1 = generateRandomLetter();
|
||||
const letter2 = generateRandomLetter();
|
||||
var data = [
|
||||
{
|
||||
data: {
|
||||
js_url: "PCstatic/js/pik.js",
|
||||
controlLetter1: letter1,
|
||||
controlLetter2: letter2,
|
||||
positions: positions,
|
||||
cloudRight: cloudRight,
|
||||
cloudLeft: cloudLeft,
|
||||
type: type,
|
||||
},
|
||||
timeline: [
|
||||
{ url: `potree/paired_comparison_template.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>Which point cloud looked better?</b>",
|
||||
options: better_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>What letter combination was displayed in the last point cloud?</b>",
|
||||
options: generiereUndMischePaar(letter1 + letter2),
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return data;
|
||||
}
|
||||
|
||||
function generate_test_data_for_pointclouds_sequentiell(
|
||||
cloudOne,
|
||||
cloudTwo,
|
||||
type,positions
|
||||
) {
|
||||
const letter1 = generateRandomLetter();
|
||||
const letter2 = generateRandomLetter();
|
||||
var data = [
|
||||
{
|
||||
data: {
|
||||
js_url: "PCstatic/js/pik.js",
|
||||
controlLetter1: letter1,
|
||||
controlLetter2: letter2,
|
||||
positions: positions,
|
||||
cloudOne: cloudOne,
|
||||
cloudTwo: cloudTwo,
|
||||
type: type,
|
||||
perspectives: [],
|
||||
tab_switch: 0,
|
||||
},
|
||||
timeline: [
|
||||
{ url: `potree/sequentiell_template.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>What letter/number was displayed in the last point cloud?</b>",
|
||||
options: generateRandomLetterChoice(letter1),
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ url: `potree/sequentiell_template2.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>How would you rate the difference compared to the previous point cloud?</b>",
|
||||
options: comp_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>What letter/number was displayed in the last point cloud?</b>",
|
||||
options: generateRandomLetterChoice(letter2),
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return data;
|
||||
}
|
||||
|
||||
function generate_test_data_for_pointclouds_sequentiell_2_elements(
|
||||
cloudOne,
|
||||
cloudTwo,
|
||||
type,positions
|
||||
) {
|
||||
const letter1 = generateRandomLetter();
|
||||
const letter2 = generateRandomLetter();
|
||||
const letter3 = generateRandomLetter();
|
||||
const letter4 = generateRandomLetter();
|
||||
var choices12 = generateRandomChoicesTwo(letter1, letter2);
|
||||
var choices34 = generateRandomChoicesTwo(letter3, letter4);
|
||||
var data = [
|
||||
{
|
||||
data: {
|
||||
js_url: "PCstatic/js/pik.js",
|
||||
controlLetter1: letter1,
|
||||
controlLetter2: letter2,
|
||||
controlLetter3: letter3,
|
||||
controlLetter4: letter4,
|
||||
positions: positions,
|
||||
cloudOne: cloudOne,
|
||||
cloudTwo: cloudTwo,
|
||||
type: type,
|
||||
perspectives: [],
|
||||
tab_switch: 0,
|
||||
},
|
||||
timeline: [
|
||||
{ url: `potree/sequentiell_template.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices12[0],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices12[1],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ url: `potree/sequentiell_template2.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>How would you rate the difference compared to the previous point cloud?</b>",
|
||||
options: comp_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices34[0],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices34[1],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return data;
|
||||
}
|
||||
|
||||
function generate_test_data_for_pointclouds_sequentiell_3_elements(
|
||||
cloudOne,
|
||||
cloudTwo,
|
||||
type,positions
|
||||
) {
|
||||
const letter1 = generateRandomLetter();
|
||||
const letter2 = generateRandomLetter();
|
||||
const letter3 = generateRandomLetter();
|
||||
const letter4 = generateRandomLetter();
|
||||
const letter5 = generateRandomLetter();
|
||||
const letter6 = generateRandomLetter();
|
||||
var choices123 = generateRandomChoicesThree(letter1, letter2, letter3);
|
||||
var choices456 = generateRandomChoicesThree(letter4, letter5, letter6);
|
||||
var data = [
|
||||
{
|
||||
data: {
|
||||
js_url: "PCstatic/js/pik.js",
|
||||
controlLetter1: letter1,
|
||||
controlLetter2: letter2,
|
||||
controlLetter3: letter3,
|
||||
controlLetter4: letter4,
|
||||
controlLetter5: letter5,
|
||||
controlLetter6: letter6,
|
||||
positions: positions,
|
||||
cloudOne: cloudOne,
|
||||
cloudTwo: cloudTwo,
|
||||
type: type,
|
||||
perspectives: [],
|
||||
tab_switch: 0,
|
||||
},
|
||||
timeline: [
|
||||
{ url: `potree/sequentiell_template.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices123[0],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices123[1],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices123[2],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ url: `potree/sequentiell_template2.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>How would you rate the difference compared to the previous point cloud?</b>",
|
||||
options: comp_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices456[0],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices456[1],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt:
|
||||
"<b>Which element was displayed in the last point cloud?</b>",
|
||||
options: choices456[2],
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return data;
|
||||
}
|
||||
|
||||
// Support functions for the main test object generation functions (see above)
|
||||
function twoRandomPositions(positions) {
|
||||
let randomIndex1 = Math.floor(Math.random() * positions.length);
|
||||
let randomIndex2 = Math.floor(Math.random() * positions.length);
|
||||
while (randomIndex1 == randomIndex2) {
|
||||
randomIndex2 = Math.floor(Math.random() * positions.length);
|
||||
}
|
||||
return [positions[randomIndex1], positions[randomIndex2]];
|
||||
}
|
||||
|
||||
function fourRandomPositions(positions) {
|
||||
if (positions.length < 4) {
|
||||
throw new Error("The positions array must contain at least 4 elements");
|
||||
}
|
||||
|
||||
let result = [];
|
||||
let availableIndices = [...Array(positions.length).keys()];
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let randomIndex = Math.floor(Math.random() * availableIndices.length);
|
||||
let selectedIndex = availableIndices[randomIndex];
|
||||
|
||||
result.push(positions[selectedIndex]);
|
||||
availableIndices.splice(randomIndex, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function sixRandomPositions(positions) {
|
||||
if (positions.length < 6) {
|
||||
throw new Error("The positions array must contain at least 6 elements");
|
||||
}
|
||||
|
||||
let result = [];
|
||||
let availableIndices = [...Array(positions.length).keys()];
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let randomIndex = Math.floor(Math.random() * availableIndices.length);
|
||||
let selectedIndex = availableIndices[randomIndex];
|
||||
|
||||
result.push(positions[selectedIndex]);
|
||||
availableIndices.splice(randomIndex, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
function generateRandomLetter() {
|
||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
|
||||
const randomIndex = Math.floor(Math.random() * 35);
|
||||
return alphabet[randomIndex];
|
||||
}
|
||||
|
||||
function generateRandomLetterChoice(initialLetter) {
|
||||
let choices = [initialLetter];
|
||||
|
||||
while (choices.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices.includes(newLetter)) {
|
||||
choices.push(newLetter);
|
||||
}
|
||||
}
|
||||
//durchmischen des arrays
|
||||
for (let i = choices.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices[i], choices[j]] = [choices[j], choices[i]];
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
|
||||
function generateRandomChoicesTwo(initialElement1, initialElement2) {
|
||||
let choices1 = [initialElement1];
|
||||
let choices2 = [initialElement2];
|
||||
|
||||
while (choices1.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices1.includes(newLetter) && newLetter != initialElement2) {
|
||||
choices1.push(newLetter);
|
||||
}
|
||||
}
|
||||
//durchmischen des arrays
|
||||
for (let i = choices1.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices1[i], choices1[j]] = [choices1[j], choices1[i]];
|
||||
}
|
||||
|
||||
while (choices2.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices2.includes(newLetter) && !choices1.includes(newLetter)) {
|
||||
choices2.push(newLetter);
|
||||
}
|
||||
}
|
||||
|
||||
//durchmischen des arrays
|
||||
for (let i = choices2.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices2[i], choices2[j]] = [choices2[j], choices2[i]];
|
||||
}
|
||||
return [choices1, choices2];
|
||||
}
|
||||
|
||||
function generateRandomChoicesThree(initialElement1, initialElement2, initialElement3) {
|
||||
let choices1 = [initialElement1];
|
||||
let choices2 = [initialElement2];
|
||||
let choices3 = [initialElement3];
|
||||
|
||||
while (choices1.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices1.includes(newLetter) && newLetter != initialElement2 && newLetter != initialElement3) {
|
||||
choices1.push(newLetter);
|
||||
}
|
||||
}
|
||||
//durchmischen des arrays
|
||||
for (let i = choices1.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices1[i], choices1[j]] = [choices1[j], choices1[i]];
|
||||
}
|
||||
|
||||
while (choices2.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices2.includes(newLetter) && !choices1.includes(newLetter) && newLetter != initialElement3) {
|
||||
choices2.push(newLetter);
|
||||
}
|
||||
}
|
||||
|
||||
//durchmischen des arrays
|
||||
for (let i = choices2.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices2[i], choices2[j]] = [choices2[j], choices2[i]];
|
||||
}
|
||||
|
||||
while (choices3.length < 10) {
|
||||
let newLetter = generateRandomLetter();
|
||||
if (!choices3.includes(newLetter) && !choices1.includes(newLetter) && !choices2.includes(newLetter)) {
|
||||
choices3.push(newLetter);
|
||||
}
|
||||
}
|
||||
|
||||
//durchmischen des arrays
|
||||
for (let i = choices3.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[choices3[i], choices3[j]] = [choices3[j], choices3[i]];
|
||||
}
|
||||
|
||||
return [choices1, choices2, choices3];
|
||||
}
|
||||
|
||||
function generiereUndMischePaar(initialesPaar) {
|
||||
// Funktion, um ein zufälliges Paar von Buchstaben zu generieren
|
||||
function zufaelligesPaar() {
|
||||
return generateRandomLetter() + generateRandomLetter();
|
||||
}
|
||||
|
||||
// Initialisiert das Array mit dem übergebenen Paar
|
||||
let paare = [initialesPaar];
|
||||
|
||||
// Generiert 9 zufällige Paare
|
||||
while (paare.length < 10) {
|
||||
let neuesPaar = zufaelligesPaar();
|
||||
// Stellt sicher, dass das generierte Paar einzigartig ist
|
||||
if (!paare.includes(neuesPaar)) {
|
||||
paare.push(neuesPaar);
|
||||
}
|
||||
}
|
||||
|
||||
// Mischung des Arrays
|
||||
for (let i = paare.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[paare[i], paare[j]] = [paare[j], paare[i]];
|
||||
}
|
||||
|
||||
return paare;
|
||||
}
|
||||
|
||||
// Create 4 Block timeline with 2 Randersacker and 2 Bremen
|
||||
// Uses previously generated test blocks
|
||||
function generateBlockSequence() {
|
||||
const test_data_bremen_seq = [
|
||||
TQ0001,
|
||||
TQ0002,
|
||||
TQ0003,
|
||||
TQ0004,
|
||||
TQ0005,
|
||||
TQ0006,
|
||||
];
|
||||
const test_data_randersacker_seq = [
|
||||
TQ1001,
|
||||
TQ1002,
|
||||
TQ1003,
|
||||
TQ1004,
|
||||
TQ1005,
|
||||
TQ1006,
|
||||
];
|
||||
const block_sequence = [];
|
||||
if (Math.random() < 0.5) {
|
||||
//zuerst 2 zufällige Bremen, dann 2 zufällige Randersacker
|
||||
let randomIndex1 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
let randomIndex2 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
while (randomIndex1 == randomIndex2) {
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
}
|
||||
block_sequence.push(test_data_bremen_seq[randomIndex1]);
|
||||
block_sequence.push(test_data_bremen_seq[randomIndex2]);
|
||||
|
||||
randomIndex1 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
while (randomIndex1 == randomIndex2) {
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
}
|
||||
block_sequence.push(test_data_randersacker_seq[randomIndex1]);
|
||||
block_sequence.push(test_data_randersacker_seq[randomIndex2]);
|
||||
|
||||
} else {
|
||||
//zuerst 2 zufällige Randersacker, dann 2 zufällige Bremen
|
||||
let randomIndex1 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
let randomIndex2 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
while (randomIndex1 == randomIndex2) {
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_randersacker_seq.length);
|
||||
}
|
||||
block_sequence.push(test_data_randersacker_seq[randomIndex1]);
|
||||
block_sequence.push(test_data_randersacker_seq[randomIndex2]);
|
||||
|
||||
randomIndex1 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
while (randomIndex1 == randomIndex2) {
|
||||
randomIndex2 = Math.floor(Math.random() * test_data_bremen_seq.length);
|
||||
}
|
||||
block_sequence.push(test_data_bremen_seq[randomIndex1]);
|
||||
block_sequence.push(test_data_bremen_seq[randomIndex2]);
|
||||
}
|
||||
return block_sequence;
|
||||
}
|
||||
var test_data = generateBlockSequence();
|
||||
|
||||
// jsTimelineObjs containing pages for introduction, information and instructions
|
||||
var welcome = {
|
||||
type: "external-html",
|
||||
url: "PCstatic/html/welcome.html",
|
||||
cont_btn: "consent",
|
||||
executeScript: true,
|
||||
};
|
||||
var instructions0 = {
|
||||
type: "external-html",
|
||||
url: "PCstatic/html/instructions_P0.html",
|
||||
cont_btn: "consent",
|
||||
executeScript: true,
|
||||
};
|
||||
var instructions1 = {
|
||||
type: "external-html",
|
||||
url: "PCstatic/html/instructions_P1_no_ emphasis_quality.html",
|
||||
cont_btn: "consent",
|
||||
executeScript: true,
|
||||
};
|
||||
var instructions2 = {
|
||||
type: "external-html",
|
||||
url: "PCstatic/html/instructions_P2.html",
|
||||
cont_btn: "consent",
|
||||
executeScript: true,
|
||||
};
|
||||
var post_test_survey = {
|
||||
// still just a test
|
||||
type: "survey-text",
|
||||
preamble: "<h3>One last question</h3>",
|
||||
questions: [
|
||||
{
|
||||
prompt:
|
||||
"What made a point cloud look good or bad? Please describe on what you have focused most. Also write any feedback here.",
|
||||
rows: 10,
|
||||
columns: 100,
|
||||
},
|
||||
],
|
||||
on_finish: function () {
|
||||
var interaction_data = jsPsych.data.getInteractionData();
|
||||
jsPsych.data.get().addToLast({
|
||||
interaction: interaction_data.json(),
|
||||
useragent: user_agent_string,
|
||||
campaign: urlvar.campaign,
|
||||
worker: urlvar.worker,
|
||||
randkey: urlvar.randkey,
|
||||
verificationcode: verification,
|
||||
});
|
||||
},
|
||||
};
|
||||
var debrief_block = {
|
||||
type: "instructions",
|
||||
allow_keys: false,
|
||||
pages: [
|
||||
'<p>Thank you very much for your participation.' +
|
||||
'<p>Your Microworkers verification code is: <b>'+verification+'</b></p>' +
|
||||
'<p>Please copy this code to Microworkers to receive your payment, afterwards you can close this window.</p>' +
|
||||
'<p>----------------------------------------------------------------------------------------------------</p>' +
|
||||
"<b>What have we tested?</b>" +
|
||||
"<p>Two methods of reduction are presented alongside the original. The first, known as octree can be described as follows:</p>"+
|
||||
"<p>The number of points per volume in the cloud is higher in the inner regions and lower in the outer regions. They can be saved as Octrees.</p>" +
|
||||
'<img id="Bsp1" style="width:600px;height:300px;margin:10px" src="PCstatic/img/Octree.png" />' +
|
||||
"<p>The space of the cloud is divided into 8 sections, which can be subdivided again. The leaves of the tree are the points.</p>" +
|
||||
"<p>One method to reduce a point cloud is to subdivide the Octree to a certain size. Then only allow a certain maximum amount of points per leaf (e.g. 2). This especially reduces the cloud in very dense regions and leaves the sparse regions untouched.</p>" +
|
||||
"<p>Another method is to project the point cloud onto a sphere and then project the sphere onto a 2D picture (similar to 2D maps of earth). The picture is now reduced in size and then converted back into a point cloud.</p>" +
|
||||
"<p>These and other methods were tested in the survey together with other factors that could influence the QoE of a viewer.</p>" +
|
||||
"<br>" +
|
||||
"<p>Thank you again for your participation!</p>" +
|
||||
"<br>",
|
||||
],
|
||||
on_load: function () {
|
||||
jsPsych.data
|
||||
.get()
|
||||
.addToLast({ Window: $(window).width() + "x" + $(window).height() });
|
||||
saveData(taskName + "data", jsPsych.data.get().json());
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// creates jsTimelineObj for the trial/test run
|
||||
let letter1 = generateRandomLetter();
|
||||
let choices = generateRandomLetterChoice(letter1);
|
||||
let cloudOne = "trial";
|
||||
let positions = [
|
||||
[0, 0, 0],
|
||||
];
|
||||
let trial_run = {
|
||||
type: "external-html",
|
||||
cont_btn: "end-trial",
|
||||
executeScript: true,
|
||||
data: {
|
||||
js_url: "PCstatic/js/pik.js",
|
||||
controlLetter1: letter1,
|
||||
positions: positions,
|
||||
cloudOne: cloudOne,
|
||||
type: "trial",
|
||||
},
|
||||
timeline: [
|
||||
{ url: `potree/sequentiell_template.html` },
|
||||
{
|
||||
type: "survey-multi-choice",
|
||||
questions: [
|
||||
{
|
||||
prompt: "<b>How would you rate the Point Cloud?</b>",
|
||||
options: total_option,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
{
|
||||
prompt: "<b>What element was displayed in the last point cloud?</b>",
|
||||
options: choices,
|
||||
required: true,
|
||||
horizontal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
let feedback_trial = {
|
||||
type: "external-html",
|
||||
url: "PCstatic/html/feedback_no_emphasis_quality.html",
|
||||
executeScript: true,
|
||||
cont_btn: "end-trial",
|
||||
};
|
||||
|
||||
const testRunLoop = {
|
||||
timeline: [trial_run, feedback_trial],
|
||||
loop_function: function (data) {
|
||||
var responses = JSON.parse(
|
||||
jsPsych.data.get().last(2).select("responses").values
|
||||
);
|
||||
var controlLetter1 = jsPsych.data.get().last(2).select("controlLetter1")
|
||||
.values[0];
|
||||
|
||||
if (responses.Q1 != controlLetter1) {
|
||||
//repeat the loop
|
||||
new Notification("Test Run Feedback");
|
||||
return true;
|
||||
} else {
|
||||
//end the loop
|
||||
false;
|
||||
}
|
||||
},
|
||||
};
|
||||
jsPsych.data.addProperties();
|
||||
|
||||
|
||||
// Now build the timeline for the study run. Push all desired objects into it in the correct order
|
||||
var timeline = [];
|
||||
|
||||
timeline.push(start_if)
|
||||
timeline.push(start_if2)
|
||||
timeline.push(start_if3)
|
||||
timeline.push(welcome);
|
||||
timeline.push(instructions0)
|
||||
timeline.push(instructions1)
|
||||
timeline.push(instructions2)
|
||||
timeline.push(testRunLoop);
|
||||
|
||||
test_data.forEach(function (this_test) {
|
||||
var test_block = {
|
||||
type: "external-html",
|
||||
timeline: this_test,
|
||||
executeScript: true,
|
||||
cont_btn: "end-trial",
|
||||
force_refresh: true,
|
||||
};
|
||||
timeline.push(test_block);
|
||||
});
|
||||
|
||||
timeline.push(post_test_survey);
|
||||
|
||||
// When this block is reached, the captured data is saved
|
||||
timeline.push(debrief_block);
|
||||
|
||||
//jsPsych init function starts test.
|
||||
jsPsych.init({
|
||||
timeline: timeline,
|
||||
show_progress_bar: true,
|
||||
});
|
||||
Reference in New Issue
Block a user