Drag and Drop for simple Quiz

Hi-
I’ve searched and looked at I think all of the Drag and Drop threads. I’m having trouble just making a very simple DnD example for a one question/multiple option quiz. User just needs to match up a few elements to the correct drop zones and there needs to be a correct or incorrect indication.
I’d welcome any help!
Thank you!
Matt

Try this

The important part is using Maths.abs(); to specify how far the element is from the correct drop zone.

D

1 Like

Thanks for this. I think all of these examples won’t help me as they seem to rely somewhat on innerHTML when indicating the correct answer. Is that right? What I’d like to do is have the dragged element be an image. When the image gets to the correct drop zone I’d like there to be a correct or incorrect indication.
Thank you!

This is not a wholly trivial thing you're looking to do, as making an element draggable all by itself is a bit tricky without some JS. However, building from this:

…the rest is really just a question of determining intersect. Here's a rough version.

D-n-d_test.hype.zip (17.6 KB)

The example is using the element bounding box to determine if it’s in the correct place or not so I guess you can change the element to an image or any other type of element

D

Exactly, yeah. I did it with a couple of element primitives as an illustration; it’ll work with any kind of element on top of any other kind of element - so text over a graphic, for instance, or a button over a shape, an image over another image…

There is, however, one problem with the code as presented, illustrated most effectively with this minor revision:

D-n-d_test.hype.zip (17.7 KB)

As you can see, if you drag the orange circle to the bottom-right corner, it still is detected as being within the grey square, even though it isn’t. That’s because I don’t test for the rect, just for a simple x,y coordinate boundary, with this line here:

if (gX > targetX && gY > targetY)

The way to correct for that is to poll for the entire rectangle (well, bounding rect) of the shape, not just a quick and dirty test to see if the circle is both beyond the shape’s left edge, and below the shape’s top edge, with this minor revision:

if ((gX > leftX && gY > topY) && (gX < rightX && gY < bottomY))

The result gives considerably more accurate hit testing for the boundary of the shape:

D-n-d_test_2.hype.zip (17.8 KB)

This will work on a per-shape basis, provided you correctly identify the target shape you want the item being dragged to intersect.

1 Like

This is fabulous! Thank you so much @warrenao!

Would it be possible to edit the javascript to have multiple drag elements and multiple drop zones?

…and then to enact a time line when all of the elements are in the correct place?
Thank you!
Matt

Here is my take on it.

The squares and circles are of even numbers.
Both sets are either a square class or a circle class.

Each circle corresponds with its own square simply using it’s z-index.
You do not have to code for the z-index just use the natural order that they have in the element panel.
when added to an array they will be that order. i.e front most circle element will be item 0 in the array and the same for a square.

(You can use any other way to tie them together.)

This example does what you want I think. I have a very small margin for distance. adjust as needed.

Having uneven classes will break this. Still trying to figure a way of doing that. i.e 3 squares and 2 circles but in most cases you will always want even numbers.

hitTestGroup2.hype.zip (23.1 KB)

2 Likes

Yes. Yes, it would.

The variant by @MarkHunte is also a nice take on it, and worth tinkering with.

1 Like

These are all great! Thanks @warrenao and @MarkHunte!! :grinning:

1 Like

Maybe this is what you are loking for this:
http://freefallmotion.com/clientes/educativo/sampler_drag_drop.zip
However i cant make it work on mobile for some reason… hope can help you…

1 Like

Hi,
So I tried using this. Now I’m going crazy. The hitTest works perfectly, even if I add objects. Then I decided to make my own quiz. See example. As far as I know everything is the same, but I get this: Error in hit: TypeError: undefined is not an object (evaluating ‘fig.getBoundingClientRect’)
67
This means it won’t change to the next scene!?
Can someone please shine his light on this? As always the solution will be easy I guess.:smirk:
tia

dragdrop1.zip (39.2 KB)

The problem you have here is that on the other scenes you have Rects with the same class name 'square'

This is fine until you want to gather all elements with the class name 'square'

The other scenes rects will be picked up and instead of iterating over 4 items you will be iterating over 12.

I wrote a work around for situations like this which has been included in an extension that gathers scene info.

The extension is placed in your head file.

You can then query the current scene element only instead of all of the scenes by using the extension like so.

var sceneInfo = hypeDocument.sceneInfo()
var currentSceneElement  = sceneInfo.sceneElement;
 
var theSquareClass =  currentSceneElement.querySelectorAll('.square');
var thefigClass = document.getElementsByClassName('fig');

dragdrop1_MHv1.hype.zip (47.4 KB)

3 Likes

As always: Mark the Savior! Thank you. I indeed forgot that the other scenes contained rectangles with the same classname. Although I had noticed that there must be an equal number in my one scene test.

