Skip to content

Commit 2019ae1

Browse files
authored
Add mirror threshold options
1 parent ecc04b2 commit 2019ae1

File tree

5 files changed

+157
-4
lines changed

5 files changed

+157
-4
lines changed

src/Draggable/Plugins/Mirror/Mirror.js

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export const defaultOptions = {
3232
yAxis: true,
3333
cursorOffsetX: null,
3434
cursorOffsetY: null,
35+
thresholdX: null,
36+
thresholdY: null,
3537
};
3638

3739
/**
@@ -140,6 +142,12 @@ export default class Mirror extends AbstractPlugin {
140142

141143
const {source, originalSource, sourceContainer, sensorEvent} = dragEvent;
142144

145+
// Last sensor position of mirror move
146+
this.lastMirrorMovedClient = {
147+
x: sensorEvent.clientX,
148+
y: sensorEvent.clientY,
149+
};
150+
143151
const mirrorCreateEvent = new MirrorCreateEvent({
144152
source,
145153
originalSource,
@@ -187,13 +195,38 @@ export default class Mirror extends AbstractPlugin {
187195

188196
const {source, originalSource, sourceContainer, sensorEvent} = dragEvent;
189197

198+
let passedThreshX = true;
199+
let passedThreshY = true;
200+
201+
if (this.options.thresholdX || this.options.thresholdY) {
202+
const {x: lastX, y: lastY} = this.lastMirrorMovedClient;
203+
204+
if (Math.abs(lastX - sensorEvent.clientX) < this.options.thresholdX) {
205+
passedThreshX = false;
206+
} else {
207+
this.lastMirrorMovedClient.x = sensorEvent.clientX;
208+
}
209+
210+
if (Math.abs(lastY - sensorEvent.clientY) < this.options.thresholdY) {
211+
passedThreshY = false;
212+
} else {
213+
this.lastMirrorMovedClient.y = sensorEvent.clientY;
214+
}
215+
216+
if (!passedThreshX && !passedThreshY) {
217+
return;
218+
}
219+
}
220+
190221
const mirrorMoveEvent = new MirrorMoveEvent({
191222
source,
192223
originalSource,
193224
sourceContainer,
194225
sensorEvent,
195226
dragEvent,
196227
mirror: this.mirror,
228+
passedThreshX,
229+
passedThreshY,
197230
});
198231

199232
this.draggable.trigger(mirrorMoveEvent);
@@ -248,6 +281,8 @@ export default class Mirror extends AbstractPlugin {
248281
this.mirrorOffset = mirrorOffset;
249282
this.initialX = initialX;
250283
this.initialY = initialY;
284+
this.lastMovedX = initialX;
285+
this.lastMovedY = initialY;
251286
return {mirrorOffset, initialX, initialY, ...args};
252287
};
253288

@@ -258,6 +293,8 @@ export default class Mirror extends AbstractPlugin {
258293
mirrorClass,
259294
scrollOffset: this.scrollOffset,
260295
options: this.options,
296+
passedThreshX: true,
297+
passedThreshY: true,
261298
};
262299

263300
return (
@@ -284,6 +321,13 @@ export default class Mirror extends AbstractPlugin {
284321
return null;
285322
}
286323

324+
const setState = ({lastMovedX, lastMovedY, ...args}) => {
325+
this.lastMovedX = lastMovedX;
326+
this.lastMovedY = lastMovedY;
327+
328+
return {lastMovedX, lastMovedY, ...args};
329+
};
330+
287331
const initialState = {
288332
mirror: mirrorEvent.mirror,
289333
sensorEvent: mirrorEvent.sensorEvent,
@@ -292,9 +336,15 @@ export default class Mirror extends AbstractPlugin {
292336
initialX: this.initialX,
293337
initialY: this.initialY,
294338
scrollOffset: this.scrollOffset,
339+
passedThreshX: mirrorEvent.passedThreshX,
340+
passedThreshY: mirrorEvent.passedThreshY,
341+
lastMovedX: this.lastMovedX,
342+
lastMovedY: this.lastMovedY,
295343
};
296344

297-
return Promise.resolve(initialState).then(positionMirror({raf: true}));
345+
return Promise.resolve(initialState)
346+
.then(positionMirror({raf: true}))
347+
.then(setState);
298348
}
299349

300350
/**
@@ -432,7 +482,20 @@ function removeMirrorID({mirror, ...args}) {
432482
* @private
433483
*/
434484
function positionMirror({withFrame = false, initial = false} = {}) {
435-
return ({mirror, sensorEvent, mirrorOffset, initialY, initialX, scrollOffset, options, ...args}) => {
485+
return ({
486+
mirror,
487+
sensorEvent,
488+
mirrorOffset,
489+
initialY,
490+
initialX,
491+
scrollOffset,
492+
options,
493+
passedThreshX,
494+
passedThreshY,
495+
lastMovedX,
496+
lastMovedY,
497+
...args
498+
}) => {
436499
return withPromise(
437500
(resolve) => {
438501
const result = {
@@ -444,8 +507,14 @@ function positionMirror({withFrame = false, initial = false} = {}) {
444507
};
445508

446509
if (mirrorOffset) {
447-
const x = sensorEvent.clientX - mirrorOffset.left - scrollOffset.x;
448-
const y = sensorEvent.clientY - mirrorOffset.top - scrollOffset.y;
510+
const x = passedThreshX
511+
? Math.round((sensorEvent.clientX - mirrorOffset.left - scrollOffset.x) / (options.thresholdX || 1)) *
512+
(options.thresholdX || 1)
513+
: lastMovedX;
514+
const y = passedThreshY
515+
? Math.round((sensorEvent.clientY - mirrorOffset.top - scrollOffset.y) / (options.thresholdY || 1)) *
516+
(options.thresholdY || 1)
517+
: lastMovedY;
449518

450519
if ((options.xAxis && options.yAxis) || initial) {
451520
mirror.style.transform = `translate3d(${x}px, ${y}px, 0)`;
@@ -459,6 +528,9 @@ function positionMirror({withFrame = false, initial = false} = {}) {
459528
result.initialX = x;
460529
result.initialY = y;
461530
}
531+
532+
result.lastMovedX = x;
533+
result.lastMovedY = y;
462534
}
463535

464536
resolve(result);

src/Draggable/Plugins/Mirror/MirrorEvent/MirrorEvent.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ export class MirrorMoveEvent extends MirrorEvent {
141141
get mirror() {
142142
return this.data.mirror;
143143
}
144+
145+
/**
146+
* Sensor has exceeded mirror's threshold on x axis
147+
* @type {Boolean}
148+
* @readonly
149+
*/
150+
get passedThreshX() {
151+
return this.data.passedThreshX;
152+
}
153+
154+
/**
155+
* Sensor has exceeded mirror's threshold on y axis
156+
* @type {Boolean}
157+
* @readonly
158+
*/
159+
get passedThreshY() {
160+
return this.data.passedThreshY;
161+
}
144162
}
145163

146164
/**

src/Draggable/Plugins/Mirror/MirrorEvent/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ The mirror follows your mouse/touch movements.
9696
Read-only property for the mirror element, which is also a copy of the `originalSource` element.
9797
The mirror follows your mouse/touch movements.
9898

99+
**`mirrorEvent.passedThreshX: Booolean`**
100+
Read-only property for whether or not the mirror's threshold has been exceeded in the x axis.
101+
102+
**`mirrorEvent.passedThreshY: Booolean`**
103+
Read-only property for whether or not the mirror's threshold has been exceeded in the y axis.
104+
105+
99106
## MirrorDestroyEvent
100107

101108
`MirrorDestroyEvent` gets triggered before the mirror gets removed from the DOM.

src/Draggable/Plugins/Mirror/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ this is not where the source will be placed, only the temporary mirror element,
3232
that follows your cursor as you drag. You can specify a css selector, a HTMLElement or a function
3333
that returns a HTMLElement. Default is the source parent element.
3434

35+
**`thresholdX {Number|null}`**
36+
Defining this sets a threshold that must be exceeded by the mouse for the mirror to move on the x axis. Default: `null`
37+
38+
**`thresholdY {Number|null}`**
39+
Defining this sets a threshold that must be exceeded by the mouse for the mirror to move on the y axis. Default: `null`
40+
3541
### Events
3642

3743
| Name | Description | Cancelable | Cancelable action |

src/Draggable/Plugins/Mirror/tests/Mirror.test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,56 @@ describe('Mirror', () => {
270270
releaseMouse(draggable.source);
271271
});
272272

273+
it('moves mirror only when past `thresholdX` or `thresholdY`', async () => {
274+
draggable = new Draggable(container, {
275+
...draggableOptions,
276+
mirror: {
277+
thresholdX: 10,
278+
thresholdY: 50,
279+
},
280+
});
281+
282+
clickMouse(draggableElement);
283+
waitForDragDelay();
284+
waitForRequestAnimationFrame();
285+
286+
await waitForPromisesToResolve();
287+
288+
const mirrorElement = document.querySelector('.draggable-mirror');
289+
290+
moveMouse(document.body, {
291+
clientX: 5,
292+
clientY: 10,
293+
});
294+
295+
await waitForPromisesToResolve();
296+
waitForRequestAnimationFrame();
297+
298+
expect(mirrorElement.style.transform).toBe('translate3d(0px, 0px, 0)');
299+
300+
moveMouse(document.body, {
301+
clientX: 10,
302+
clientY: 40,
303+
});
304+
305+
await waitForPromisesToResolve();
306+
waitForRequestAnimationFrame();
307+
308+
expect(mirrorElement.style.transform).toBe('translate3d(10px, 0px, 0)');
309+
310+
moveMouse(document.body, {
311+
clientX: 100,
312+
clientY: 100,
313+
});
314+
315+
await waitForPromisesToResolve();
316+
waitForRequestAnimationFrame();
317+
318+
expect(mirrorElement.style.transform).toBe('translate3d(100px, 100px, 0)');
319+
320+
releaseMouse(draggable.source);
321+
});
322+
273323
it('prevents mirror movement when `mirror:move` gets canceled', async () => {
274324
draggable = new Draggable(container, draggableOptions);
275325

0 commit comments

Comments
 (0)