bevacqua / dragula

:ok_hand: Drag and drop so simple it hurts
https://bevacqua.github.io/dragula/
MIT License
21.91k stars 1.97k forks source link

Scroll while dragging #121

Closed bryannielsen closed 8 years ago

bryannielsen commented 9 years ago

I see two situations where implementing some scrolling would be very helpful -

If the container is taller than the viewport. It would be nice if the plugin could scroll the page when you hit the edge of the viewport while dragging an item.

If the target container has a height restriction along with overflow:scroll. Similarly, the plugin could change the scroll position of the target container when you hit an edge.

I made an attempt at implementing this but it seems that my handler bound to mousemove was only being triggered when I dragged an element outside of the container and back in. I'm not sure if the plugin is killing mousemove events for performance reasons (that's my guess) but is there any other way to get the position of the dragged element as it moves?

Thanks!

bevacqua commented 9 years ago

Can you show me a demo?

rohitdaryanani commented 9 years ago

I think he means something like this.

screen recording 2015-07-22 at 09 24 am

I just filed a similar issue yesterday in dragular since my project is angular here is the link to issue

bevacqua commented 9 years ago

Ah, got it. Can you work on a tentative PR?

rohitdaryanani commented 9 years ago

I tried working on it but somehow the mouse events don't get triggered.

bevacqua commented 9 years ago

I presume you'd have to use requestAnimationFrame or some such to get the scrolling going

fergyfresh commented 9 years ago

I could look into this one as well, also granted no one beats me to it before I get some free time.

bevacqua commented 9 years ago

@fergyfresh feel free to look into as many as you want! that's encouraged :dancers:

fergyfresh commented 9 years ago

Those are the only ones I think I can fix xD

On Wed, Jul 22, 2015, 10:09 PM Nicolas Bevacqua notifications@github.com wrote:

@fergyfresh https://github.com/fergyfresh feel free to look into as many as you want! that's encouraged [image: :dancers:]

— Reply to this email directly or view it on GitHub https://github.com/bevacqua/dragula/issues/121#issuecomment-123930974.

bryannielsen commented 9 years ago

Yea @rohitdaryanani's gif is a perfect example for the second case, but also if you can imagine a container that's taller than the viewport, it would be nice to scroll the viewport down when you dragged an item to the bottom of the container.

I ran into the same issue with not being able to get realtime data from mouse events but I wasn't sure if there were other ways to get the dragged item position after the drag started. I suppose doing something with setInterval to grab the item position once the drag is initiated and scrolling based on that might work, and then once the item is released kill the handler? I could try this out later if it sounds viable, I'm not an expert with this stuff :-p

rohitdaryanani commented 9 years ago

Hey @bryannielsen, @luckylooke solved this in the angular version known as dragular heres the link.

zeeamber commented 9 years ago

I have addressed both the issues

  1. If the container is taller than the viewport
  2. If the target container has a height restriction along with overflow:scroll

changes are pushed to a new branch "scroll-while-dragging". I'm new to github technicalities. help me out if anything is left from my side. Thanks

@bryannielsen @bevacqua

luanfonceca commented 8 years ago

I want that too.

o/

Klaasvaak commented 8 years ago

I implemented a scroll on drag in my project. Here is a snippet:

    document.addEventListener('mousemove', this._onMouseMove);   

    _onMouseMove (e) {
      this._pageY = e.pageY;

      if (this._drake.dragging) {
        //scroll while drag
        const y = this._pageY;
        const container = document.querySelector('.my-container');
        const containerBottom = container.offsetTop + container.offsetHeight;
        const containerTop = container.offsetTop;

        if (containerBottom - y < 120) {
          this._scrollDown(container, y);
        } else if (containerTop + y < 120) {
          this._scrollUp(container, y);
        }
      }
    },

  _scrollDown (container, pageY) {
    if (this._drake.dragging && pageY === this._pageY) {
      container.scrollTop += 5;
      setTimeout(this._scrollDown.bind(this, container, pageY), 20);
    }
  }

  _scrollUp (container, pageY) {
    if (this._drake.dragging && pageY === this._pageY) {
      container.scrollTop -= 5;
      setTimeout(this._scrollUp.bind(this, container, pageY), 20);
    }
  }

I use setTimeout to keep on scrolling when we mouse is not moving. Of course the callback of setTimeout should be saved and cleared when the view is removed.

bevacqua commented 8 years ago

I like this solution way better than what we have in PR #129. Think you could contribute a ES5 version of it with a PR? It should also be able to scroll sideways.

Klaasvaak commented 8 years ago

@bevacqua I looked at the PR and I find it very hard to understand.

I think it should just be something like this:

  1. add mousemove event
  2. is mouseposition in container? continue
  3. are we dragging? continue
  4. is mouseposition at the top or bottom in container? continue
  5. scroll up or scroll down. Call scroll up or scroll down with a timeout
  6. if previous mouse position does not equals current mouse position: stop else => go to 5.

If you want to scroll horizontal just switch above text up and down for left and right.

bevacqua commented 8 years ago

Sounds awesome, and I think your code is also much terser. Would you consider creating a PR of your own? It'd be greatly appreciated.

Klaasvaak commented 8 years ago

I will have a look

chezwicker commented 8 years ago

Just another suggestion based on what dragular is doing: simply fire dragenter and dragleave events that can be listened to - see pull request. Feel free to discard if that's not the way to go (but please tell me why in that case ;-)...

swatigoel1991 commented 8 years ago

In my project, i need a page level scroll. I have one Dragula instance containing 3 containers. Each container has many widgets. I don't need container level scroll. Currently Dragula is not supporting it and i above approach is also not addressing this issue.

hollowdoor commented 8 years ago

I have created a module that will do this kind of scrolling in a more generic way. See pull request https://github.com/bevacqua/dragula/pull/200 for the conversation about this.

Here is the link https://github.com/hollowdoor/dom_autoscroller with dragula being used in the example. The module can be found on npm at dom-autoscroller.

dom-autoscroller handles container level scroll as well as document/page level scroll if you set it's element to window.

ghost commented 8 years ago

Just my 2 cents: It should use something similar to jQuery.scrollParent() to detect the element that needs to be scrolled. In my case I need the page to be scrolled.

scooterlord commented 8 years ago

Hello! Is this going to be implemented after all?

bevacqua commented 8 years ago

Closing in favor of modules such as dom-autoscroller

Klaasvaak commented 8 years ago

:+1:

nguyenj commented 7 years ago

@bryannielsen I have a PR out that address scrolling while dragging. Let me know if this works for you.

r-sw-eet commented 3 years ago

would be nice to have, or how is dom-autoscroller a workaround?

eevleevs commented 3 years ago

None of the suggestions here helped, I ended making https://github.com/eevleevs/scroller