1 Like

Somewhere something went wrong. Symbols in next scenes won’t color the squares. Did I break something?
dragdrop1_MHv2.zip (62.7 KB)

Sorry my bad.

Change :

var thefigClass = document.getElementsByClassName('fig');

to,

var thefigClass = currentSceneElement.querySelectorAll('.fig');

1 Like

Even a savior sometimes makes a mistake :stuck_out_tongue_winking_eye:
Works perfectly now!

1 Like

Extremely helpful and versatile code thanks @MarkHunte !

Hi all,

Can anyone enlighten me on how to get the bounding box of a circle ? This example uses rectangles and the getBoundingClientRect(); method. How would you get the centre position on a round drag object?

Here is the original code from this thread for the hit() function. I have added a few comments for myself to understand it a little better but apart form that its unchanged.

Any help greatly appreciated, Stephen.

var sceneInfo = hypeDocument.sceneInfo()
var currentSceneElement  = sceneInfo.sceneElement;

/* Returns all elements in the document that match the 'square' and 'fig' CSS selector as a static NodeList object. The NodeList object represents a collection of nodes.
 The nodes can be accessed by index numbers. The index starts at 0.
 Use the length property of the NodeList object to determine the number of elements that matches the specified selector, 
 then loop through all elements and extract the info you want.*/
 
var theSquareClass =  currentSceneElement.querySelectorAll('.square');
var thefigClass = currentSceneElement.querySelectorAll('.fig');
 
/* Two node list objects have been created for later use */ 
	 
	
/* PART 1 - Loop through all elements with a class named square  */
for (var i = 0; i < theSquareClass.length; i++) {

/* PART 2 - For each element with a class of square find all elements on the stage with a class of fig AND give a value in the array starting with 0 THEN
store that element with the class of fig in an arrary variable called fig */
var fig = thefigClass[i];
 
 
 /* PART 3 - Return the size of the first element in the array and store its position relative to the viewport in the figRect variable*/
var figRect = fig.getBoundingClientRect();


	 /* PART 4 - Calculate the x and y center points of the first FIG element and store the values as figXCenter and figYCenter */
	var figXCenter = figRect.left + (figRect.width / 2);
	var figYCenter = figRect.top + (figRect.height / 2);
	 	
/* PART 5 - Return the size of the first element in the array and store its position relative to the viewport in the squareRect variable*/
var squareRect = theSquareClass[i].getBoundingClientRect();
	 	
	/* PART 6 - Calculate the x and y center points of the first SQUARE element and store the values as squareXCenter and squareYCenter */ 
	var squareXCenter = squareRect.left + (squareRect.width / 2);
	var squareYCenter = squareRect.top + (squareRect.height / 2);
	 

	/* PART 7 - Calculate the centre position of the fig element in relation to the centre of the square element and store in the variable currentDistance */
	var currentDistance = (figXCenter - squareXCenter) * (figXCenter - squareXCenter) + (figYCenter - squareYCenter) * (figYCenter - squareYCenter);
	
	/* PART 8 - Round and clean up the currentDistance value */
	var thisDist = Math.round(currentDistance );
	
	/* PART 9 - If the centre point of the fig element is within 400 px of the center point of the square element then... */
	if ( thisDist < 400 ) {
	
	
		 // Loop through the node object for 'this' CSS selector with a class of 'square' and alter the background color property
		
		 theSquareClass[i].style.backgroundColor = "green";
		 theSquareClass[i].style.color = "green";
		 
	
				}  else {
		
		
		 theSquareClass[i].style.backgroundColor = "white";
		 theSquareClass[i].style.color = "steelblue";
		 
		}
	  
	}
	
	/* PART 10 - Loop through the square class node object list and for each selector that NOW has a color of green add one to the new variable count. 	    Then exit loop if i reaches the number of elements with the square class (else) do something...*/
	var counter = 0;
	
	for (var i = 0; i < theSquareClass.length; i++) {
	
	var squareColour = theSquareClass[i].style.backgroundColor;
	 if ( squareColour === "green" ) {
	 counter++
	 }
	
			}
	/* PART 11 - If all square selectors have a background color of green then run correct modal*/		
	if ( counter == theSquareClass.length ) {
	// DO SOMETHING HERE 
	
	hypeDocument.functions().dragDropCorrect(hypeDocument, element, event);

	
	 } 
	 
	 		 else {
	 
	 // PAUSE CORRECT TIMELINE FOR ANOTHER TRY 'OR' PLAY WRONG TIMELINE NOW
	
	 }
	 
	 
/* code sinppets */	
//hypeDocument.getElementById('displayCurrentDistance').innerHTML = thisDist; 


//END OF CODE