RactiveJS draggable utilizing mouseevent

I am trying to achieve a simple draggable DIV with RactiveJS utilizing proxy events (on-mousedown,up,move,out)

Following JSFiddle works just fine, however when the user moves the mouse too fast the dragging stops. This is simply because the mouseevent handlers in my case are on the DIV tag instead of the body or document elements. The final idea I have is to create a slider component, however I am seeking to provide the best user experience and make this work more like JQuery's draggable.

Template:

<div class="rect {{drag ? 'dragging' : ''}}" 
         on-mousedown="startDrag"
         on-mouseup="stopDrag" 
         on-mouseout="stopDrag" 
         on-mousemove="drag"
         style="top:{{top}}px; left:{{left}}px;">
</div>

Ractive instance:

var ractive = new Ractive({
    el: "#content",
    template: "#template",
    data: {left:20,top:80}
});
ractive.on({
    startDrag : function (event) {
        this.set({
            'drag': true,
            'mouseX': event.original.clientX - this.get('left'),
            'mouseY': event.original.clientY - this.get('top')
        });
    },
    stopDrag : function (event) {
        this.set('drag', false);
    },
    drag : function (event) {
        if(this.get('drag')) {
            var x = event.original.clientX, 
                y = event.original.clientY;
            this.set({
                top: y - this.get('mouseY') ,
                left: x - this.get('mouseX')
            });
            event.original.stopPropagation();
        }
    }
})

How can I improve the above code?

Answers:

Answer

Usually mousemove and mouseend need to be on the document. I find that with Ractive a decorator usually works better for dragging. Here's one example to get you going (http://jsfiddle.net/h9j2hdyj/1/):

<div class="rect noSelect {{ dragging ? 'dragging' : ''}}" 
     decorator='drag:"position"'
     style="{{#position}}top:{{top}}px;left:{{left}}px{{/}}">
</div>

decorator:

Ractive.decorators.drag = function(node, keypath){

    var ractive = this, initial, begin, startPos;

    node.addEventListener('mousedown', start, false)

    function listenOnDocument(){
        document.addEventListener('mousemove', move, false)
        document.addEventListener('mouseup', unlistenOnDocument, false)
    }

    function unlistenOnDocument(){
        document.removeEventListener('mousemove', move, false)
        document.removeEventListener('mouseup', end, false)
    }

    function start(e){
        begin = { x: e.x, y: e.y }
        startPos = ractive.get(keypath)
        startPos = { x: startPos.left, y: startPos.top }
        ractive.set('dragging', true)
        listenOnDocument()
        e.preventDefault()
        e.stopPropagation()
    }

    function move(e){
        ractive.set(keypath, {
            left: startPos.x + (e.x - begin.x),
            top: startPos.y + (e.y - begin.y)
        })
        e.preventDefault()
        e.stopPropagation()
    }

    function end(){
        unlistenOnDocument()
        ractive.set('dragging', false)
    }

  return {
      update: function(pos){
          console.log(pos)
          position = pos
      },
    teardown: function(){
        node.removeEventListener('mousedown', start, false)
        end()
    }
  }

}
Answer

Another option is to use the ractive-touch plugin's pan events - they use Hammer.js under the hood so they're mouse- and touch-friendly.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.