Skip to content

Commit

Permalink
generalize assets/drag.js
Browse files Browse the repository at this point in the history
- to accept `path` (on top of dpos/pos0)
- to accept `touch` option to emulate touch drag
  • Loading branch information
etpinard committed Jun 11, 2019
1 parent 121227b commit 8806fb7
Showing 1 changed file with 133 additions and 33 deletions.
166 changes: 133 additions & 33 deletions test/jasmine/assets/drag.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,146 @@
var isNumeric = require('fast-isnumeric');

var mouseEvent = require('./mouse_event');
var touchEvent = require('./touch_event');
var getNodeCoords = require('./get_node_coords');
var delay = require('./delay');

function makeFns(node, dx, dy, opts) {
/**
* Inside `opts`:
*
* @param {array of 2 numbers} pos0 :
* px position of start of drag motion, default computed using `node` and `edge`
* @param {DOM element} node :
* element to drag on, default found using `pos0`
* @param {string} edge :
* combinations of 'n', 's', 'e', 'w' used to find `pos0` of `node`
*
* Set one of:
* @param {array of arrays of numbers} path :
* px position drag path
* @param {array of 2 numbers} dpos :
* px position delta
* @param {array of 2 numbers} posN :
* px position of end of drag motion
*
* If using `dpos` or `posN`
* @param {number} nsteps :
* set number of steps to take between `pos0` and `pos0` + `dpos` or `posN`, default is 1
*
* @param {boolean} touch :
* pass `true` to simulate touch events
* @param {boolean} shiftKey, altKey, ctrlKey ....
* pass `true to simulate <shift>, alt, ctrl drag (see ./mouse_event.js for more info)
*
* @param {function} clearThrottle :
* pass Lib.clearThrottle to clear throttle for all mouse/touch event
* @param {boolean} noCover :
* do not wait for "drag cover" element to start "move" events
*
* @return {object}
* - {function} start
* - {function} end
*/
function makeFns(opts) {
opts = opts || {};

var nsteps = opts.nsteps || 1;
var edge = opts.edge || '';
var noCover = Boolean(opts.noCover);
var path;

if(Array.isArray(opts.path) && opts.path.length >= 2 &&
Array.isArray(opts.path[0]) && Array.isArray(opts.path[1])) {
path = opts.path;
} else {
var nsteps = opts.nsteps || 1;
var p0, dp;
var msg = [];

if(opts.pos0 && isNumeric(opts.pos0[0]) && isNumeric(opts.pos0[1])) {
p0 = opts.pos0;
} else if(opts.node) {
var coords = getNodeCoords(opts.node, opts.edge || '');
p0 = [coords.x, coords.y];
} else {
msg.push('Cannot determine drag path start position from the given options');
}

if(opts.dpos && isNumeric(opts.dpos[0]) && isNumeric(opts.dpos[1])) {
dp = opts.dpos;
} else if(opts.posN && isNumeric(opts.posN[0]) && isNumeric(opts.posN[1])) {
dp = [opts.posN[0] - opts.pos0[0], opts.posN[1] - opts.pos0[1]];
} else {
msg.push('Cannot determine drag path step from the given options');
}

if(msg.length) {
throw new Error(msg.join('\n'));
}

path = [p0];

for(var i = 1; i <= nsteps; i++) {
path[i] = [
p0[0] + i * dp[0] / nsteps,
p0[1] + i * dp[1] / nsteps
];
}
}

var coords = getNodeCoords(node, edge);
var fromX = isNumeric(opts.x0) ? opts.x0 : coords.x;
var fromY = isNumeric(opts.y0) ? opts.y0 : coords.y;
function extendOpts(patch) {
var out = {};
var k;
for(k in opts) out[k] = opts[k];
for(k in patch) out[k] = patch[k];
return out;
}

var dragCoverNode;
var toX;
var toY;

function start() {
mouseEvent('mousemove', fromX, fromY, {element: node});
mouseEvent('mousedown', fromX, fromY, {element: node});
if(opts.clearThrottle) opts.clearThrottle();

var x0 = path[0][0];
var y0 = path[0][1];

var _opts = extendOpts({element: opts.node});

if(opts.touch) {
touchEvent('touchstart', x0, y0, _opts);
} else {
mouseEvent('mousemove', x0, y0, _opts);
mouseEvent('mousedown', x0, y0, _opts);
}

return (noCover ? Promise.resolve(node) : waitForDragCover())
return (opts.noCover ? Promise.resolve(opts.node) : waitForDragCover())
.then(function(_dragCoverNode) {
dragCoverNode = _dragCoverNode;

for(var i = 1; i <= nsteps; i++) {
toX = fromX + i * dx / nsteps;
toY = fromY + i * dy / nsteps;
mouseEvent('mousemove', toX, toY, {element: dragCoverNode});
}
var _opts = extendOpts({element: dragCoverNode});

path.slice(1).forEach(function(p) {
if(opts.clearThrottle) opts.clearThrottle();
if(opts.touch) {
touchEvent('touchmove', p[0], p[1], _opts);
} else {
mouseEvent('mousemove', p[0], p[1], _opts);
}
});
});
}

function end() {
mouseEvent('mouseup', toX, toY, {element: dragCoverNode});
return noCover || waitForDragCoverRemoval();
var iN = path.length - 1;
var xN = path[iN][0];
var yN = path[iN][1];

var _opts = extendOpts({element: dragCoverNode});

if(opts.touch) {
touchEvent('touchend', xN, yN, _opts);
} else {
mouseEvent('mouseup', xN, yN, _opts);
}

return opts.noCover || waitForDragCoverRemoval();
}

return {
Expand All @@ -45,21 +149,17 @@ function makeFns(node, dx, dy, opts) {
};
}

/*
* drag: grab a node and drag it (dx, dy) pixels
* optionally specify an edge ('n', 'se', 'w' etc)
* to grab it by an edge or corner (otherwise the middle is used)
/**
* Inside `opts`:
*
* Same as in makeDragFns plus:
*
* @param {number} timeDelay :
* time delay between drag start promise resolve and drag end call
*/
function drag(node, dx, dy, edge, x0, y0, nsteps, noCover, timeDelay) {
if(!timeDelay) timeDelay = 0;
var fns = makeFns(node, dx, dy, {
edge: edge,
x0: x0,
y0: y0,
nsteps: nsteps,
noCover: noCover
});

function drag(opts) {
var fns = makeFns(opts);
var timeDelay = opts.timeDelay || 0;
return fns.start().then(delay(timeDelay)).then(fns.end);
}

Expand Down

0 comments on commit 8806fb7

Please sign in to comment.