Jeremy

Forum Replies Created

Viewing 15 posts - 376 through 390 (of 1,522 total)
  • Author
    Posts
  • in reply to: Conditional Assent/Consent Page #8318
    Jeremy
    Keymaster

    Hi,

    The two newTrial commands in your code are embedded inside a PennController command — PennController() is the older name of newTrial(), so you’re effectively passing PennController trials as arguments to another PennController trial, which won’t work

    Here is what you can do instead:

    newTrial("age" ,
        newVar("over18", false).global()
        ,
        newText("age", "<p>Are you 18 years of age or older?</p>").print()
        ,
        newButton("yes", "Yes, I am 18 years old or older.").print()
        ,
        newButton("no", "No, I am under 18 years old.").print()
        ,
        newSelector("yesno")
            .add( getButton("yes") , getButton("no") )
            .wait()
            .test.selected( getButton("yes") )
            .success( getVar("over18").set(true) )
    )
    
    newTrial( "*sent" ,
        getVar("over18").test.is(true).success(
            newHtml("consent", "Consent-Online.html").css("margin-bottom", "2em").print()
            ,
            newButton("By clicking this button I indicate my consent")
                .print()
                .wait()
        ).failure(
            newHtml("assent", "Assent-Online.html").css("margin-bottom", "2em").print()
            ,
            newButton("By clicking this button I indicate my assent")
                .print()
                .wait()
        )
    )

    Jeremy

    in reply to: Getting variable from csv, based on DropDown selections #8315
    Jeremy
    Keymaster

    Hi,

    You could print the image onto a Canvas element, and manipulate that one Canvas element instead—I don’t think there’s anything you can do on an Image element you cannot do on a Canvas element:

    Template("fullList.csv",
        variable => newTrial("demo",
            newText("head", " ")
                .text(getVar("asdf"))
                .before(newText("b","").text(getVar("namelist")).after(newText(": ")))
                .center()
                .print()
            ,
            newCanvas("image").center().print()
            ,
            getVar("namelist")
                .test.is("P1A").success( newImage(variable.P1A).print(getCanvas("image")) )
                .test.is("P1B").success( newImage(variable.P1B).print(getCanvas("image")) )
                .test.is("P1C").success( newImage(variable.P1C).print(getCanvas("image")) )
                .test.is("P2A").success( newImage(variable.P2A).print(getCanvas("image")) )
                .test.is("P2B").success( newImage(variable.P2B).print(getCanvas("image")) )
                .test.is("P2C").success( newImage(variable.P2C).print(getCanvas("image")) )
                .test.is("P3A").success( newImage(variable.P3A).print(getCanvas("image")) )
                .test.is("P3B").success( newImage(variable.P3B).print(getCanvas("image")) )
                .test.is("P3C").success( newImage(variable.P3C).print(getCanvas("image")) )
            ,
            newButton("Flicker")
                .center()
                .print()
                .wait()
                .remove()
            ,
            getCanvas("image").remove()
            ,
            newTimer(2000).start().wait()
            ,
            getCanvas("image").print()
            ,
            newButton("Finish").center().print().wait()
        )
    )

    Jeremy

    in reply to: Getting variable from csv, based on DropDown selections #8312
    Jeremy
    Keymaster

    Hi,

    Javascript is immediate, PennController is delayed. More specifically, you cannot dynamically pass values to newImage (also, how would PennController be able to preload the image file if it had to wait until the trial starts to know which file to use?)

    What happens in your case is, as soon as the experiment page is open, all the javascript code is executed immediately (top down). First it creates the varForImg variable, it creates the setvarForImg and getvarForImg functions, it sets the Sequence, it creates the trial labeled "whoareyou", and runs the Template function to create as many newTrials as there are lines in fullList.csv. Because you call setvarForImg 9 times in that newTrial function, it is called 9 times with each newTrial creation, and when the script gets to newImage("comicstrip", varForImg) when creating a trial, the value of varForImg is always set to the value of variable.P3C, because that’s the value passed to the most recently executed setvarForImg function

    Then, when you progress through the experiment, as you get to a trial labeled "demo", that trial already contains an Image element named "comicstrip" that points to a file whose name is the value in the P3C cell for the row from which the trial was created. The first PennController commands to be run as you start a new trial are the tests on the Var element, whose success commands have no actual effect (because setvarForImg returns undefined, which success will simply ignore: undefined is not a PennController command). When the trial’s execution reaches the Image element, it will simply display the the file referenced in the P3C cell, regardless of the earlier tests

    What you can do instead is delete all references to varForImg (including the javascript functions) and include all 9 possible newImage commands in the trial (then PennController will effectively create, and preload, all 9 Image elements per trial) but only execute one of those in the tests on the Var element:

    Template("fullList.csv",
        variable => newTrial("demo",
            newText("head", " ")
                .text(getVar("asdf"))
                .before(newText("b","").text(getVar("namelist")).after(newText(": ")))
                .center()
                .print()
            ,
            defaultImage.center().print()
            ,
            getVar("namelist")
                .test.is("P1A").success( newImage(variable.P1A) )
                .test.is("P1B").success( newImage(variable.P1B) )
                .test.is("P1C").success( newImage(variable.P1C) )
                .test.is("P2A").success( newImage(variable.P2A) )
                .test.is("P2B").success( newImage(variable.P2B) )
                .test.is("P2C").success( newImage(variable.P2C) )
                .test.is("P3A").success( newImage(variable.P3A) )
                .test.is("P3B").success( newImage(variable.P3B) )
                .test.is("P3C").success( newImage(variable.P3C) )
            ,
            newButton("moveOn", "Continue")
                .center()
                .print()
                .wait()
        )
    )

    Jeremy

    in reply to: MouseTracker element: Dynamic starting procedure #8311
    Jeremy
    Keymaster

    Hi Judith,

    The critical Audio element is played twice because you tell it twice to play: once when you create it, just after the previous Audio element has stopped playing, and once inside the callback function, when the mouse moves upward. Simply delete the .play() that you don’t want

    Jeremy

    in reply to: problem by Sequence and some others #8310
    Jeremy
    Keymaster

    Hi,

    1. The syntax you are using in Template automatically assigns a label to the items that are generated. Indeed, when I look up your code, every item generated by your Template commands consists of two PennController trials, and the two newTrial commands you use in there have different strings as their first arguments ("example" and "grad", or "experiment" and "grad")

    If you want to give labels to items consisting of pairs of elements, so that participants will always see the two newTrials of a pair in a row, and so that those two newTrials will remain associated with each other through randomize, you can pass the label before "PennController": ["experiment", "PennController",newTrial(, ["example", "PennController",newTrial( (also remember to change "example.csv" in the current Sequence command in project back to "example" like you have in your message above)

    2. Yes, I think it’s fine, but always take test-runs of your experiment and check the results file to see if you do get all the information you want. In this case, if you press F or J early, I expect that you should have a line in your results file for that Key element ("stop early") but no line for the other Key element ("keypress") or a line that reports NA. But you should really just take a test-run and check your results file

    Jeremy

    in reply to: Typo in results for DragDrop #8305
    Jeremy
    Keymaster

    Thanks, I’ll fix it for the next release!

    Jeremy

    in reply to: Resources Not Loading – Random Points in Experiment #8302
    Jeremy
    Keymaster

    Hi Kelly,

    My guess is that it’s just too many resources. You’re requesting close to 700 files: it’s just very likely that at least one of those requests will fail for any number of reasons, and still quite likely that more than one will fail. Distributing the requests over two different servers (github and the farm) probably helped, but to be honest, I’m surprised you were still able to run 2 pilots with no issues

    As I mentioned in my previous post, one minor thing you could do is replace the https://github.com URLs with https://raw.githubusercontent.com URLs so the browser doesn’t have to send as many requests, i.e you can replace https://github.com/USERNAME/REPO/raw/main/FOLDER/SUBFOLDER/file.mp3 with https://raw.githubusercontent.com/USERNAME/REPO/main/FOLDER/SUBFOLDER/file.mp3. It won’t solve everything, since as you said you’ve also experienced issues preloading files from the farm, but it’s still a step in the right direction

    Amazon offers 5GB of S3 storage with AWS Free Tier (valid 12 months). You could upload a zip file there (see this post for tips on how to set things up so your experiment can download the zip file from S3)

    Jeremy

    in reply to: Eye Tracking: Time limit and webcam resolution #8301
    Jeremy
    Keymaster

    Hi Henrik,

    You could use add a Footer to every trial that checks how long it’s been since the experiment started and jumps to a trial that sends the results if it’s been too long:

    const start_time = Date.now()
    
    Footer(
        newFunction( ()=>Date.now()-start_time>(20 * 60 * 1000) ) // 20min
            .test.is( true )
            .success( jump("timeout") )
    )
    
    Sequence("intro", randomize("trials"), SendResults(), "end", "timeout")
    
    newTrial("intro", newButton("Start the experiment").print().wait() )
    
    newTrial("end", newText("This is the end").print(),newButton().wait() )
    
    newTrial("timeout", 
        newText("You have timed out, we are sending your results to the server").print()
        ,
        SendResults()
        ,
        newText("Your results have been sent, thank you for your participation").print()
        ,
        newButton().wait()
    )

    Jeremy

    in reply to: Conditional feedback based on DragDrop response #8299
    Jeremy
    Keymaster

    Hi,

    EDIT: actually you do need callback if you want to only move on when dropping in the right box:

    newText("yes"),newText("no", "drop in the other box")
    ,
    		
    newDragDrop("dd", "bungee")
    	.log("all")
    	.addDrop(
    		getText(first_arg), 
    		getText(second_arg)
    	)
    	.addDrag(getText("word"))
    	.callback( 
    	    getText("yes").remove(),getText("no").remove()
    	    ,
    	    self.test.dropped( getText(target_res) )
            	.success( getText("yes").print() )
            	.failure( getText("no").print() )
    	)
    	.offset('0.5em', '0.1em', 
    		getText(first_arg), 
    		getText(second_arg)
    	)
    	.wait( self.test.dropped(getText(target_res)) )
    	.removeDrag(getText("word"))
    	.removeDrop(
    		getText(first_arg), 
    		getText(second_arg)
    	)
    ,
    
    getMouseTracker("mouse").stop()
    ,

    End of EDIT

    You don’t need to use callback, just test whether the Text element whose name corresponds to the value of target_res is the one that received the draggable element after wait:

    newDragDrop("dd", "bungee")
    	.log("all")
    	.addDrop(
    		getText(first_arg), 
    		getText(second_arg)
    	)
    	.addDrag(getText("word"))
    	.offset('0.5em', '0.1em', 
    		getText(first_arg), 
    		getText(second_arg)
    	)
    	.wait()
    	.test.dropped( getText(target_res) )
    	.success( newText("yes").print() )
    	.failure( newText("no").print() )
    	.removeDrag( getText("word") )
    	.removeDrop(
    		getText(first_arg), 
    		getText(second_arg)
    	)
    ,
    
    getMouseTracker("mouse").stop()
    ,

    Jeremy

    • This reply was modified 3 years, 1 month ago by Jeremy.
    in reply to: MouseTracker only while dragging for use with DragDrop #8294
    Jeremy
    Keymaster

    Hi,

    My initial suggestion was to use a Selector element to detect a click on the word, and start the MouseTracker element then, but it turns out that selector.callback also fires only after the click has been released, which defeats the purpose

    At this point, you’re better off injecting a javascript function using the Function element:

    newMouseTracker("mouse").log()
    ,
    
    newFunction( async ()=> {
        await new Promise(r=>getText("word")._element.jQueryContainer.mousedown(r));
        getMouseTracker("mouse").start()._runPromises();
    })
        .call()
    ,

    Jeremy

    in reply to: Logging value of randomly chosen text #8290
    Jeremy
    Keymaster

    Hi,

    newX commands (and their arguments) are evaluated immediately so even if you were able to directly refer to the value of the Var element (which you can: getVar("word_num").value) you wouldn’t necessarily get what you want, because the execution of a PennController trial (and of the commands on its elements) happens, well, whenever the trial is executed

    You could do this instead:

    newVar("random_word", variable["word_" + Math.floor(Math.random() * 12)] ).log(),
    newText("word", "").text( getVar("random_word") ).print()

    or

    newTrial("trial_prac",
    // ...
      word_num = Math.floor(Math.random() * 12),
      newText("word", variable["word_" + word_num]).print()
    //...
    )
    .log("word_num", word_num)
    

    EDIT: sorry, I just saw your second message. That’s a great solution (it’s actually cleaner than creating a variable within newTrial like I suggest)

    Jeremy

    • This reply was modified 3 years, 1 month ago by Jeremy.
    Jeremy
    Keymaster

    Hi,

    Create a container element (eg. a Text element) and set its display style attribute to flex. Then print your elements inside that container element. Also make sure to set the position style attribute of your boxes to relative in order for “word” to be positioned relative to the boxes themselves and not their container (the container Text element):

    Template("practice.csv", variable => 
      newTrial("trial_prac",
        newText("container", "").css('display', 'flex').print()
        ,
        newText("Should the word go here ").print(getText("container"))
        ,
        newText("firstbox", " ")
          .css({border:'1px solid #000', width: '4em', position: 'relative'})
          .print(getText("container"))
        ,
        newText(" or here&nbsp;").print(getText("container"))
        ,
        newText("secondbox", " ")
          .css({border:'1px solid #000', width: '4em', position: 'relative'})
          .print(getText("container"))
        ,
        newText("?").print(getText("container"))
        ,
        newText("word", "word").center().print()
        ,
        newDragDrop("dd", "bungee")
          .log()
          .addDrop( 
            getText("firstbox"),  
            getText("secondbox"), 
          )
          .addDrag(getText("word"))
          .offset('0.5em', '0em', getText("firstbox"), getText("secondbox"))
          .wait()
        ,
        newButton("Ready")
          .css("margin-top", "2em")
          .center()
          .print()
          .wait()
          .remove()
      )
    )

    Jeremy

    in reply to: MediaRecorder in Safari #8285
    Jeremy
    Keymaster

    Hi,

    The PennController MediaRecorder element (which relies on, but is distinct from, the MediaRecorder API) only checks webm and ogg for audio, but Safari 14+ only references mp4 as supported, which is why you get that error

    I will need to add audio/mp4 to the next release, and raise an explicit error message when no supported type is found. In the meantime, feel free to upload a copy of PennElement_mediarecorder.js to your project’s Modules folder, replacing line audio: {'audio/webm': 'webm', 'audio/ogg': 'ogg'}, with audio: {'audio/webm': 'webm', 'audio/ogg': 'ogg', 'audio/mp4': 'mp4'},. You’ll get an error about MediaRecorder being defined multiple times, but I think the experiment should still run ok

    Jeremy

    Jeremy
    Keymaster

    Hi,

    If you haven’t done so yet, I invite you to read the tutorial, more specifically section 5.1.2 which explains how to display elements side by side

    A Selector element has no visible content: it just makes some elements that are independently printed onto the page, selectable (by a click, by a keypress, or either). You remove an element by calling remove on that element

    Applying these points to your code (and updating it to modern PennController syntax and commands):

    Template("practice.csv", variable => 
      newTrial("trial_prac",
        newText("sentence", "<p>testing</p>")
          .center()
          .print()
        ,
        newSelector("position")
        ,
        newCanvas("buttons", 200, 50)
          .add(              0, 0, newButton("XXXX").selector("position") )
          .add("right at 100%", 0, newButton("YYYY").selector("position") )
          .center()
          .print()
        ,
        getSelector("position")
          .shuffle()
          .once()
          .wait()
          .log()
        ,
        getCanvas("buttons").remove()
        ,
        newButton("Next")
        .center()
        .print()
        .wait()
      )
    )

    Jeremy

    in reply to: How to measure the total time of experiment #8273
    Jeremy
    Keymaster

    Hi,

    Since your experiment starts with a PennController trial and ends with one too, and since PennController trials automatically add a line to the results file for the start of the trial and a line for the end of the trial too, simply subtract the EventTime of the first “_Start_” event of the run from the EventTime of the last “_End_” event of the run. No need to use any Var element

    Jeremy

Viewing 15 posts - 376 through 390 (of 1,522 total)