psychopy.org | Reference | Downloads | Github

Changing the slider marker size in Javascript

URL of experiment: https://pavlovia.org/arkadiym/affective_slider

Description of the problem: When I upload the psychopy experiment to Pavlovia, the slider changes that are implemented in the Psychopy code, within “begin routine” are lost.

Original modifications to the slider that are written in the psychopy code/begin routine are as follows:

Slider1.marker.size=(.05,.05)
Slider1.marker.color=“black”
Slider2.marker.size=(.05,.05)
Slider2.marker.color=“black”

Does anyone know where I can implement these changes within the Javascript code for them to take effect?

Any advice would be greatly appreciated.
best,
Arkadiy

I am posting the JS code here, in case someone might be able to suggest where I can implement the changes to increase the marker size and change it’s color to black:

/************************* 
 * Affective_Slider Test *
 *************************/

import { PsychoJS } from 'https://pavlovia.org/lib/core-3.2.js';
import * as core from 'https://pavlovia.org/lib/core-3.2.js';
import { TrialHandler } from 'https://pavlovia.org/lib/data-3.2.js';
import { Scheduler } from 'https://pavlovia.org/lib/util-3.2.js';
import * as util from 'https://pavlovia.org/lib/util-3.2.js';
import * as visual from 'https://pavlovia.org/lib/visual-3.2.js';
import { Sound } from 'https://pavlovia.org/lib/sound-3.2.js';

// init psychoJS:
var psychoJS = new PsychoJS({
  debug: true
});

// open window:
psychoJS.openWindow({
  fullscr: true,
  color: new util.Color([0, 0, 0]),
  units: 'height',
  waitBlanking: true
});

// store info about the experiment session:
let expName = 'affective_slider';  // from the Builder filename that created this script
let expInfo = {'participant': '', 'session': '001'};

// schedule the experiment:
psychoJS.schedule(psychoJS.gui.DlgFromDict({
  dictionary: expInfo,
  title: expName
}));

const flowScheduler = new Scheduler(psychoJS);
const dialogCancelScheduler = new Scheduler(psychoJS);
psychoJS.scheduleCondition(function() { return (psychoJS.gui.dialogComponent.button === 'OK'); }, flowScheduler, dialogCancelScheduler);

// flowScheduler gets run if the participants presses OK
flowScheduler.add(updateInfo); // add timeStamp
flowScheduler.add(experimentInit);
flowScheduler.add(trialRoutineBegin);
flowScheduler.add(trialRoutineEachFrame);
flowScheduler.add(trialRoutineEnd);
flowScheduler.add(quitPsychoJS, '', true);

// quit if user presses Cancel in dialog box:
dialogCancelScheduler.add(quitPsychoJS, '', false);

psychoJS.start({expName, expInfo});

var frameDur;
function updateInfo() {
  expInfo['date'] = util.MonotonicClock.getDateStr();  // add a simple timestamp
  expInfo['expName'] = expName;
  expInfo['psychopyVersion'] = '3.2.4';
  expInfo['OS'] = window.navigator.platform;

  // store frame rate of monitor if we can measure it successfully
  expInfo['frameRate'] = psychoJS.window.getActualFrameRate();
  if (typeof expInfo['frameRate'] !== 'undefined')
    frameDur = 1.0/Math.round(expInfo['frameRate']);
  else
    frameDur = 1.0/60.0; // couldn't get a reliable measure so guess

  // add info from the URL:
  util.addInfoFromUrl(expInfo);
  
  return Scheduler.Event.NEXT;
}

