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?
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()
}
}
}