|
var most = require('most'); |
|
|
|
var DROP = 0, GRAB = 1, DRAG = 2; |
|
|
|
(function() |
|
{ |
|
// The thing we want to make draggable |
|
var playground = document.querySelector('.playground'); |
|
var draggable = document.querySelector('.draggable'); |
|
var dragOffset = {}; |
|
|
|
// A higher-order stream (stream whose events are themselves streams) |
|
// A mousedown DOM event generates a stream event which is |
|
// a stream of 1 GRAB followed by DRAGS (ie mousemoves). |
|
var drag = most.fromEvent('mousedown', draggable) |
|
.map(function(e) |
|
{ |
|
e.preventDefault(); |
|
|
|
console.log('e: ' + e.clientX + ', ' + e.clientY); |
|
console.log('draggable: ' + draggable.offsetLeft + ', ' + draggable.offsetTop + " (" + draggable.offsetWidth + "x" + draggable.offsetHeight + ")"); |
|
dragOffset.dx = e.clientX - draggable.offsetLeft; |
|
dragOffset.dy = e.clientY - draggable.offsetTop; |
|
console.log("dragOffset: " + JSON.stringify(dragOffset)); |
|
return most.fromEvent('mousemove', playground) |
|
.map(function(e) |
|
{ |
|
return eventToDragInfo(DRAG, e); |
|
}) |
|
.startWith(eventToDragInfo(GRAB, e)); |
|
}); |
|
|
|
// A mouseup DOM event generates a stream event which is a |
|
// stream containing a DROP |
|
var drop = most.fromEvent('mouseup', playground) |
|
.map(function(e) |
|
{ |
|
return most.of(eventToDragInfo(DROP, e)); |
|
}); |
|
|
|
// Merge the drag and drop streams |
|
// Then use switch() to ensure that the resulting stream behaves |
|
// like the drag stream until an event occurs on the drop stream. Then |
|
// it will behave like the drop stream until the drag stream starts |
|
// producing events again. |
|
// This effectively *toggles behavior* between dragging behavior and |
|
// dropped behavior. |
|
most.merge(drag, drop) |
|
.switch() |
|
.reduce(handleDrag, dragOffset); |
|
})(); |
|
|
|
function eventToDragInfo(action, e) |
|
{ |
|
return { action: action, target: e.target, x: e.clientX, y: e.clientY }; |
|
} |
|
|
|
function handleDrag(offset, dd) |
|
{ |
|
var el = dd.target; |
|
|
|
// console.log(dd); |
|
if (dd.action === GRAB) |
|
{ |
|
el.classList.add('dragging'); |
|
return offset; |
|
} |
|
|
|
if (dd.action === DROP) |
|
{ |
|
el.classList.remove('dragging'); |
|
return offset; |
|
} |
|
|
|
var els = dd.target.style; |
|
els.left = (dd.x - offset.dx) + 'px'; |
|
els.top = (dd.y - offset.dy) + 'px'; |
|
|
|
return offset; |
|
} |