PennController for IBEX › Forums › Support › DragDrop features
- This topic has 11 replies, 4 voices, and was last updated 2 years, 4 months ago by
ediachek.
-
AuthorPosts
-
July 27, 2021 at 6:29 pm #7131
AlexY
ParticipantHi, I found on the documentation that we can do drag and drop now. I have been trying to use this feature by testing it out with a simple trial but unsuccessful. Here is the demo.
Basically for this trial, I am just trying to see if the image can be dragged to either one of the gaps.
Another question about the documentation page: would it be possible to have a demo link that includes the commands on that page so I can see how it actually works?
Thanks a lot in advance!
Alex
July 28, 2021 at 10:53 am #7135Jeremy
KeymasterHi Alex,
It is wiser to keep the debugger on until you’ve shared the data-collection link with your participants. For example, after I copied your project, I re-activated the debugger and noticed your project uses PennController 1.9, when the DragDrop element was introduced in 2.0.
After I uploaded the most recent version of PennController.js to the Modules folder, the experiment started to run but stayed on the preloading page with the debugger complaining:
Found an existing Image element named “fish-plural”--using name “fish-plural2” instead for new element
Indeed, at line 43 you have
newImage("fish-plural")
when it should begetImage("fish-plural")
—the experiment would try (and fail) to preload an inexistent image with the filenamefish-plural2
After I fixed that, the debugger no longer threw error messages, but I was still unable to drag the image: I looked up the Log tab of the debugger and noticed that the last command was
add
on the “drag” Canvas element, when it should have beenwait
on the DragDrop element if everything had run smoothly. And indeed, at line 36 you have.add(getImage("fish-plural"))
: coordinates are missing here, so PennController is trying to interpret the reference to the image as an X coordinate, and crashes (I should make the debugger throw an error message in such cases)After I provide coordinates to that
add
command, things work… -ish. Because the Canvas elements are created with no dimensions (e.g.newCanvas("gap-0")
) they technically occupy no space on the page, and end up overlapping one another( (although uou can still see “gap-1” because it is printed 250px to the right of the left edge of the Canvas element). Giving them a size, for example 200×200 (newCanvas("gap-0", 200,200)
) improves things: I can now drag and drop the image onto gap-0 or gap-1, and the trial will complete as expected (however it’s not easy to see with gap-1, because the text is printed 250px to the right, out of bounds of a 200×200 canvas)Note that because you print your Text elements onto Canvas elements, you don’t need any of the
center
,unfold
orprint
commands you call on them: theadd
command will print them at the provided coordinates at once when executed. So here’s an optimized code (I added background colors to the canvases to delineate them visually):newCanvas("gap-0", 200,200) .add( "center at 50%", "middle at 50%", newText("gap0")) .color("lightblue") .center() .print() .log() //remember this , newCanvas("gap-1", 200,200) .add( "center at 50%", "middle at 50%", newText("gap1")) .color("pink") .center() .print() .log() //remember this , newCanvas("drag", 200,200) .add(0,0,newImage("fish-plural", "2fishRoundTank.png").size(200, 200) ) .center() .print() .log() , newDragDrop("dd") .addDrop(getCanvas("gap-0"),getCanvas("gap-1")) .addDrag(getImage("fish-plural")) .offset(25) // will pin the elements to (25,25) from the top-left edge of the dropzone .single() .log() .wait()
Thank you for the suggestion about including a demonstration feature for code blocks on the documentation, it’s something I would like to implement one day, but unfortunately I cannot dedicate time to it at the moment
Jeremy
July 29, 2021 at 8:40 pm #7139AlexY
ParticipantThank you very much, Jeremy!
Based on the codes you suggested, I am getting closer to what I wanted to do for my experiment: Basically I am trying to create a trial where the two gaps (gap-0 and gap-1) are embedded in a sentence, e.g. “This is ____ and _____.” There will be two draggable items where participants have to decide which item to put in which gap. I have tried various ways to modify the code but I can’t seem to solve the following issues:
1. I cannot make the instruction display on top of the page.
2. I cannot make the two canvases display horizontally. I have the same problem with the two draggable items.
3. Is there a way to present the two canvases in a way that they are embedded in the sentence above: “This is _(gap-0)_ and _(gap-1)_.”?Thank you very much again for your help!
Alex
July 29, 2021 at 9:22 pm #7140AlexY
ParticipantSorry, please ignore #1, it was simply an ordering issue.
July 30, 2021 at 11:25 am #7143Jeremy
KeymasterHi Alex,
Here is a template/demo project featuring the DragDrop element that you might be interested in taking a look at: https://farm.pcibex.net/r/MOytaR/
2. the main purpose of Canvas elements is precisely to control visual layout, in particular when you need to print two elements side by side. Here’s an example, printing two Canvas elements side by side:
newCanvas("container", 400, 200) .add( 0,0, newCanvas("pink patch", 200,200).color("pink")) .add( 0,0, newCanvas("blue patch", 200,200).color("blue")) .print()
3. look at the code of the first trial in the demo project I shared above to see an example
Jeremy
September 15, 2022 at 8:34 am #8413mwf2120
ParticipantHi! I am relatively new to Pcibex and am trying to do the following: log coordinate location of images (between 2 and 5 depending on set randomization) that are dragged and dropped to another canvas. The figures (images) can be placed anywhere and in any order on the new canvas. I’d really like to record x and y coordinates where participants place each figure. I’ve been able to implement the drag and drop approach, and to collect coordinate data for clicks, but coordinate data collection fails when I try to drag and drop (probably because the images are “clicked” in one place and “unclicked” in another). Is there a better way to do this? Thanks so much!
Drag and drop sample approach:
newTrial(“Set_2”, newCanvas(“figlist”, “72vw”,”58vh”) .css(“padding”,”1em”) .color(“lightgray”) .print(“left at 5vw”, “middle at 50vh”) , newCanvas(“grid”, “72vw”, “58vh”) .css(“padding”, “1em”) .color(“yellow”) .print(“left at 20vw”, “middle at 50vh”) , newSelector(“figures”) , newImage(“man”, “man_small.png”).selector(“figures”).print(getCanvas(“figlist”)), newImage(“boy”, “boy_small.png”).selector(“figures”).print(getCanvas(“figlist”)) , getSelector(“figures”).shuffle() .log() , newDragDrop(“dd”) .addDrag(getImage(“man”)) .addDrag(getImage(“boy”)) .addDrop(getCanvas(“figlist”)) .log() , newTimer(5000).start() .wait() )
Thanks for any help!
October 17, 2022 at 3:02 pm #9584ediachek
ParticipantHi Jeremy,
I was wondering if it’s possible to “link” two pictures together using the Drag and drop feature. In my task, participants will hear “Put the bear on the flower”, for which I expect them to place one object on top of the other. Then, they will hear “Now put them in the box”, and I would hope that the two images of the bear and flower would get “linked” so that participants could just drop them in the box at the same time using one mouse movement. Looking forward to hearing your thoughts!!
-Yev
October 19, 2022 at 7:56 pm #9599Jeremy
KeymasterHi,
I just realized I never addressed the previous post, so I will do it now. Unfortunately there is no built-in way to log coordinates in a DragDrop element, but it can be achieved using some javascript. The
set
command of Var elements accepts javascript functions, so we can create one Var element for each pair of coordinates we want to log:newTimer(5000).start() .wait() , newVar("manXY").set(v=>{ const bcr = getImage("man")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log(), newVar("boyXY").set(v=>{ const bcr = getImage("boy")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log(), newVar("figlistXY").set(v=>{ const bcr = getCanvas("figlist")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log() )
Now, regarding the linking of two pictures, it should be possible in theory, but I found out there are a few bugs with such chaining in the DragDrop element. We will need a few tricks to work around those bugs, namely we will remove the image of the bear once it’s placed on the flower, and replace it with a copy of it; we will need to retrieve the coordinates of the original image to do that though, which will involve some javascript
We will also need to have the bear and the flower placed on a Canvas element and make them “transparent” so that the Canvas element can be dragged onto the box:ERRATUM: see this post on how to use a single DragDrop element instead
newText("instructions", "Put the bear on the flower").print() , newImage("bear","bear.png").size(100,100).print(), newImage("bearCopy","bear.png").size(100,100).cssContainer("pointer-events","none").css("pointer-events","none") , newCanvas("flowerCV", 200,200).add(0,0,newImage("flower","flower.png").size(200,200)).print() , newCanvas("boxCV", 300,300).add(0,0,newImage("box","box.png").size(300,300)).print() , newDragDrop("bearToFlower") .addDrag(getImage("bear")) .addDrop(getCanvas("flowerCV")) .wait() , newFunction(()=>new Promise(async r=>{ const bearBCR = getImage("bear")._element.jQueryElement[0].getBoundingClientRect(); const flowerBCR = getCanvas("flowerCV")._element.jQueryElement[0].getBoundingClientRect(); await getCanvas("flowerCV").add(bearBCR.x-flowerBCR.x,bearBCR.y-flowerBCR.y,getImage("bearCopy"))._runPromises(); r(); })).call() , getImage("bear").hidden().remove(), getImage("flower").cssContainer("pointer-events","none") , getText("instructions").text("Now put them in the box") , newDragDrop("flowerToBox") .addDrag(getCanvas("flowerCV")) .addDrop(getCanvas("boxCV")) .wait()
Let me know if you have questions
Jeremy
-
This reply was modified 2 years, 4 months ago by
Jeremy. Reason: reference to correction below
October 20, 2022 at 3:36 pm #9600ediachek
ParticipantThank you, Jeremy! This code works great!
One more question. If I wanted a 3×3 grid with images so that the bear and flower would be at random positions from one trial to another, I think I would need to use the selector command with the shuffle argument. Where would I plug it in this code?
Thanks!
YevOctober 20, 2022 at 3:48 pm #9601Jeremy
KeymasterSimply print the “bear” Image element and the Canvas elements containing the other images on a bigger Canvas element, and then shuffle those:
newCanvas("mainContainer", 900,300).print() , newImage("bear","bear.png").size(100,100).print(0,0,getCanvas("mainContainer")), newImage("bearCopy","bear.png").size(100,100).cssContainer("pointer-events","none").css("pointer-events","none") , newCanvas("flowerCV", 200,200).add(0,0,newImage("flower","flower.png").size(200,200)).print(300,0,getCanvas("mainContainer")) , newCanvas("boxCV", 300,300).add(0,0,newImage("box","box.png").size(300,300)).print(600,0,getCanvas("mainContainer")) , newSelector("shuffle").add(getImage("bear"),getCanvas("flowerCV"),getCanvas("boxCV")).shuffle().disable()
Jeremy
October 20, 2022 at 3:59 pm #9602Jeremy
KeymasterNote that I found another bug with the suggestion above: creating a second DragDrop element messes with detecting dropping events on it, hence never validating its
wait
command. So instead of creating two DragDrop elements, one should create and reuse a single one:newDragDrop("dragdrop") .addDrag(getImage("bear")) .addDrop(getCanvas("flowerCV")) .wait() .removeDrag(getImage("bear")) .removeDrop(getCanvas("flowerCV")) , // ... getDragDrop("dragdrop") .addDrag(getCanvas("flowerCV")) .addDrop(getCanvas("boxCV")) .wait()
Jeremy
October 20, 2022 at 4:03 pm #9604ediachek
ParticipantThis is working perfectly! Thank you so much!
-
This reply was modified 2 years, 4 months ago by
-
AuthorPosts
- You must be logged in to reply to this topic.