Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On gridster keep widget under mouse during drag

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');
  });
like image 237
Superdrac Avatar asked May 20 '14 12:05

Superdrac


1 Answers

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)

like image 65
mfirdaus Avatar answered Oct 23 '22 04:10

mfirdaus