Jump to content
GreenSock

Joe Hakooz

Draggable hitTest() Multiple Elements

Go to solution Solved by Diaco,

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'm surprised I couldn't find more on this. Perhaps my lack of searching skillz ?

 

It appears that using Draggable and hitTest() only tests against a single test object. I tried using a jQuery selector (containing multiple elements) but only the first element is "tested"...

Draggable.create($('.dragElement), {
    onDrag: function () {
        // dragging
        if(this.hitTest($('.dropElements'), 10)){ // Problem. This should be testing against more than one element. 
            // over one of the drop zones
            console.log('hit'); 
        }
    }
});

And if this is possible, how can I know which element was "hit"?

 

Thanks!

Link to comment
Share on other sites

  • Solution

Hi Joe Hakooz  :)

 

you need a js loop ( for , while , ...) for that , pls check this out : 

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

  • Like 3
Link to comment
Share on other sites

Yep, Diaco is exactly right. I don't think it'd be intuitive to have hitTest() accommodate multiple elements because how would you distinguish which one was hit and what if there were more than one that had an overlap? What exactly would the function return? See what I mean? Seems cleaner to just focus on one, and then if you need to test multiple, you do your own loop and use whatever logic you need. 

Link to comment
Share on other sites

  • 7 months later...

I would actually argue that the hitTest() function should return a percentage rather than a boolean. The percentage would represent the overlap. 0 would mean no hit detected, anything above zero would represent the percentage of overlap.

 

This would be useful when the item was touching multiple drop spots, when you want to know which drop spot the drag item was most over.

  • Like 3
Link to comment
Share on other sites

@slopps, I see what you mean but there are two challenges with that:

  1. Most people seem to only need a boolean which is cheaper to calculate. Changing the behavior to return a percentage over overlap would mean that everyone pays that higher processing cost (seems a bit wasteful)
  2. We're very reluctant to alter method signatures because it could break people's existing code. We'll do it on occasion if we feel very strongly that it's a significant upgrade and worth the potential backlash from legacy code, but I'm not sure that in this particular case it rises to that level. If we get a lot of people requesting this, we're totally willing to reconsider. 
Link to comment
Share on other sites

You're right on both accounts. I was going to argue that it was being calculated anyway, but looking at the hitTest implementation I see that the area is only calculated if a ratio is passed.

 

Perhaps it could become a new function, getOverlapArea or some such? It goes without saying, I defer to you as this is one of the most well made libraries I've used (thank you, btw!). Not sure if percentage would be as necessary since area could also be used for comparison between the drop-zones to determine dropspot "most-over."

 

In the meantime, if anyone needs it you could get the overlap area of two elements with the following function (borrowed mostly from Draggables own hitTest implementation):

*Note: this is not as backward compatible as gsaps own hitTest code, so use at your own risk:

 

getOverlapArea = function(element1, element2)
{
  if(element1.jquery) element1 = element1[0]; //convert from jquery to dom element
  if(element2.jquery) element2 = element2[0]; //convert from jquery to dom element

  var rect1 = element1.getBoundingClientRect();
  var rect2 = element2.getBoundingClientRect();

  var xOverlap = Math.max(0, Math.min(rect1.right , rect2.right) - Math.max(rect1.left, rect2.left));
  var yOverlap = Math.max(0, Math.min(rect1.bottom, rect2.bottom) - Math.max(rect1.top, rect2.top));

  return   xOverlap * yOverlap;
};
  
  • Like 6
Link to comment
Share on other sites

That's great, @slopps, thanks for sharing your solution. 

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

If you look at the docs, one of the examples says

 

//checks if at least 50% of the surface area of either element is overlapping:
if (this.hitTest("#element3", "50%")) {
//do stuff
}

 

therefore, it checks if 50% of either element is overlapping with the other

  • Like 3
Link to comment
Share on other sites

Yep, exactly. Thanks @slopps.

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.
×