You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
79 lines
2.5 KiB
JavaScript
79 lines
2.5 KiB
JavaScript
"use strict";
|
|
|
|
// const React = require("react");
|
|
const euclideanDistance = require("euclidean-distance");
|
|
const throttleit = require("throttleit");
|
|
// const useForceUpdate = require("use-force-update");
|
|
|
|
/* CAUTION: This hook has a bunch of effectively-global state! This is fine since a) there can only ever be one drag operation on a document at a time anyway, and b) this appears to be necessary to sidestep performance limitations introduced by React's state-handling cycles, but it's definitely something you shouldn't normally do. */
|
|
|
|
let operationData;
|
|
let isDragging;
|
|
let lastMouseX;
|
|
let lastMouseY;
|
|
let newX;
|
|
let newY;
|
|
let onChangeCallback;
|
|
let thresholdMet = false;
|
|
let dragThreshold;
|
|
|
|
function getCurrentValues() {
|
|
return {
|
|
x: operationData.initialValueX + (lastMouseX - operationData.initialMouseX),
|
|
y: operationData.initialValueY + (lastMouseY - operationData.initialMouseY)
|
|
};
|
|
}
|
|
|
|
let processMouseMove = throttleit(() => {
|
|
/* Yes, the below check is there for a reason; just in case the `movingWindow` state changes between the call to the throttled wrapper and the wrapped function itself. */
|
|
if (onChangeCallback != null) {
|
|
if (thresholdMet === false) {
|
|
let origin = [operationData.initialMouseX, operationData.initialMouseY];
|
|
let position = [lastMouseX, lastMouseY];
|
|
|
|
if (euclideanDistance(origin, position) > dragThreshold) {
|
|
thresholdMet = true;
|
|
}
|
|
}
|
|
|
|
if (thresholdMet === true) {
|
|
let {x, y} = getCurrentValues();
|
|
newX = x;
|
|
newY = y;
|
|
onChangeCallback(x, y, lastMouseX, lastMouseY);
|
|
}
|
|
}
|
|
}, 10);
|
|
|
|
module.exports = {
|
|
mouseMove: function (x, y) {
|
|
/* NOTE: Due to how synthetic events work in React, we need to separate out the 'get coordinates from event' and 'do something with the coordinates' step; if we throttle the coordinate extraction logic, we'll run into problems when synthetic events have already been cleared for reuse by the time we try to obtain the coordinates. Therefore, `processMouseMove` contains all the throttled logic, whereas the coordinate extraction happens on *every* mousemove event. */
|
|
lastMouseX = x;
|
|
lastMouseY = y;
|
|
|
|
if (isDragging) {
|
|
processMouseMove();
|
|
}
|
|
},
|
|
useDraggable: function (options) {
|
|
let dragEnded;
|
|
|
|
if (isDragging === true && options.isDragging === false) {
|
|
dragEnded = true;
|
|
} else {
|
|
dragEnded = false;
|
|
}
|
|
|
|
operationData = options.operationData;
|
|
dragThreshold = options.threshold;
|
|
onChangeCallback = options.onChange;
|
|
isDragging = options.isDragging;
|
|
|
|
if (dragEnded) {
|
|
return [newX, newY];
|
|
} else {
|
|
return [null, null];
|
|
}
|
|
}
|
|
};
|