Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
FatMunkey

Prevent Draggables from overlapping with a recursive function

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I have taken the Codepen for "Draggable with "droppable" logic" (

See the Pen GFBvn by GreenSock (@GreenSock) on CodePen

) and forked it and rewritten a lot of it to to get the effect i am looking for.

 

basically, i do not want any draggable item to EVER overlap any any other draggable item.  I spent a good part of the morning today searching the forum and reading up in the docs trying to think of some form of simple collision detection.  The idea being to detect a collision and have a simple collision event that would make the divs bounce off of each other.  that is not built in to gsap (should be!) and I have not found anyone on the forum who has successfully done it.

 

So I must try.

 

What I have in my sample is the result of banging my newbie head on my monitor all day!  it is not 100% collision detection (like I'm used to seeing in Unity) but it does prevent overlaps in a clunky sort of way.  If you drag, say, box1, over any other box it will be tweened 100px repeatedly until it is no longer overlapping.  Additionally, there is a recursiveness in the function calls.  If, while moving box1 away from box2, box1 then overlaps box3, the recursive will continue to cycle the functions and the tween will be repeated until box1 is no longer overlapping any box.

 

This works regardless of which box you drag around and drop.  I say it is clunky because it tweens 100px, pauses, tweens another 100px, pases...and so forth until the dreaded overlapping is cured.

 

Where I am stuck is replacing the 100px with the amount of overlap (plus some small amount so the box ends up a little bit away from the last box it overlapped).  I have commented the code so you can see the varible names, etc. and understand what i am struggling with.

 

As an added bonus, it would be nice, but not strictly necessary, to remove the clunkiness I mentioned above.  

 

One final comment, it may appear that this if for a game.  It is not.  I would do this in Unity if it were a game - or maybe Buildbox.  This is actually just one step along the path I  have chosen to build a "unique" interface for a desktop app I want to build using Electron.

 

See the Pen wjVqvW by FatMunkey (@FatMunkey) on CodePen

Link to comment
Share on other sites

On 5/27/2018 at 2:12 AM, FatMunkey said:

basically, i do not want any draggable item to EVER overlap any any other draggable item.  I spent a good part of the morning today searching the forum and reading up in the docs trying to think of some form of simple collision detection.  The idea being to detect a collision and have a simple collision event that would make the divs bounce off of each other.  that is not built in to gsap (should be!) and I have not found anyone on the forum who has successfully done it.

 

 

Simple collision detection is using Draggable's hit test. What you're asking is much, MUCH more complicated than that. You would need to use something like the Separating Axis Theorem (SAT), and find the Minimum Translation Vector (MTV). The MTV is the shortest distance that the colliding object can be moved in order to no longer be colliding.

 

And collision detection should be done while you're dragging. Trying to check for collisions on drag end will only make it more complicated. What happens if you drop a box in the middle of 4 other boxes, so that each edge is overlapping a different box? There might be not be a solution as the different boxes can keep pushing your draggable back and forth between each other, resulting in an infinite loop.

 

You can read up on SAT in the links here. You will need Flash to view some of the demos in those links.

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection#Separating_Axis_Theorem

 

SAT.js might be a good library to look at. If there's a collision, the response object will give you the MTV.

https://github.com/jriecken/sat-js

 

 

See the Pen bb6983d03e1c3582f9aac486ab9069f8 by osublake (@osublake) on CodePen

 

 

  • Like 5
Link to comment
Share on other sites

OSUBlake,

 

Thanks for the reply.  I appreciate the time you spend doing this.

 

Well, I understand that collision detection from the ground up is not a trivial thing.  It is if you re using a game engine because the engine does all that heavy lifting.  I don't want to reinvent the wheel!  In fact, if Unity had a good way to display HTML5/CSS/ inside of a game environment I would be doing this in Unity.  As it stands, there is a Unity add-on that wil do it but it is not up-to-date with the engine version.  Additionally,  Unity is getting rid of JavaScript as a scripting language.  C# won.  I have looked at some HTM5 game engines but I have not found a good fit.  Maybe you can make a suggestion? 

 

Anyway, I don't really need a true collision detection.  I don't want anything bouncing off of anything like a pong game.  I just want to detect if two draggables are overlapping and then move the one that was dragged last the shortest possible distance to get to a non overlapping location.

 

Everything will be square or rectangular.  No circles of weird polygonal shapes, just plain boxes.  Let me ask you:

 

  1. Does SAT.js only work in an HTML canvas? 
  2. Will it move Dom elements with content such as iframes with video or text, etc.? 
  3. Does it play nice with gsap?  (This is not the only thing I want to use gsap for.)

 

I read the README for SAT.js and I can't see the answers to those questions there. 

 

I have updated the codepen in my original question to give you a better idea of what I am shooting for.  If you double click on "Thing 1" you will see it twen to 500px by 600px.  The intent is to use that same double click event to add DOM element that will have content such as text, images and even iframes with video.  I am a little hesitant to use iframes but...

 

If you look at this

See the Pen MGPBXe by FatMunkey (@FatMunkey) on CodePen

you will see an earlier experiment I did before i spent money on gsap.  It was good enough to convince me to buy, but I used bootstrap and it has an iframe so it causes some wonkyness when you double click on to collapse the bootstrap card.  I will give you the general idea though. 

 

 

Link to comment
Share on other sites

 

 

On 5/27/2018 at 1:18 PM, FatMunkey said:

I have looked at some HTM5 game engines but I have not found a good fit.  Maybe you can make a suggestion? 

 

There's a lot of HTML5 game engines like Phaser, Construct, PlayCanvas and Cocos, but I don't know how useful they would be for building a user interface.

 

 

On 5/27/2018 at 1:18 PM, FatMunkey said:

Everything will be square or rectangular.  No circles of weird polygonal shapes, just plain boxes.  Let me ask you:

  1. Does SAT.js only work in an HTML canvas? 
  2. Will it move Dom elements with content such as iframes with video or text, etc.? 
  3. Does it play nice with gsap?  (This is not the only thing I want to use gsap for.)

 

I read the README for SAT.js and I can't see the answers to those questions there. 

 

 

Like a lot of physics libraries, SAT.js does not do anything visually. It just calculates stuff for you. You have to wire it up to whatever you're using. 

 

Using Draggable + SAT.js like you described. It will move the draggable off of whatever item it does a collision check against, but there's a problem, just like I described in my previous post. When your draggable is moved off an item, it might be pushed onto another item. That item might have already been checked for collisions, or it might push your draggable back to the item it was just moved from. You can run through the collision detection process multiple times and hope that it will settle in a place where it doesn't overlap, but there are no guarantees without adding more logic to the process. 

 

 

See the Pen dKbWdN by osublake (@osublake) on CodePen

 

 

 

  • Like 5
Link to comment
Share on other sites

Here's a somewhat related demo. Using a little brute force to prevent any overlapping. You could do the same thing.

 

And no, you don't have to move an element to figure out if it's going to overlap. Rectangles are a very useful model. Just update your model until it isn't overlapping. 

 

var bounds = element.getBoundingClientRect();

var rect = {
  x: bounds.left,
  y: bounds.top,
  width: bounds.width,
  height: bounds.height
};

 

 

See the Pen WjWPob by osublake (@osublake) on CodePen

 

 

 

  • Like 4
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×