3 different drag elements for 1 drop field?

Hi there,
is it generally possible to generate a drop field for three different drag elements? That the drag elements are swapped and returned to their starting point as soon as a new drag lands in the drop field. And this only with JavaScript, without timeline animations.

Thanks a lot

With JavaScript anything is possible :slight_smile:

As drop targets aren’t a built-in feature of Hype, are you currently using any specific drop code?

This is post probably has the most canonical way and easiest setup:

The general flow is:

  1. Add the HypeDragAndDropEnabler.js file to your project, and turn off the “Include in document <head>” checkbox
  2. Add these script tags to your head html via the document inspector:
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
    <script src="https://cdn.jsdelivr.net/gh/worldoptimizer/HypeMutationObserver@1.1/HypeMutationObserver.min.js"></script>
    <script type="text/javascript" src="${resourcesFolderName}/HypeDragAndDropEnabler.js? toEnsureLoidingLatestBuilt"></script>
    
  3. Add a Class Name to the drop element (in the Identity Inspector)
  4. Add at least these two Additional HTML Attributes to the drag elements (also in the Identity Inspector):
    • data-drag as true
    • data-drop as the class name specified in step 3

In this flow, it is the drag element that specifies where it can be dropped, so it is possible for a single target to take multiple elements.

SimpleDragAndDrop.hype.zip (23.3 KB)

There’s more configurability and options that are shown in the original post about it.

2 Likes

dragAndMultipleBack.hype.zip (20.6 KB)

it’ll need timelines and custombehavior for backSwap though …

//////

in fact you could use those custombehavior-events to swap back by listeners … just search the forum for attempts on this feature …

I currently use this drop script:

DragAndDrop.hype.zip (31.5 KB)

But I’m not sure if a combination would work with this script, because I currently have two drop fields for one drag element and I would like to have one dropfield for 3 elements only accepting one at the time returning the other based on the coordinates it has been on its startposition.

you can extend both scripts, but mixing does not make sense …

DragAndDropExtended.hype.zip (23.0 KB)

This solution is on top of the draganddropenabler-script.
To make it work the script needed a small change to make the solved puzzle-pieces avaiable in hypeDocument.customData.solvedPuzzlePieses

read the comments in the script to see how it works.

Hope it’ll work :slight_smile: (for sure improveable :wink: )

 function collectDragInitPositions(hypeDocument, element, event) {
  		//Object to hold the initial positions of the draggable elements
  		hypeDocument.customData.dragElsOrigPositions = {};
  		//array holding the draggable elements
      const dragEls = [... element.querySelectorAll("[data-drag]")];
      //fill the above mentioned array with top/left positions
      dragEls.forEach(function(el){
      const leftPos = hypeDocument.getElementProperty(el, 'left');
      const topPos = hypeDocument.getElementProperty(el, 'top');
      hypeDocument.customData.dragElsOrigPositions[el.id] = {};
      hypeDocument.customData.dragElsOrigPositions[el.id].left  = leftPos;
      hypeDocument.customData.dragElsOrigPositions[el.id].top  = topPos;
      })

  }


  function extendDragDropJustOneDropAtATime(hypeDocument, element, event) {
 //is it our custombehaviour that triggerd this event?
   if(event.customBehaviorName === "checkApple"){
   //get arr from the set resolved by the extension ...
   const droppedIds = [... hypeDocument.customData.solvedPuzzlePieses];
//set the price. the draggable element holds it as a data-attribute
hypeDocument.getElementById('price').innerHTML = hypeDocument.getElementById(droppedIds[droppedIds.length-1]).dataset.price;
//is there a second apple in the shoppingbag, then put it out
  if(droppedIds.length > 1){
  //the first entry is the outdated one
const identyfier = droppedIds[0];
//get the element
const el = hypeDocument.getElementById(identyfier);
//reset its position
hypeDocument.setElementProperty(el, 'left', hypeDocument.customData.dragElsOrigPositions[identyfier].left, 0.3, 'easeinout');
hypeDocument.setElementProperty(el, 'top', hypeDocument.customData.dragElsOrigPositions[identyfier].top, 0.3, 'easeinout');
//delete id from the set
hypeDocument.customData.solvedPuzzlePieses.delete(identyfier);
  };

   
   }
    return true;
  }

  if("HYPE_eventListeners" in window === false) {
    window.HYPE_eventListeners = Array();
  }
  window.HYPE_eventListeners.push({"type":"HypeTriggerCustomBehavior", "callback":extendDragDropJustOneDropAtATime});
  window.HYPE_eventListeners.push({"type":"HypeScenePrepareForDisplay", "callback":collectDragInitPositions});
3 Likes