var trialClock;
var Slider1;
var Intensity_Cue_1;
var Intensity_Cue_2;
var Happy;
var Unhappy;
var wideawake;
var sleepy;
var Slider2;
var key_resp;
var globalClock;
var routineTimer;
function experimentInit() {
  // Initialize components for Routine "trial"
  trialClock = new util.Clock();
  Slider1 = new visual.Slider({
    win: psychoJS.window, name: 'Slider1',
    size: [0.97, 0.01], pos: [0, (- 0.35)], units: 'height',
    labels: undefined, ticks: [0, 100],
    granularity: 0, style: [visual.Slider.Style.RATING],
    color: new util.Color('white'), 
    fontFamily: 'Arial', bold: true, italic: false, 
    flip: false,
  });
  
  Intensity_Cue_1 = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Intensity_Cue_1', units : undefined, 
    image : 'PNGs/AS_intensity_cue.png', mask : undefined,
    ori : 0, pos : [0, (- 0.2)], size : [1, 0.07],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -1.0 
  });
  Intensity_Cue_2 = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Intensity_Cue_2', units : undefined, 
    image : 'PNGs/AS_intensity_cue.png', mask : undefined,
    ori : 0, pos : [0, (- 0.42)], size : [1, 0.07],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -2.0 
  });
  Happy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Happy', units : undefined, 
    image : 'PNGs/AS_happy.png', mask : undefined,
    ori : 0, pos : [0.56, (- 0.39)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -3.0 
  });
  Unhappy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Unhappy', units : undefined, 
    image : 'PNGs/AS_unhappy.png', mask : undefined,
    ori : 0, pos : [(- 0.56), (- 0.39)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -4.0 
  });
  wideawake = new visual.ImageStim({
    win : psychoJS.window,
    name : 'wideawake', units : undefined, 
    image : 'PNGs/AS_wideawake.png', mask : undefined,
    ori : 0, pos : [0.56, (- 0.17)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -5.0 
  });
  sleepy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'sleepy', units : undefined, 
    image : 'PNGs/AS_sleepy.png', mask : undefined,
    ori : 0, pos : [(- 0.56), (- 0.17)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -6.0 
  });
  Slider2 = new visual.Slider({
    win: psychoJS.window, name: 'Slider2',
    size: [0.97, 0.01], pos: [0, (- 0.13)], units: 'height',
    labels: undefined, ticks: [1, 100],
    granularity: 0, style: [visual.Slider.Style.RATING],
    color: new util.Color('white'), 
    fontFamily: 'HelveticaBold', bold: true, italic: false, 
    flip: false,
  });
  
  key_resp = new core.Keyboard({psychoJS, clock: new util.Clock(), waitForStart: true});
  
  // Create some handy timers
  globalClock = new util.Clock();  // to track the time since experiment started
  routineTimer = new util.CountdownTimer();  // to track time remaining of each (non-slip) routine
  
  return Scheduler.Event.NEXT;
}

var t;
var frameN;
var trialComponents;
function trialRoutineBegin() {
  //------Prepare to start Routine 'trial'-------
  t = 0;
  trialClock.reset(); // clock
  frameN = -1;
  // update component parameters for each repeat
  Slider1.reset()
  Slider2.reset()
  key_resp.keys = undefined;
  key_resp.rt = undefined;
  // keep track of which components have finished
  trialComponents = [];
  trialComponents.push(Slider1);
  trialComponents.push(Intensity_Cue_1);
  trialComponents.push(Intensity_Cue_2);
  trialComponents.push(Happy);
  trialComponents.push(Unhappy);
  trialComponents.push(wideawake);
  trialComponents.push(sleepy);
  trialComponents.push(Slider2);
  trialComponents.push(key_resp);
  
  for (const thisComponent of trialComponents)
    if ('status' in thisComponent)
      thisComponent.status = PsychoJS.Status.NOT_STARTED;
  
  return Scheduler.Event.NEXT;
}

