Jump to content
Search Community

Physics collision vs applyBounds() for draggable?

ajhalls test
Moderator Tag

Go to solution Solved by OSUblake,

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 am a little stuck on this today, I made this yesterday and my initial thought was to use some sort of physics collision sensing to keep you from being able to overlap the handles, but then I noticed the "bounds" and being able to set "maxX" and "minX", but it is listed as a read only property. I thought I could get around it with the .applyBounds where each time you release a handle, it updates the "maxX" and "minX" of the handles on either side, but I am missing something. It seems to not set the bounds, but clear any previous setting.

 

this is my first time using Greensock's draggable as opposed to jQuery, I could try going back, but I like the idea of learning more about what I can do here. So first question, did I make the right choice in trying to set and reset these bounds each time I let go, or would it have been much simpler to just say handles collide and can't jump over each other?

See the Pen egxpjv?editors=1111 by ajhalls (@ajhalls) on CodePen

Link to comment
Share on other sites

This seems to be working better using the .hitTest() function rather than bounds, if they collide, I endDrag(). One of the issues I am having though is that they work great if you are dragging slowly, but if you drag faster, they end up overlapping slightly which then makes it pretty hard to drag again as you have to keep inching it away. Any tips to adding a buffer of some kind there?

 

See the Pen EZrmgB?editors=1111 by ajhalls (@ajhalls) on CodePen

Link to comment
Share on other sites

Overlap is to be expected in a collision. The hitTest method only tells if you 2 objects are colliding, not by how much. You have to implement your own logic to handle that. For this to work, you need to find the minimum translation vector (MTV), which is the minimum amount you need to translate an object back so that there is no overlap. Basically, find the amount of overlap, and move it back.

 

I can make a demo later if you need more help. I would probably run the collision detection check in a live snap function. Check out this post which is somewhat related.

https://greensock.com/forums/topic/15972-how-to-stick-the-element-to-the-border/?p=69923

 

.

  • Like 2
Link to comment
Share on other sites

Thanks Blake, what I came up with is a modified checkHit() that just moves it back 6px. I could then also modify the function that sets the duration to subtract that 6px from the calculation to end up with a 0 duration. It still fails if you go too fast, but for average use it is fine.

 

  function checkHit(obj1, obj2, obj3) {
    if (draggableHandles[currentHandle].hitTest(obj2, "0%")) {// left side
      draggableHandles[currentHandle].endDrag();
      TweenLite.set($("#bar-"+currentHandle), {x:"+=6"});
    }
    if (obj3){ // right side
      if (draggableHandles[currentHandle].hitTest(obj3, "0%")) {
        draggableHandles[currentHandle].endDrag();
        TweenLite.set($("#bar-"+currentHandle), {x:"-=6"});
      }
    }
  }
Link to comment
Share on other sites

For what it is worth, the issue seems to be a lag in the .endDrag() getting executed. I have tried numerous ways to get it to stop when I tell it to stop, but it always continues just a little beyond.

 

For instance:

  function checkHit(obj1, obj2, obj3) {
    PanelWidths = [resizingPanels[0].css("width"), resizingPanels[1].css("width")];
    console.log(PanelWidths);
    if (parseInt(PanelWidths[0], 10) <=15) {
      draggableHandles[currentHandle].endDrag();
      
    }
    if (obj3){
      if (parseInt(PanelWidths[1], 10) <=15) {
        draggableHandles[currentHandle].endDrag();
      }
    }
      
  }

This should stop right at 15, but looking at the console I get:

["177px", "23px"]
["181px", "19px"]
["184px", "16px"]
["188px", "12px"]

I also tried to increase the dragResistance as it got closer to the end to slow it down, but then it get jumpy where as it hits the slowdown boundary it jumps back about 30px.

  function checkHit(obj1, obj2, obj3) {
    PanelWidths = [resizingPanels[0].css("width"), resizingPanels[1].css("width")];
    console.log(PanelWidths);
    if (parseInt(PanelWidths[0], 10) <=35 || parseInt(PanelWidths[1], 10) <=35) {
      draggableHandles[currentHandle].dragResistance=0.5;
      
    }else{
      draggableHandles[currentHandle].dragResistance=0;
    }
    if (parseInt(PanelWidths[0], 10) <=15) {
      draggableHandles[currentHandle].endDrag();
      
    }
    if (obj3){
      if (parseInt(PanelWidths[1], 10) <=15) {
        draggableHandles[currentHandle].endDrag();
      }
    }
      
  }

 

I can try retranslating things like I did in my last post, but I haven't figured out the combination of resizing the panels under the handles to keep the division under the handle, instead it keeps sneaking out just a little :)

 

As always, I can work around it, but it is worth mentioning that endDrag isn't as instant as I thought it would be, It doesn't seem to be a delay in the hitTest function since it fails on this other example as well.

 

My work around ended up looking like this:

  function checkHit() {
    PanelWidths = [resizingPanels[0].css("width"), resizingPanels[1].css("width")];

    if (parseInt(PanelWidths[0], 10) <=1) {
      draggableHandles[currentHandle].endDrag();
      TweenLite.set($("#panel-"+(currentHandle+1)), {width:"-=1"});
      TweenLite.set($("#panel-"+currentHandle), {width:"+=1"});
      TweenLite.set($("#bar-"+(currentHandle)), {x:"+=1"});
    }
      if (parseInt(PanelWidths[1], 10) <=1) {
        draggableHandles[currentHandle].endDrag();
        TweenLite.set($("#panel-"+(currentHandle+1)), {width:"+=1"});
        TweenLite.set($("#panel-"+currentHandle), {width:"-=1"});
        TweenLite.set($("#bar-"+currentHandle), {x:"-=1"});
      }
  }
Link to comment
Share on other sites

Hm, I wonder if there's just a fundamental misunderstanding about some mechanics here...

 

Are you under the impression that when someone drags, it literally calls the onDrag once for every single pixel it moves? Or maybe even every partial pixel? No, it's just tied to mouse/touch events that the browser dispatches (which can happen at various increments, depending on a lot of factors). For example, if you move your mouse REALLY fast from 0 to 1000 (x-coordinates) in 500ms, it doesn't call onDrag() 1000 times, once every 0.5ms. That'd be way too much pressure on the CPU. Instead, the browser dispatches several "mousemove" events (or "touchmove") over that time, but one might be when x is 121 and the next could be at 534. Again, there are lots of factors involved (CPU load, how fast the mouse moved, etc.). Draggable simply listens for those events and responds accordingly. It also maps things to requestAnimationFrame to significantly improve performance and eliminate waste. 

 

If you're writing your logic such that it depends on onDrag() firing once for every pixel moved, that'll definitely be problematic. It's not about a lag in endDrag() or anything like that either. 

 

If your goal is to "catch" your moving item when it hits a boundary, you'll need to basically sense that overlap and then back it up accordingly so that it's right on the edge (according to whatever logic you decide is best - there are many ways to do it). Blake probably has some genius example sitting around ;) 

  • Like 1
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.
×
×
  • Create New...