Drag and Drop for simple Quiz

dragdrop

(Matt) #1

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


Drag and Drop question
#2

Try this

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

D


(Matt) #3

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!


At the end of an On Drag Action can a Timeline be triggered?
(Warren Adams-Ockrassa) #4

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)


Run timeline if an element is to specific position (Drag / Drop)
#5

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


(Warren Adams-Ockrassa) #6

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…


(Warren Adams-Ockrassa) #7

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.


(Matt) #8

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


(Mark Hunte) #9

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)


Offset of hypeGestureXPosition and hypeGestureYPosition
(Warren Adams-Ockrassa) #10

Yes. Yes, it would.

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


(Matt) #11

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


(thejoepeach) #12

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…


#13

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)


(Mark Hunte) #14

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)


#15

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.


#16

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


(Mark Hunte) #17

Sorry my bad.

Change :

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

to,

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


#18

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


(Stephen G) #19

Extremely helpful and versatile code thanks @MarkHunte !


(Stephen G) #20

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