var continueRoutine;
function trialRoutineEachFrame() {
  //------Loop for each frame of Routine 'trial'-------
  let continueRoutine = true; // until we're told otherwise
  // get current time
  t = trialClock.getTime();
  frameN = frameN + 1;// number of completed frames (so 0 is the first frame)
  // update/draw components on each frame
  
  // *Slider1* updates
  if (t >= 0.0 && Slider1.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Slider1.tStart = t;  // (not accounting for frame time here)
    Slider1.frameNStart = frameN;  // exact frame index
    Slider1.setAutoDraw(true);
  }

  
  // *Intensity_Cue_1* updates
  if (t >= 0.0 && Intensity_Cue_1.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Intensity_Cue_1.tStart = t;  // (not accounting for frame time here)
    Intensity_Cue_1.frameNStart = frameN;  // exact frame index
    Intensity_Cue_1.setAutoDraw(true);
  }

  
  // *Intensity_Cue_2* updates
  if (t >= 0.0 && Intensity_Cue_2.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Intensity_Cue_2.tStart = t;  // (not accounting for frame time here)
    Intensity_Cue_2.frameNStart = frameN;  // exact frame index
    Intensity_Cue_2.setAutoDraw(true);
  }

  
  // *Happy* updates
  if (t >= 0.0 && Happy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Happy.tStart = t;  // (not accounting for frame time here)
    Happy.frameNStart = frameN;  // exact frame index
    Happy.setAutoDraw(true);
  }

  
  // *Unhappy* updates
  if (t >= 0.0 && Unhappy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Unhappy.tStart = t;  // (not accounting for frame time here)
    Unhappy.frameNStart = frameN;  // exact frame index
    Unhappy.setAutoDraw(true);
  }

  
  // *wideawake* updates
  if (t >= 0.0 && wideawake.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    wideawake.tStart = t;  // (not accounting for frame time here)
    wideawake.frameNStart = frameN;  // exact frame index
    wideawake.setAutoDraw(true);
  }

  
  // *sleepy* updates
  if (t >= 0.0 && sleepy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    sleepy.tStart = t;  // (not accounting for frame time here)
    sleepy.frameNStart = frameN;  // exact frame index
    sleepy.setAutoDraw(true);
  }

  
  // *Slider2* updates
  if (t >= 0.0 && Slider2.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Slider2.tStart = t;  // (not accounting for frame time here)
    Slider2.frameNStart = frameN;  // exact frame index
    Slider2.setAutoDraw(true);
  }

  
  // *key_resp* updates
  if (t >= 0.0 && key_resp.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    key_resp.tStart = t;  // (not accounting for frame time here)
    key_resp.frameNStart = frameN;  // exact frame index
    // keyboard checking is just starting
    psychoJS.window.callOnFlip(function() { key_resp.clock.reset(); });  // t=0 on next screen flip
    psychoJS.window.callOnFlip(function() { key_resp.start(); }); // start on screen flip
    psychoJS.window.callOnFlip(function() { key_resp.clearEvents(); });
  }

  if (key_resp.status === PsychoJS.Status.STARTED) {
    let theseKeys = key_resp.getKeys({keyList: ['space'], waitRelease: false});
    
    // check for quit:
    if (theseKeys.length > 0 && theseKeys[0].name === 'escape') {
      psychoJS.experiment.experimentEnded = true;
    }
    
    if (theseKeys.length > 0) {  // at least one key was pressed
      key_resp.keys = theseKeys[0].name;  // just the last key pressed
      key_resp.rt = theseKeys[0].rt;
      // a response ends the routine
      continueRoutine = false;
    }
  }
  
  // check for quit (typically the Esc key)
  if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) {
    return psychoJS.quit('The [Escape] key was pressed. Goodbye!', false);
  }
  
  // check if the Routine should terminate
  if (!continueRoutine) {  // a component has requested a forced-end of Routine
    return Scheduler.Event.NEXT;
  }
  
  continueRoutine = false;  // reverts to True if at least one component still running
  for (const thisComponent of trialComponents)
    if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) {
      continueRoutine = true;
      break;
    }
  
  // refresh the screen if continuing
  if (continueRoutine) {
    return Scheduler.Event.FLIP_REPEAT;
  }
  else {
    return Scheduler.Event.NEXT;
  }
}


