Skip to content

Commit 2341910

Browse files
committed
Merge branch 'snap-restrict-smooth-end'
2 parents e23fd46 + b3a5b55 commit 2341910

File tree

1 file changed

+165
-77
lines changed

1 file changed

+165
-77
lines changed

interact.js

Lines changed: 165 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,20 @@
7575

7676
inertiaStatus = {
7777
active : false,
78+
smoothEnd : false,
7879
target : null,
7980
targetElement: null,
8081

8182
startEvent: null,
8283
pointerUp : {},
8384

84-
xe : 0,
85-
ye : 0,
85+
xe: 0,
86+
ye: 0,
87+
sx: 0,
88+
sy: 0,
8689
duration: 0,
8790

88-
t0 : 0,
91+
t0: 0,
8992
vx0: 0,
9093
vys: 0,
9194

@@ -196,8 +199,9 @@
196199
endSpeed : 10, // the speed at which inertia is slow enough to stop
197200
actions : ['drag', 'resize'],
198201
zeroResumeDelta: false,
202+
smoothEndDuration: 300,
199203

200-
numberTypes: /^resistance$|^minSpeed$|^endSpeed$/,
204+
numberTypes: /^resistance$|^minSpeed$|^endSpeed$|^smoothEndDuration$/,
201205
arrayTypes : /^actions$/,
202206
boolTypes: /^zeroResumeDelta$/
203207
},
@@ -911,6 +915,24 @@
911915
return origin;
912916
}
913917

918+
function calcInertia (status) {
919+
var inertiaOptions = status.target.options.inertia,
920+
lambda = inertiaOptions.resistance,
921+
inertiaDur = -Math.log(inertiaOptions.endSpeed / status.v0) / lambda;
922+
923+
status.x0 = prevEvent.pageX;
924+
status.y0 = prevEvent.pageY;
925+
status.t0 = status.startEvent.timeStamp / 1000;
926+
status.sx = status.sy = 0;
927+
928+
status.modifiedXe = status.xe = (status.vx0 - inertiaDur) / lambda;
929+
status.modifiedYe = status.ye = (status.vy0 - inertiaDur) / lambda;
930+
status.te = inertiaDur;
931+
932+
status.lambda_v0 = lambda / status.v0;
933+
status.one_ve_v0 = 1 - inertiaOptions.endSpeed / status.v0;
934+
}
935+
914936
function inertiaFrame () {
915937
var options = inertiaStatus.target.options.inertia,
916938
lambda = options.resistance,
@@ -950,6 +972,27 @@
950972
}
951973
}
952974

975+
function smoothEndFrame () {
976+
var t = new Date().getTime() - inertiaStatus.t0,
977+
duration = inertiaStatus.target.options.inertia.smoothEndDuration;
978+
979+
if (t < duration) {
980+
inertiaStatus.sx = easeOutQuad(t, 0, inertiaStatus.xe, duration);
981+
inertiaStatus.sy = easeOutQuad(t, 0, inertiaStatus.ye, duration);
982+
983+
pointerMove(inertiaStatus.startEvent);
984+
985+
inertiaStatus.i = reqFrame(smoothEndFrame);
986+
}
987+
else {
988+
inertiaStatus.active = false;
989+
inertiaStatus.smoothEnd = false;
990+
991+
pointerMove(inertiaStatus.startEvent);
992+
pointerUp(inertiaStatus.startEvent);
993+
}
994+
}
995+
953996
function _getQBezierValue(t, p1, p2, p3) {
954997
var iT = 1 - t;
955998
return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
@@ -962,6 +1005,12 @@
9621005
};
9631006
}
9641007

