Slider labels are not aligned correctly Online

See PR #276

So, I’ve done a bit of bug-hunting (and in the process submitted a pull request for an unrelated issue #274) and found the bug-causing sequence:

  1. User presses Ok on DlgFromDict
  2. This fires psychoJS.window.adjustScreenSize() which requests a fullscreen transition from the browser
  3. At the same time, experimentInit() sets up the Slider, and at some point, calls _estimateBoundingBox()
  4. In _estimateBoundingBox(), this._tickPositions_px is set using tickPositions.map()
  5. tickPositions.map() uses to_px() with a this._win argument
  6. BUG OCCURS HERE: to_px() uses this._win.size to convert tickPositions from PsychoPy dimension units to browser pixel units
  7. Finally, the initial label positions, this._labelPositions_px, are set from this._tickPositions_px

The problem at Step 6 is that this._win.size represents the current window size. At this point, this._win.size may still be the pre-fullscreen window size, so the labels are placed in the correct positions for the pre-fullscreen window. However, once post-fullscreen, the labels will be in the wrong positions.

The main issue is that Step 2 is async, so it cannot be guaranteed which state the window is in.

You can easily reproduce the bug by:

  • Option 1: Make your window very small before pressing Ok on DlgFromDict. Once fullscreen, the labels will be grouped in the center of the window. This is because this._win.size is small.

  • Option 2: Wait until fullscreen is achieved, and then fire experimentInit() again. This re-initializes the Sliders, and the labels will be in the correct positions.

  • Option 3: Manually fullscreen the window before pressing Ok on DlgFromDict. The labels will be in the correct positions because the window size has not changed

Possible fix:

  • Add a timeout between closing DlgFromDict and triggering Scheduler.Event.NEXT. In DlgFromDict > close: function() ...:
    Replace (line 288 on GitHub):
    self._dialogComponent.status = PsychoJS.Status.FINISHED;
    With:
if (self._psychoJS._window.fullscr) {
    setTimeout(() => self._dialogComponent.status = PsychoJS.Status.FINISHED, 2000);
  } else {
    self._dialogComponent.status = PsychoJS.Status.FINISHED;
  }

This sets a timeout for 2000ms before continuing. In my quick testing, a minimum of around 500ms seemed to work too, but 2000ms hopefully gives some buffer space without making the experiment appear to be frozen.

(I tried a fix that listened for the fullscreenchange event, but at least in my quick testing, it still required a delay to guarantee the resize was complete)

1 Like