function trialRoutineEnd() {
  //------Ending Routine 'trial'-------
  for (const thisComponent of trialComponents) {
    if (typeof thisComponent.setAutoDraw === 'function') {
      thisComponent.setAutoDraw(false);
    }
  }
  psychoJS.experiment.addData('Slider1.response', Slider1.getRating());
  psychoJS.experiment.addData('Slider1.rt', Slider1.getRT());
  psychoJS.experiment.addData('Slider2.response', Slider2.getRating());
  psychoJS.experiment.addData('Slider2.rt', Slider2.getRT());
  psychoJS.experiment.addData('key_resp.keys', key_resp.keys);
  if (typeof key_resp.keys !== undefined) {  // we had a response
      psychoJS.experiment.addData('key_resp.rt', key_resp.rt);
      routineTimer.reset();
      }
  
  key_resp.stop();
  // the Routine "trial" was not non-slip safe, so reset the non-slip timer
  routineTimer.reset();
  
  return Scheduler.Event.NEXT;
}


function endLoopIteration({thisScheduler, isTrials=true}) {
  // ------Prepare for next entry------
  return function () {
    // ------Check if user ended loop early------
    if (currentLoop.finished) {
      // Check for and save orphaned data
      if (Object.keys(psychoJS.experiment._thisEntry).length > 0) {
        psychoJS.experiment.nextEntry();
      }
      thisScheduler.stop();
    } else if (isTrials) {
      psychoJS.experiment.nextEntry();
    }
  return Scheduler.Event.NEXT;
  };
}


function importConditions(loop) {
  const trialIndex = loop.getTrialIndex();
  return function () {
    loop.setTrialIndex(trialIndex);
    psychoJS.importAttributes(loop.getCurrentTrial());
    return Scheduler.Event.NEXT;
    };
}


function quitPsychoJS(message, isCompleted) {
  // Check for and save orphaned data
  if (Object.keys(psychoJS.experiment._thisEntry).length > 0) {
    psychoJS.experiment.nextEntry();
  }
  psychoJS.window.close();
  psychoJS.quit({message: message, isCompleted: isCompleted});

  return Scheduler.Event.QUIT;
}

Hi @arkadiy, I think in your last example you had not translated the code component from Python to JS. In the code component dialog, you can set your code type to “both” and see the Python (left) and JS (right) side by side to help translation. This is how you can set the marker size and color for your online task: Using a code component, with code in the relevant tabs (see comments):

// Begin Experiment
col = new util.Color('black')  // Create your color once
newMarkerSize = 35  // in pixels

// Each Frame
try {
    if (slider._markerColor.int !== col.int) {
        slider._markerColor = col;
        slider._marker.lineStyle(1, col.int, 1, 0.5);
        slider._marker.beginFill(col.int, 1);
        slider._marker.drawCircle(0, 0, newMarkerSize / 2);
        slider._marker.endFill();
        slider._needUpdate = true;
        slider._updateIfNeeded();
     }
} catch (err) {}

Hi @dvbridges, thank you for this suggestion.
I included the code you suggested in the code component in Psychopy (screenshots below), synced it with Pavlovia, but the marker size is still not affected.