1008+
// http://gizma.com/easing/
1009+
function easeOutQuad (t, b, c, d) {
1010+
t /= d;
1011+
return -c * t*(t-2) + b;
1012+
}
1013+
9651014
function nodeContains (parent, child) {
9661015
while ((child = child.parentNode)) {
9671016

@@ -1331,8 +1380,8 @@
13311380
this.snap = {
13321381
range : snapStatus.range,
13331382
locked : snapStatus.locked,
1334-
x : snapStatus.x,
1335-
y : snapStatus.y,
1383+
x : snapStatus.snappedX,
1384+
y : snapStatus.snappedY,
13361385
realX : snapStatus.realX,
13371386
realY : snapStatus.realY,
13381387
dx : snapStatus.dx,
@@ -1928,8 +1977,8 @@
19281977

19291978
prepared = action;
19301979

1931-
snapStatus.x = null;
1932-
snapStatus.y = null;
1980+
snapStatus.snappedX = null;
1981+
snapStatus.snappedY = null;
19331982

19341983
downTime = new Date().getTime();
19351984
downEvent = event;
@@ -2067,8 +2116,8 @@
20672116
inRange = closest.inRange;
20682117
snapChanged = (closest.anchor.x !== status.x || closest.anchor.y !== status.y);
20692118

2070-
status.x = closest.anchor.x;
2071-
status.y = closest.anchor.y;
2119+
status.snappedX = closest.anchor.x;
2120+
status.snappedY = closest.anchor.y;
20722121
status.dx = closest.dx;
20732122
status.dy = closest.dy;
20742123
}
@@ -2087,8 +2136,8 @@
20872136
inRange = distance < snap.range;
20882137
snapChanged = (newX !== status.x || newY !== status.y);
20892138

2090-
status.x = newX;
2091-
status.y = newY;
2139+
status.snappedX = newX;
2140+
status.snappedY = newY;
20922141
status.dx = dx;
20932142
status.dy = dy;
20942143

@@ -2697,34 +2746,62 @@
26972746
}
26982747

26992748
var endEvent,
2700-
inertiaOptions = target && target.options.inertia,
2749+
options = target && target.options,
2750+
inertiaOptions = options && options.inertia,
27012751
prop;
27022752

27032753
if (dragging || resizing || gesturing) {
27042754

27052755
if (inertiaStatus.active) { return; }
27062756

2707-
var deltaSource =target.options.deltaSource,
2708-
pointerSpeed = pointerDelta[deltaSource + 'Speed'];
2757+
var deltaSource = options.deltaSource,
2758+
pointerSpeed = pointerDelta[deltaSource + 'Speed'],
2759+
now = new Date().getTime(),
2760+
inertiaPossible = false,
2761+
inertia = false,
2762+
smoothEnd = false,
2763+
dx = 0,
2764+
dy = 0,
2765+
startEvent;
27092766

27102767
// check if inertia should be started
2711-
if (target.options.inertiaEnabled
2712-
&& prepared !== 'gesture'
2713-
&& indexOf(inertiaOptions.actions, prepared) !== -1
2714-
&& event !== inertiaStatus.startEvent
2715-
&& (new Date().getTime() - curCoords.timeStamp) < 50
2716-
&& pointerSpeed > inertiaOptions.minSpeed
2717-
&& pointerSpeed > inertiaOptions.endSpeed) {
2768+
inertiaPossible = (options.inertiaEnabled
2769+
&& prepared !== 'gesture'
2770+
&& indexOf(inertiaOptions.actions, prepared) !== -1
2771+
&& event !== inertiaStatus.startEvent);
27182772

2773+
inertia = (inertiaPossible
2774+
&& (now - curCoords.timeStamp) < 50
2775+
&& pointerSpeed > inertiaOptions.minSpeed
2776+
&& pointerSpeed > inertiaOptions.endSpeed);
27192777

2720-
var lambda = inertiaOptions.resistance,
2721-
inertiaDur = -Math.log(inertiaOptions.endSpeed / pointerSpeed) / lambda,
2722-
startEvent;
2778+
if (inertiaPossible && !inertia
2779+
&& ((options.snapEnabled && options.snap.endOnly
2780+
&& indexOf(options.snap.actions, prepared) !== -1)
2781+
|| (options.restrictEnabled && options.restrict.endOnly))) {
27232782

2724-
inertiaStatus.active = true;
2725-
inertiaStatus.target = target;
2726-
inertiaStatus.targetElement = target._element;
2783+
var snapRestrict = {};
2784+
2785+
snapRestrict.snap = snapRestrict.restrict = snapRestrict;
27272786

2787+
setSnapping(event, snapRestrict);
2788+
if (snapRestrict.locked) {
2789+
dx += snapRestrict.dx;
2790+
dy += snapRestrict.dy;
2791+
}
2792+
2793+
setRestriction(event, snapRestrict);
2794+
if (snapRestrict.restricted) {
2795+
dx += snapRestrict.dx;
2796+
dy += snapRestrict.dy;
2797+
}
2798+
2799+
if ((snapRestrict.locked || snapRestrict.restricted) && (dx || dy)) {
2800+
smoothEnd = true;
2801+
}
2802+
}
2803+
2804+
if (inertia || smoothEnd) {
27282805
if (events.useAttachEvent) {
27292806
// make a copy of the pointerdown event because IE8
27302807
// http://stackoverflow.com/a/3533725/2280888
@@ -2739,70 +2816,78 @@
27392816
inertiaStatus.startEvent = startEvent = new InteractEvent(event, prepared, 'inertiastart');
27402817
target.fire(inertiaStatus.startEvent);
27412818

2742-
inertiaStatus.vx0 = pointerDelta[deltaSource + 'VX'];
2743-
inertiaStatus.vy0 = pointerDelta[deltaSource + 'VY'];
2744-
inertiaStatus.v0 = pointerSpeed;
2745-
inertiaStatus.x0 = prevEvent.pageX;
2746-
inertiaStatus.y0 = prevEvent.pageY;
2747-
inertiaStatus.t0 = inertiaStatus.startEvent.timeStamp / 1000;
2748-
inertiaStatus.sx = inertiaStatus.sy = 0;
2819+
inertiaStatus.target = target;
2820+
inertiaStatus.targetElement = target._element;
2821+
inertiaStatus.t0 = now;
27492822

2750-
inertiaStatus.modifiedXe = inertiaStatus.xe = (inertiaStatus.vx0 - inertiaDur) / lambda;
2751-
inertiaStatus.modifiedYe = inertiaStatus.ye = (inertiaStatus.vy0 - inertiaDur) / lambda;
2752-
inertiaStatus.te = inertiaDur;
2823+
if (inertia) {
2824+
inertiaStatus.vx0 = pointerDelta[deltaSource + 'VX'];
2825+
inertiaStatus.vy0 = pointerDelta[deltaSource + 'VY'];
2826+
inertiaStatus.v0 = pointerSpeed;
27532827

2754-
inertiaStatus.lambda_v0 = lambda / inertiaStatus.v0;
2755-
inertiaStatus.one_ve_v0 = 1 - inertiaOptions.endSpeed / inertiaStatus.v0;
2828+
calcInertia(inertiaStatus);
27562829

2757-
var startX = startEvent.pageX,
2758-
startY = startEvent.pageY,
2759-
statusObject;
2830+
var page = getPageXY(event),
2831+
origin = getOriginXY(target, target._element),
2832+
statusObject;
27602833

2761-
if (startEvent.snap && startEvent.snap.locked) {
2762-
startX -= startEvent.snap.dx;
2763-
startY -= startEvent.snap.dy;
2764-
}
2834+
page.x = page.x + (inertia? inertiaStatus.xe: 0) - origin.x;
2835+
page.y = page.y + (inertia? inertiaStatus.ye: 0) - origin.y;
27652836

2766-
if (startEvent.restrict) {
2767-
startX -= startEvent.restrict.dx;
2768-
startY -= startEvent.restrict.dy;
2769-
}
2837+
statusObject = {
2838+
useStatusXY: true,
2839+
x: page.x,
2840+
y: page.y,
2841+
dx: 0,
2842+
dy: 0,
2843+
snap: null
2844+
};
27702845

2771-
statusObject = {
2772-
useStatusXY: true,
2773-
x: startX + inertiaStatus.xe,
2774-
y: startY + inertiaStatus.ye,
2775-
dx: 0,
2776-
dy: 0,
2777-
snap: null
2778-
};
2846+
statusObject.snap = statusObject;
2847+
2848+
dx = dy = 0;
27792849

2780-
statusObject.snap = statusObject;
2850+
if (options.snapEnabled && options.snap.endOnly
2851+
&& indexOf(options.snap.actions, prepared) !== -1) {
27812852

2782-
if (target.options.snapEnabled && target.options.snap.endOnly) {
2783-
var snap = setSnapping(event, statusObject);
2853+
var snap = setSnapping(event, statusObject);
27842854

2785-
if (snap.locked) {
2786-
inertiaStatus.modifiedXe += snap.dx;
2787-
inertiaStatus.modifiedYe += snap.dy;
2855+
if (snap.locked) {
2856+
dx += snap.dx;
2857+
dy += snap.dy;
2858+
}
2859+
}
2860+
2861+
if (options.restrictEnabled && options.restrict.endOnly) {
2862+
var restrict = setRestriction(event, statusObject);
2863+
2864+
if (restrict.restricted) {
2865+
dx += restrict.dx;
2866+
dy += restrict.dy;
2867+
}
27882868
}
2789-
}
27902869

2791-
if (target.options.restrictEnabled && target.options.restrict.endOnly) {
2792-
var restrict = setRestriction(event, statusObject);
2870+
inertiaStatus.modifiedXe += dx;
2871+
inertiaStatus.modifiedYe += dy;
27932872

2794-
inertiaStatus.modifiedXe += restrict.dx;
2795-
inertiaStatus.modifiedYe += restrict.dy;
2873+
inertiaStatus.i = reqFrame(inertiaFrame);
27962874
}
2875+
else {
2876+
inertiaStatus.smoothEnd = true;
2877+
inertiaStatus.xe = dx;
2878+
inertiaStatus.ye = dy;
27972879

2798-
cancelFrame(inertiaStatus.i);
2799-
inertiaStatus.i = reqFrame(inertiaFrame);
2880+
inertiaStatus.sx = inertiaStatus.sy = 0;
28002881

2882+
inertiaStatus.i = reqFrame(smoothEndFrame);
2883+
}
2884+
2885+
inertiaStatus.active = true;
28012886
return;
28022887
}
28032888

2804-
if ((target.options.snapEnabled && target.options.snap.endOnly)
2805-
|| (target.options.restrictEnabled && target.options.restrict.endOnly)) {
2889+
if ((options.snapEnabled && options.snap.endOnly)
2890+
|| (options.restrictEnabled && options.restrict.endOnly)) {
28062891
// fire a move event at the snapped coordinates
28072892
pointerMove(event, true);
28082893
}
@@ -3604,7 +3689,8 @@
36043689
minSpeed : defaults.minSpeed,
36053690
endSpeed : defaults.endSpeed,
36063691
actions : defaults.actions,
3607-
zeroResumeDelta: defaults.zeroResumeDelta
3692+
zeroResumeDelta: defaults.zeroResumeDelta,
3693+
smoothEndDuration: defaults.smoothEndDuration
36083694
};
36093695
}
36103696

@@ -3613,6 +3699,7 @@
36133699
inertia.endSpeed = this.validateSetting('inertia', 'endSpeed' , options.endSpeed);
36143700
inertia.actions = this.validateSetting('inertia', 'actions' , options.actions);
36153701
inertia.zeroResumeDelta = this.validateSetting('inertia', 'zeroResumeDelta', options.zeroResumeDelta);
3702+
inertia.smoothEndDuration = this.validateSetting('inertia', 'smoothEndDuration', options.smoothEndDuration);
36163703

36173704
this.options.inertiaEnabled = true;
36183705
this.options.inertia = inertia;
@@ -4803,8 +4890,8 @@
48034890
paths : snap.paths,
48044891
range : snap.range,
48054892
locked : snapStatus.locked,
4806-
x : snapStatus.x,
4807-
y : snapStatus.y,
4893+
x : snapStatus.snappedX,
4894+
y : snapStatus.snappedY,
48084895
realX : snapStatus.realX,
48094896
realY : snapStatus.realY,
48104897
dx : snapStatus.dx,
@@ -4834,6 +4921,7 @@
48344921
if (typeof options.resistance === 'number') { inertia.resistance = options.resistance;}
48354922
if (typeof options.minSpeed === 'number') { inertia.minSpeed = options.minSpeed ;}
48364923
if (typeof options.endSpeed === 'number') { inertia.endSpeed = options.endSpeed ;}
4924+
if (typeof options.smoothEndDuration === 'number') { inertia.smoothEndDuration = options.smoothEndDuration ;}
48374925

48384926
if (typeof options.zeroResumeDelta === 'boolean') { inertia.zeroResumeDelta = options.zeroResumeDelta ;}
48394927

0 commit comments

Comments
 (0)