On gridster keep widget under mouse during drag
Asked Answered
S

1

6

I actually use gridster for drag some items.

My container is bigger than my window, so, i have a scrollbar on the right side, as usual. Now, if i want to drag an item from the top to the bottom, I need to click on it and scroll the mouse at the same time.

As you can see on this fiddle, If you take the item and you start to scroll, the item stay at his first position, you need to move the mouse for bring it to it.

There is a way for keep the item under the mouse even if you scroll ?

Sample html code:

<div class="container">
  <div class="gridster">
    <ul>
       <li data-row="1" data-col="1" data-sizex="2" data-sizey="2">0</li>
       <li data-row="1" data-col="3" data-sizex="1" data-sizey="2">1</li>
       <li data-row="1" data-col="4" data-sizex="1" data-sizey="1">2</li>
       <li data-row="3" data-col="2" data-sizex="3" data-sizey="1">3</li>
       <li data-row="4" data-col="1" data-sizex="1" data-sizey="1">4</li>
       <li data-row="3" data-col="1" data-sizex="1" data-sizey="1">5</li>
       <li data-row="4" data-col="2" data-sizex="1" data-sizey="1">6</li>
       <li data-row="5" data-col="2" data-sizex="1" data-sizey="1">7</li>
       <li data-row="4" data-col="4" data-sizex="1" data-sizey="1">8</li>
       <li data-row="1" data-col="5" data-sizex="1" data-sizey="3">9</li>
    </ul>
  </div>
</div>

Sample css code:

.container{
    height:1600px;
}

Sample jQuery code:

 var gridster;

  $(function(){
    gridster = $(".gridster ul").gridster({
      widget_base_dimensions: [100, 55],
      widget_margins: [5, 5],
    }).data('gridster');
  });
Suffice answered 20/5, 2014 at 12:40 Comment(2)
Trying to understand your issue: are you saying you are trying to scroll with the scroll wheel on your mouse while holding down the mouse click for the drag? Why not just drag the item and let the window scroll naturally as you drag it out of view?Whitecollar
"are you saying you are trying to scroll with the scroll wheel on your mouse while holding down the mouse click for the drag?" --> Yes ! Its what i'm trying. "Why not just drag the item and let the window scroll naturally as you drag it out of view?" --> Because my document height is dynamic and when it become really big it's just horrible (and buggy) to let the window scroll naturally..Suffice
L
7

I guess defined as an algorithm, we want the draggable object, when we scroll, to stay where the mouse is. So we'd need an onScroll event somewhere.

Normally, we'd just update the position of the object with the position of the mouse, but onScroll doesn't seem to have mouse position information attached to it. Rephrasing it, we could say that we want the object to move/offset by n amount equal to the amount we scroll. That could work.

Of course some poking around gridster is needed to figure out how to offset the object. But I think something like this could work:

var gridster = $(".gridster ul").gridster({
  widget_base_dimensions: [100, 55],
  widget_margins: [5, 5],
  draggable: {
    start: function (e, ui, $widget) {
      var that = this , //to access gridster from inside onscroll
          oldScroll = $(document).scrollTop() //to calculate scroll change 
          obj = $(this.helper ? this.$helper : this.$player) //draggable/helper

      $(document).on("scroll", function () {
        //calculate scroll change
        var curr = $(document).scrollTop()
        var diff = curr-oldScroll
        oldScroll = curr
        //add change to stored offset for gridster
        that.drag_api.el_init_offset.top += diff 

        //show change temporarily because gridster doesn't update
        obj.css({
          'top': parseFloat(obj.css("top")) + diff
        });

      })
    },
    stop: function (e, ui, $widget) {
      $(document).off("scroll")
    }
  }
}).data('gridster');

Example

I guess this will be a good starting point. Current caveats, the grid itself doesn't update until another mousemove. Might need more poking about.


Update

The above code breaks on drag scroll as gridster has it's own scrolling implementation. Looking at the problem I couldn't find a way to differentiate between drag scroll and normal scroll (looked at onMouseWheel and DOMMouseScroll but didn't look like it was well supported. So I suppose a quick fix would be to disable offsetting on scroll if near the edge. So adding these:

//change stored offset for gridster if not on edge
if(!that.edge) that.drag_api.el_init_offset.top += diff 

And we need to check on drag. So we add a drag handler to gridster. Something like:

  drag:function(e,ui,$widget){
     //check if edge
     var pixelFromEdge=100
     this.edge= e.clientY< pixelFromEdge ||
     $("html")[0].clientHeight-e.clientY < pixelFromEdge   
  },

Demo

Honestly it feels there's probably a better and more elegant solution (short of actually modifying the plugin. which would probably be a lot easier)

Leges answered 24/5, 2014 at 13:27 Comment(4)
It seems to be a good solution, but it totally cancel the natural scoll... If you let the page scroll naturally just a little bit, your widget totally disappear at the bottom (or top of the page)Suffice
@Suffice I don't actually use mice that much anymore. So can you elaborate more on "scroll naturally"?Leges
it's hard to explain without video... Anyway, as we know, when we move the widget by scrolling the mouse wheel, the widget don't really move on the grid, we need to move the cursor a little to change its position on the grid. Now, if we are at the middle of the page, and there is a scroll bar on the left, if we move the cursor on bottom or on top, the window will scroll naturally and the widget will not stay undermouse..Suffice
@Suffice I see what you mean. I'll update a quickfix which involves edge detection (though I'm not that happy with it). I'll update it again if I can come up with a better solution (which probably involves tracking the mouse all the time with ondrag and incremeting on scroll)Leges

© 2022 - 2024 — McMap. All rights reserved.