I created a separate program with just the slider, to make things easier for this troubleshooting (https://pavlovia.org/arkadiym/affective_slider). Please see below for the code after syncing. Wondering if you might be able to catch an issue here that I am missing. Thank you so much for helping troubleshoot this!

/************************* 
 * Affective_Slider Test *
 *************************/

import { PsychoJS } from 'https://pavlovia.org/lib/core-3.2.js';
import * as core from 'https://pavlovia.org/lib/core-3.2.js';
import { TrialHandler } from 'https://pavlovia.org/lib/data-3.2.js';
import { Scheduler } from 'https://pavlovia.org/lib/util-3.2.js';
import * as util from 'https://pavlovia.org/lib/util-3.2.js';
import * as visual from 'https://pavlovia.org/lib/visual-3.2.js';
import { Sound } from 'https://pavlovia.org/lib/sound-3.2.js';

// init psychoJS:
var psychoJS = new PsychoJS({
  debug: true
});

// open window:
psychoJS.openWindow({
  fullscr: true,
  color: new util.Color([0, 0, 0]),
  units: 'height',
  waitBlanking: true
});

// store info about the experiment session:
let expName = 'affective_slider';  // from the Builder filename that created this script
let expInfo = {'participant': '', 'session': '001'};

// schedule the experiment:
psychoJS.schedule(psychoJS.gui.DlgFromDict({
  dictionary: expInfo,
  title: expName
}));

const flowScheduler = new Scheduler(psychoJS);
const dialogCancelScheduler = new Scheduler(psychoJS);
psychoJS.scheduleCondition(function() { return (psychoJS.gui.dialogComponent.button === 'OK'); }, flowScheduler, dialogCancelScheduler);

// flowScheduler gets run if the participants presses OK
flowScheduler.add(updateInfo); // add timeStamp
flowScheduler.add(experimentInit);
flowScheduler.add(trialRoutineBegin);
flowScheduler.add(trialRoutineEachFrame);
flowScheduler.add(trialRoutineEnd);
flowScheduler.add(quitPsychoJS, '', true);

// quit if user presses Cancel in dialog box:
dialogCancelScheduler.add(quitPsychoJS, '', false);

psychoJS.start({expName, expInfo});

var frameDur;
function updateInfo() {
  expInfo['date'] = util.MonotonicClock.getDateStr();  // add a simple timestamp
  expInfo['expName'] = expName;
  expInfo['psychopyVersion'] = '3.2.4';
  expInfo['OS'] = window.navigator.platform;

  // store frame rate of monitor if we can measure it successfully
  expInfo['frameRate'] = psychoJS.window.getActualFrameRate();
  if (typeof expInfo['frameRate'] !== 'undefined')
    frameDur = 1.0/Math.round(expInfo['frameRate']);
  else
    frameDur = 1.0/60.0; // couldn't get a reliable measure so guess

  // add info from the URL:
  util.addInfoFromUrl(expInfo);
  
  return Scheduler.Event.NEXT;
}

var trialClock;
var Slider1;
var Intensity_Cue_1;
var Intensity_Cue_2;
var Happy;
var Unhappy;
var wideawake;
var sleepy;
var col;
var newMarkerSize;
var Slider2;
var key_resp;
var globalClock;
var routineTimer;
function experimentInit() {
  // Initialize components for Routine "trial"
  trialClock = new util.Clock();
  Slider1 = new visual.Slider({
    win: psychoJS.window, name: 'Slider1',
    size: [0.97, 0.01], pos: [0, (- 0.35)], units: 'height',
    labels: undefined, ticks: [0, 100],
    granularity: 0, style: [visual.Slider.Style.RATING],
    color: new util.Color('white'), 
    fontFamily: 'Arial', bold: true, italic: false, 
    flip: false,
  });
  
  Intensity_Cue_1 = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Intensity_Cue_1', units : undefined, 
    image : 'PNGs/AS_intensity_cue.png', mask : undefined,
    ori : 0, pos : [0, (- 0.2)], size : [1, 0.07],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -1.0 
  });
  Intensity_Cue_2 = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Intensity_Cue_2', units : undefined, 
    image : 'PNGs/AS_intensity_cue.png', mask : undefined,
    ori : 0, pos : [0, (- 0.42)], size : [1, 0.07],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -2.0 
  });
  Happy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Happy', units : undefined, 
    image : 'PNGs/AS_happy.png', mask : undefined,
    ori : 0, pos : [0.56, (- 0.39)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -3.0 
  });
  Unhappy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'Unhappy', units : undefined, 
    image : 'PNGs/AS_unhappy.png', mask : undefined,
    ori : 0, pos : [(- 0.56), (- 0.39)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -4.0 
  });
  wideawake = new visual.ImageStim({
    win : psychoJS.window,
    name : 'wideawake', units : undefined, 
    image : 'PNGs/AS_wideawake.png', mask : undefined,
    ori : 0, pos : [0.56, (- 0.17)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -5.0 
  });
  sleepy = new visual.ImageStim({
    win : psychoJS.window,
    name : 'sleepy', units : undefined, 
    image : 'PNGs/AS_sleepy.png', mask : undefined,
    ori : 0, pos : [(- 0.56), (- 0.17)], size : [0.13, 0.13],
    color : new util.Color([1, 1, 1]), opacity : 1,
    flipHoriz : false, flipVert : false,
    texRes : 128, interpolate : true, depth : -6.0 
  });
  // Begin Experiment
  col = new util.Color('black')  // Create your color once
  newMarkerSize = 100  // in pixels
  Slider2 = new visual.Slider({
    win: psychoJS.window, name: 'Slider2',
    size: [0.97, 0.01], pos: [0, (- 0.13)], units: 'height',
    labels: undefined, ticks: [1, 100],
    granularity: 0, style: [visual.Slider.Style.RATING],
    color: new util.Color('white'), 
    fontFamily: 'HelveticaBold', bold: true, italic: false, 
    flip: false,
  });
  
  key_resp = new core.Keyboard({psychoJS, clock: new util.Clock(), waitForStart: true});
  
  // Create some handy timers
  globalClock = new util.Clock();  // to track the time since experiment started
  routineTimer = new util.CountdownTimer();  // to track time remaining of each (non-slip) routine
  
  return Scheduler.Event.NEXT;
}

