Jump to content
Search Community

Draggable with css scaling

autoric test
Moderator Tag

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

Example : 

See the Pen dnuCJ?editors=001 by anon (@anon) on CodePen

 

Premise : 

We have a draggable grid that may be larger than the user's current viewport. When they start to drag, we are scaling the draggable area to fit in their viewport, and scaling back out when they are done. 

 

The Problem : 

Greensock draggable watches deltas in the pointer X / Y position to determine dragging. This means that...

1) On the initial scale the pointer becomes detached from the draggable element.

2) Pointer x/y deltas do not account for the scaled content, so it ends up feeling like there is a drag resistance when there is not. The more the content is scaled, the more exaggerated this becomes.

 

Desired Outcome : 

1) As the content scales, the x,y position of the draggable element is changed so that it remains underneath the pointer.

2) Pointer deltas are divided by scale so that there is no feeling of drag resistance.

 

I've been exploring this but cannot come up with a good comprehensive solution, especially for the first problem. For the second point, I am actually able to set a negative dragResistance 

dragResistance = 1 - 1/scale

but it feels awkward when the pointer is detached from the draggable element. Any sugestions are welcome!

 

Thanks,

Erin

Link to comment
Share on other sites

Hi Erin and welcome to the GreenSock forums.

 

For the element's offset you could take advantage of the rich event handler options Draggable has to offer. One possibility is record the current offset() of the element using onPress and during the body scale animation update you can use a set instance to keep the element in that particular offset position:

var initPosition,
    draggTarget;

function dragStart() {
    scale = 0.9* $('html')[0].clientHeight / body.offsetHeight
    if(scaleTl) {
      scaleTl.kill()
    }
    console.log('scaling to', scale)
    scaleTl = TweenLite.to(body, duration, {scale: scale, transformOrigin: "center top", scrollTop : 0,
        onUpdate:function()
        {
          TweenLite.set(draggTarget, {left:initPosition.left, top:initPosition.top});
        }
      }) 
  }

function getPosition(element)
{
  draggTarget = element;
  initPosition = $(element).offset();
}

  // when dragging ends, scale back down to 1
  function dragEnd() {
    if(scaleTl) {
      scaleTl.kill()
    } 
    console.log('scaling to', 1)
    scaleTl = TweenLite.to(body, duration, {scale: 1}) ;
  }

  Draggable.create(".box", {
    bounds:$container,
    edgeResistance:0.65,
    type:"x,y",
    throwProps:true,
    onPress : getPosition,
    onPressParams : [this.target],
    onDragStart : dragStart,
    onDragEnd : dragEnd
  });

Like that as the body scales up the target element will be kept in it's original position.

 

As for the pointer position and possible drag resistance I'm not following you. Maybe you could elaborate a little bit, so the 5 neurons that actually work in my brain can grasp that issue. What I can tell you is that for some time Draggable does works very well with transformed elements, you can check a sample here:

 

See the Pen KAFow?editors=001 by rhernando (@rhernando) on CodePen

 

With the exceptions of the 3D transforms (even if they work the tool is not design to work with those so you might not get accurate results) , I don't see any resistance while dragging.

 

Rodrigo.

  • Like 1
Link to comment
Share on other sites

I think I see exactly what's happening, and I have attached a revised version of Draggable that should resolve things, although you need to make sure you update() your Draggable after you scale the parent so that Draggable can calibrate its concatenated matrix on that element's transforms. 

 

See the demo in this codepen: 

http://codepen.io/GreenSock/pen/38be2888d72811c90f8e95f4800680d9/?editors=001

 

Is that what you were looking for? 

 

Again, please make sure you use the attached version of Draggable which is a preview of what we'll drop into the next official release. 

Draggable_0.10.2_preview.zip

  • Like 4
Link to comment
Share on other sites

@rhernando - thank you very much for the suggestion. I was pursuing this approach and it feels like it could get me there eventually, although with an unfortunate amount of math & state tracking.

 

@GreenSock - that looks fantastic. This is exactly the behavior I am expecting in the codepen demo. I will try applying this preview to our production code so that I can raise any other issues that I might see. Thank you very much for the quick response.. 

  • Like 2
Link to comment
Share on other sites

@GreenSock - I've been working to integrate the new draggable preview with our project, and I've run into one major issue, which I have coded up here: 

See the Pen rpJHh?editors=011 by anon (@anon) on CodePen

 

Basically, our DOM is a bit more complicated than the original example, and it turns out that matters. All of the math could use some tweaking, and thats fine, but the main thing to look at is what happens if you scroll down in your content and then press on one of the box elements. 

 - The onupdate fires, and fakes dragging with our bogus event while scaling is happening

 - When I start actually dragging, the box element jumps down

Link to comment
Share on other sites

I think I know exactly what's happening. All of the coordinates are based on the distance from the transformOrigin for each element (because we have to accommodate nested transforms), and you were changing the transformOrigin AFTER the mouse/touch was pressed. So, upon press, it figured out the local coordinates of the mouse (based on the origin) and recorded the starting position and then you switched the origin so that it's in a completely different place ("center top"), so the subsequent move was that many pixels from the origin (which moved, thus your element moved). The solution: just set the transformOrigin first (before the onPress). 

 

This had nothing to do with other HTML you added above it. And I don't even think it would be appropriate to call this a "bug", but I'll try to brain storm and see if there's a creative workaround I could implement internally. For now, I'd say just don't change the transformOrigin between onPress and onRelease. 

  • Like 1
Link to comment
Share on other sites

I've updated the codepen to set the transform origin as part of setup:

See the Pen rpJHh?editors=111 by anon (@anon) on CodePen

 

So, this explains the initial pop that I was seeing on first drag. However, it does not seem to address the main issue that I see. To reproduce:

 - While scrolled to the top of the page, drag one of the boxes towards the bottom half of the grid, then release. Everything works well.

 - Now scroll down the page so that box is in view again. Press and hold without dragging. T

 - Now start to drag. As soon as the first drag event fires, the box will jump down the page.

  • Like 1
Link to comment
Share on other sites

I believe I resolved the problem(s) - one had to do with the fact that you were adjusting the drag event's values based on the scroll position of the container div (long story, but that was only necessary in the one where you were affecting the <body>'s scroll position), and the other had to do with the need to add some logic internally to compensate for a parent's scroll position when determining coordinates. I have attached a revised version of Draggable - would you mind kicking the tires and seeing if you can break it? 

 

Here's a revised codepen that seems to work:

http://codepen.io/GreenSock/pen/bc9134a7e3d360c86dc984d4b328c011/?editors=001

 

That's what you were looking for, right?

Draggable_0.10.2_preview.zip

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

Jack, resurrecting this thread with another edge case.  

 

I have put together a contrived example here: 

See the Pen KFngp?editors=001 by anon (@anon) on CodePen

 

To recreate the issue begin dragging the tile around, and keep moving your mouse. In particular move the mouse outside of the grid or move it back and forth crazily. Eventually, you should see the tile snap to a new position and detach from the mouse. 

 

I have traced the issue back to this line of code: https://github.com/greensock/GreenSock-JS/blob/master/src/uncompressed/utils/Draggable.js#L1372

 

As the zoom tween fires, it is forcing the draggable instance to update. Occasionally the x or y properties change very slightly during syncXY (always on the order of e-15, possibly a js floating point error?), which causes the draggable instance to recordStartPositions again, when I don't believe it should be.

Link to comment
Share on other sites

  • 4 weeks later...

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