var t;
var frameN;
var trialComponents;
function trialRoutineBegin() {
  //------Prepare to start Routine 'trial'-------
  t = 0;
  trialClock.reset(); // clock
  frameN = -1;
  // update component parameters for each repeat
  Slider1.reset()
  // Each Frame
  try {
      if (Slider1.markerColor.int !== col.int) {
          Slider1.markerColor = col;
          Slider1.marker.lineStyle(1, col.int, 1, 0.5);
          Slider1.marker.beginFill(col.int, 1);
          Slider1.marker.drawCircle(0, 0, newMarkerSize / 2);
          Slider1.marker.endFill();
          Slider1.needUpdate = true;
          Slider1.updateIfNeeded();
       }
  } catch (err) {}
  try {
      if (Slider2.markerColor.int !== col.int) {
          Slider2.markerColor = col;
          Slider2.marker.lineStyle(1, col.int, 1, 0.5);
          Slider2.marker.beginFill(col.int, 1);
          Slider2.marker.drawCircle(0, 0, newMarkerSize / 2);
          Slider2.marker.endFill();
          Slider2.needUpdate = true;
          Slider2.updateIfNeeded();
       }
  } catch (err) {}
  Slider2.reset()
  key_resp.keys = undefined;
  key_resp.rt = undefined;
  // keep track of which components have finished
  trialComponents = [];
  trialComponents.push(Slider1);
  trialComponents.push(Intensity_Cue_1);
  trialComponents.push(Intensity_Cue_2);
  trialComponents.push(Happy);
  trialComponents.push(Unhappy);
  trialComponents.push(wideawake);
  trialComponents.push(sleepy);
  trialComponents.push(Slider2);
  trialComponents.push(key_resp);
  
  for (const thisComponent of trialComponents)
    if ('status' in thisComponent)
      thisComponent.status = PsychoJS.Status.NOT_STARTED;
  
  return Scheduler.Event.NEXT;
}

var continueRoutine;
function trialRoutineEachFrame() {
  //------Loop for each frame of Routine 'trial'-------
  let continueRoutine = true; // until we're told otherwise
  // get current time
  t = trialClock.getTime();
  frameN = frameN + 1;// number of completed frames (so 0 is the first frame)
  // update/draw components on each frame
  
  // *Slider1* updates
  if (t >= 0.0 && Slider1.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Slider1.tStart = t;  // (not accounting for frame time here)
    Slider1.frameNStart = frameN;  // exact frame index
    Slider1.setAutoDraw(true);
  }

  
  // *Intensity_Cue_1* updates
  if (t >= 0.0 && Intensity_Cue_1.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Intensity_Cue_1.tStart = t;  // (not accounting for frame time here)
    Intensity_Cue_1.frameNStart = frameN;  // exact frame index
    Intensity_Cue_1.setAutoDraw(true);
  }

  
  // *Intensity_Cue_2* updates
  if (t >= 0.0 && Intensity_Cue_2.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Intensity_Cue_2.tStart = t;  // (not accounting for frame time here)
    Intensity_Cue_2.frameNStart = frameN;  // exact frame index
    Intensity_Cue_2.setAutoDraw(true);
  }

  
  // *Happy* updates
  if (t >= 0.0 && Happy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Happy.tStart = t;  // (not accounting for frame time here)
    Happy.frameNStart = frameN;  // exact frame index
    Happy.setAutoDraw(true);
  }

  
  // *Unhappy* updates
  if (t >= 0.0 && Unhappy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Unhappy.tStart = t;  // (not accounting for frame time here)
    Unhappy.frameNStart = frameN;  // exact frame index
    Unhappy.setAutoDraw(true);
  }

  
  // *wideawake* updates
  if (t >= 0.0 && wideawake.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    wideawake.tStart = t;  // (not accounting for frame time here)
    wideawake.frameNStart = frameN;  // exact frame index
    wideawake.setAutoDraw(true);
  }

  
  // *sleepy* updates
  if (t >= 0.0 && sleepy.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    sleepy.tStart = t;  // (not accounting for frame time here)
    sleepy.frameNStart = frameN;  // exact frame index
    sleepy.setAutoDraw(true);
  }

  
  // *Slider2* updates
  if (t >= 0.0 && Slider2.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    Slider2.tStart = t;  // (not accounting for frame time here)
    Slider2.frameNStart = frameN;  // exact frame index
    Slider2.setAutoDraw(true);
  }

  
  // *key_resp* updates
  if (t >= 0.0 && key_resp.status === PsychoJS.Status.NOT_STARTED) {
    // keep track of start time/frame for later
    key_resp.tStart = t;  // (not accounting for frame time here)
    key_resp.frameNStart = frameN;  // exact frame index
    // keyboard checking is just starting
    psychoJS.window.callOnFlip(function() { key_resp.clock.reset(); });  // t=0 on next screen flip
    psychoJS.window.callOnFlip(function() { key_resp.start(); }); // start on screen flip
    psychoJS.window.callOnFlip(function() { key_resp.clearEvents(); });
  }

  if (key_resp.status === PsychoJS.Status.STARTED) {
    let theseKeys = key_resp.getKeys({keyList: ['space'], waitRelease: false});
    
    // check for quit:
    if (theseKeys.length > 0 && theseKeys[0].name === 'escape') {
      psychoJS.experiment.experimentEnded = true;
    }
    
    if (theseKeys.length > 0) {  // at least one key was pressed
      key_resp.keys = theseKeys[0].name;  // just the last key pressed
      key_resp.rt = theseKeys[0].rt;
      // a response ends the routine
      continueRoutine = false;
    }
  }
  
  // check for quit (typically the Esc key)
  if (psychoJS.experiment.experimentEnded || psychoJS.eventManager.getKeys({keyList:['escape']}).length > 0) {
    return psychoJS.quit('The [Escape] key was pressed. Goodbye!', false);
  }
  
  // check if the Routine should terminate
  if (!continueRoutine) {  // a component has requested a forced-end of Routine
    return Scheduler.Event.NEXT;
  }
  
  continueRoutine = false;  // reverts to True if at least one component still running
  for (const thisComponent of trialComponents)
    if ('status' in thisComponent && thisComponent.status !== PsychoJS.Status.FINISHED) {
      continueRoutine = true;
      break;
    }
  
  // refresh the screen if continuing
  if (continueRoutine) {
    return Scheduler.Event.FLIP_REPEAT;
  }
  else {
    return Scheduler.Event.NEXT;
  }
}


function trialRoutineEnd() {
  //------Ending Routine 'trial'-------
  for (const thisComponent of trialComponents) {
    if (typeof thisComponent.setAutoDraw === 'function') {
      thisComponent.setAutoDraw(false);
    }
  }
  psychoJS.experiment.addData('Slider1.response', Slider1.getRating());
  psychoJS.experiment.addData('Slider1.rt', Slider1.getRT());
  psychoJS.experiment.addData('Slider2.response', Slider2.getRating());
  psychoJS.experiment.addData('Slider2.rt', Slider2.getRT());
  psychoJS.experiment.addData('key_resp.keys', key_resp.keys);
  if (typeof key_resp.keys !== undefined) {  // we had a response
      psychoJS.experiment.addData('key_resp.rt', key_resp.rt);
      routineTimer.reset();
      }
  
  key_resp.stop();
  // the Routine "trial" was not non-slip safe, so reset the non-slip timer
  routineTimer.reset();
  
  return Scheduler.Event.NEXT;
}


function endLoopIteration({thisScheduler, isTrials=true}) {
  // ------Prepare for next entry------
  return function () {
    // ------Check if user ended loop early------
    if (currentLoop.finished) {
      // Check for and save orphaned data
      if (Object.keys(psychoJS.experiment._thisEntry).length > 0) {
        psychoJS.experiment.nextEntry();
      }
      thisScheduler.stop();
    } else if (isTrials) {
      psychoJS.experiment.nextEntry();
    }
  return Scheduler.Event.NEXT;
  };
}


function importConditions(loop) {
  const trialIndex = loop.getTrialIndex();
  return function () {
    loop.setTrialIndex(trialIndex);
    psychoJS.importAttributes(loop.getCurrentTrial());
    return Scheduler.Event.NEXT;
    };
}


function quitPsychoJS(message, isCompleted) {
  // Check for and save orphaned data
  if (Object.keys(psychoJS.experiment._thisEntry).length > 0) {
    psychoJS.experiment.nextEntry();
  }
  psychoJS.window.close();
  psychoJS.quit({message: message, isCompleted: isCompleted});

  return Scheduler.Event.QUIT;
}

The code for changing size and color needs to be in the “Each Frame” tab. This is because the marker does not exist until a rating is made. We attempt to set the size/color on each screen refresh, but if the marker does not exist it throws an error. We catch the error, and keep trying until a marker exists. When it does exist on a rating, we set the color and size once.

Thanks @dvbridges - I added it to the “Each Frame” tab, but still no luck. I also tried leaving it in the “Begin Routine” tab, in addition to the “Each Frame” tab, but it still doesn’t work. I also changed some of the slider properties to “set every frame” instead of “constant”, but it doesn’t seem to be fixing it. Screenshot below for the properties, not sure if t hey make a difference. Also attaching screenshot of the code added to the End Frame:

This could be because the code is not the same as the code I have used, the underscores are missing. Try with the underscores, and also leave the size, position and ticks as constant in your slider dialog.

Here is a working example using this code, where the new black slider marker is smaller than the previous red slider marker:

https://run.pavlovia.org/dvbridges/slidermarker/html/

1 Like

@dvbridges this works perfectly! thank you so much for all your help with this.

Might you be able to direct me to the documentation for the JS code for the slider? The height of the slider line (not the ticks, but the thickness of the line- the area where participants can click) appears thinner online than it does locally, and I would like to adjust that.

thank you for all your help with troubleshooting the slider and getting it to look right.