|
75 | 75 |
|
76 | 76 | inertiaStatus = {
|
77 | 77 | active : false,
|
| 78 | + smoothEnd : false, |
78 | 79 | target : null,
|
79 | 80 | targetElement: null,
|
80 | 81 |
|
81 | 82 | startEvent: null,
|
82 | 83 | pointerUp : {},
|
83 | 84 |
|
84 |
| - xe : 0, |
85 |
| - ye : 0, |
| 85 | + xe: 0, |
| 86 | + ye: 0, |
| 87 | + sx: 0, |
| 88 | + sy: 0, |
86 | 89 | duration: 0,
|
87 | 90 |
|
88 |
| - t0 : 0, |
| 91 | + t0: 0, |
89 | 92 | vx0: 0,
|
90 | 93 | vys: 0,
|
91 | 94 |
|
|
196 | 199 | endSpeed : 10, // the speed at which inertia is slow enough to stop
|
197 | 200 | actions : ['drag', 'resize'],
|
198 | 201 | zeroResumeDelta: false,
|
| 202 | + smoothEndDuration: 300, |
199 | 203 |
|
200 |
| - numberTypes: /^resistance$|^minSpeed$|^endSpeed$/, |
| 204 | + numberTypes: /^resistance$|^minSpeed$|^endSpeed$|^smoothEndDuration$/, |
201 | 205 | arrayTypes : /^actions$/,
|
202 | 206 | boolTypes: /^zeroResumeDelta$/
|
203 | 207 | },
|
|
911 | 915 | return origin;
|
912 | 916 | }
|
913 | 917 |
|
| 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 | + |
914 | 936 | function inertiaFrame () {
|
915 | 937 | var options = inertiaStatus.target.options.inertia,
|
916 | 938 | lambda = options.resistance,
|
|
950 | 972 | }
|
951 | 973 | }
|
952 | 974 |
|
| 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 | + |
953 | 996 | function _getQBezierValue(t, p1, p2, p3) {
|
954 | 997 | var iT = 1 - t;
|
955 | 998 | return iT * iT * p1 + 2 * iT * t * p2 + t * t * p3;
|
|
962 | 1005 | };
|
963 | 1006 | }
|
964 | 1007 |
|
| 1008 | + // http://gizma.com/easing/ |
| 1009 | + function easeOutQuad (t, b, c, d) { |
| 1010 | + t /= d; |
| 1011 | + return -c * t*(t-2) + b; |
| 1012 | + } |
| 1013 | + |
965 | 1014 | function nodeContains (parent, child) {
|
966 | 1015 | while ((child = child.parentNode)) {
|
967 | 1016 |
|
|
1331 | 1380 | this.snap = {
|
1332 | 1381 | range : snapStatus.range,
|
1333 | 1382 | locked : snapStatus.locked,
|
1334 |
| - x : snapStatus.x, |
1335 |
| - y : snapStatus.y, |
| 1383 | + x : snapStatus.snappedX, |
| 1384 | + y : snapStatus.snappedY, |
1336 | 1385 | realX : snapStatus.realX,
|
1337 | 1386 | realY : snapStatus.realY,
|
1338 | 1387 | dx : snapStatus.dx,
|
|
1928 | 1977 |
|
1929 | 1978 | prepared = action;
|
1930 | 1979 |
|
1931 |
| - snapStatus.x = null; |
1932 |
| - snapStatus.y = null; |
| 1980 | + snapStatus.snappedX = null; |
| 1981 | + snapStatus.snappedY = null; |
1933 | 1982 |
|
1934 | 1983 | downTime = new Date().getTime();
|
1935 | 1984 | downEvent = event;
|
|
2067 | 2116 | inRange = closest.inRange;
|
2068 | 2117 | snapChanged = (closest.anchor.x !== status.x || closest.anchor.y !== status.y);
|
2069 | 2118 |
|
2070 |
| - status.x = closest.anchor.x; |
2071 |
| - status.y = closest.anchor.y; |
| 2119 | + status.snappedX = closest.anchor.x; |
| 2120 | + status.snappedY = closest.anchor.y; |
2072 | 2121 | status.dx = closest.dx;
|
2073 | 2122 | status.dy = closest.dy;
|
2074 | 2123 | }
|
|
2087 | 2136 | inRange = distance < snap.range;
|
2088 | 2137 | snapChanged = (newX !== status.x || newY !== status.y);
|
2089 | 2138 |
|
2090 |
| - status.x = newX; |
2091 |
| - status.y = newY; |
| 2139 | + status.snappedX = newX; |
| 2140 | + status.snappedY = newY; |
2092 | 2141 | status.dx = dx;
|
2093 | 2142 | status.dy = dy;
|
2094 | 2143 |
|
|
2697 | 2746 | }
|
2698 | 2747 |
|
2699 | 2748 | var endEvent,
|
2700 |
| - inertiaOptions = target && target.options.inertia, |
| 2749 | + options = target && target.options, |
| 2750 | + inertiaOptions = options && options.inertia, |
2701 | 2751 | prop;
|
2702 | 2752 |
|
2703 | 2753 | if (dragging || resizing || gesturing) {
|
2704 | 2754 |
|
2705 | 2755 | if (inertiaStatus.active) { return; }
|
2706 | 2756 |
|
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; |
2709 | 2766 |
|
2710 | 2767 | // 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); |
2718 | 2772 |
|
| 2773 | + inertia = (inertiaPossible |
| 2774 | + && (now - curCoords.timeStamp) < 50 |
| 2775 | + && pointerSpeed > inertiaOptions.minSpeed |
| 2776 | + && pointerSpeed > inertiaOptions.endSpeed); |
2719 | 2777 |
|
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))) { |
2723 | 2782 |
|
2724 |
| - inertiaStatus.active = true; |
2725 |
| - inertiaStatus.target = target; |
2726 |
| - inertiaStatus.targetElement = target._element; |
| 2783 | + var snapRestrict = {}; |
| 2784 | + |
| 2785 | + snapRestrict.snap = snapRestrict.restrict = snapRestrict; |
2727 | 2786 |
|
| 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) { |
2728 | 2805 | if (events.useAttachEvent) {
|
2729 | 2806 | // make a copy of the pointerdown event because IE8
|
2730 | 2807 | // http://stackoverflow.com/a/3533725/2280888
|
|
2739 | 2816 | inertiaStatus.startEvent = startEvent = new InteractEvent(event, prepared, 'inertiastart');
|
2740 | 2817 | target.fire(inertiaStatus.startEvent);
|
2741 | 2818 |
|
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; |
2749 | 2822 |
|
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; |
2753 | 2827 |
|
2754 |
| - inertiaStatus.lambda_v0 = lambda / inertiaStatus.v0; |
2755 |
| - inertiaStatus.one_ve_v0 = 1 - inertiaOptions.endSpeed / inertiaStatus.v0; |
| 2828 | + calcInertia(inertiaStatus); |
2756 | 2829 |
|
2757 |
| - var startX = startEvent.pageX, |
2758 |
| - startY = startEvent.pageY, |
2759 |
| - statusObject; |
| 2830 | + var page = getPageXY(event), |
| 2831 | + origin = getOriginXY(target, target._element), |
| 2832 | + statusObject; |
2760 | 2833 |
|
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; |
2765 | 2836 |
|
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 | + }; |
2770 | 2845 |
|
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; |
2779 | 2849 |
|
2780 |
| - statusObject.snap = statusObject; |
| 2850 | + if (options.snapEnabled && options.snap.endOnly |
| 2851 | + && indexOf(options.snap.actions, prepared) !== -1) { |
2781 | 2852 |
|
2782 |
| - if (target.options.snapEnabled && target.options.snap.endOnly) { |
2783 |
| - var snap = setSnapping(event, statusObject); |
| 2853 | + var snap = setSnapping(event, statusObject); |
2784 | 2854 |
|
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 | + } |
2788 | 2868 | }
|
2789 |
| - } |
2790 | 2869 |
|
2791 |
| - if (target.options.restrictEnabled && target.options.restrict.endOnly) { |
2792 |
| - var restrict = setRestriction(event, statusObject); |
| 2870 | + inertiaStatus.modifiedXe += dx; |
| 2871 | + inertiaStatus.modifiedYe += dy; |
2793 | 2872 |
|
2794 |
| - inertiaStatus.modifiedXe += restrict.dx; |
2795 |
| - inertiaStatus.modifiedYe += restrict.dy; |
| 2873 | + inertiaStatus.i = reqFrame(inertiaFrame); |
2796 | 2874 | }
|
| 2875 | + else { |
| 2876 | + inertiaStatus.smoothEnd = true; |
| 2877 | + inertiaStatus.xe = dx; |
| 2878 | + inertiaStatus.ye = dy; |
2797 | 2879 |
|
2798 |
| - cancelFrame(inertiaStatus.i); |
2799 |
| - inertiaStatus.i = reqFrame(inertiaFrame); |
| 2880 | + inertiaStatus.sx = inertiaStatus.sy = 0; |
2800 | 2881 |
|
| 2882 | + inertiaStatus.i = reqFrame(smoothEndFrame); |
| 2883 | + } |
| 2884 | + |
| 2885 | + inertiaStatus.active = true; |
2801 | 2886 | return;
|
2802 | 2887 | }
|
2803 | 2888 |
|
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)) { |
2806 | 2891 | // fire a move event at the snapped coordinates
|
2807 | 2892 | pointerMove(event, true);
|
2808 | 2893 | }
|
|
3604 | 3689 | minSpeed : defaults.minSpeed,
|
3605 | 3690 | endSpeed : defaults.endSpeed,
|
3606 | 3691 | actions : defaults.actions,
|
3607 |
| - zeroResumeDelta: defaults.zeroResumeDelta |
| 3692 | + zeroResumeDelta: defaults.zeroResumeDelta, |
| 3693 | + smoothEndDuration: defaults.smoothEndDuration |
3608 | 3694 | };
|
3609 | 3695 | }
|
3610 | 3696 |
|
|
3613 | 3699 | inertia.endSpeed = this.validateSetting('inertia', 'endSpeed' , options.endSpeed);
|
3614 | 3700 | inertia.actions = this.validateSetting('inertia', 'actions' , options.actions);
|
3615 | 3701 | inertia.zeroResumeDelta = this.validateSetting('inertia', 'zeroResumeDelta', options.zeroResumeDelta);
|
| 3702 | + inertia.smoothEndDuration = this.validateSetting('inertia', 'smoothEndDuration', options.smoothEndDuration); |
3616 | 3703 |
|
3617 | 3704 | this.options.inertiaEnabled = true;
|
3618 | 3705 | this.options.inertia = inertia;
|
|
4803 | 4890 | paths : snap.paths,
|
4804 | 4891 | range : snap.range,
|
4805 | 4892 | locked : snapStatus.locked,
|
4806 |
| - x : snapStatus.x, |
4807 |
| - y : snapStatus.y, |
| 4893 | + x : snapStatus.snappedX, |
| 4894 | + y : snapStatus.snappedY, |
4808 | 4895 | realX : snapStatus.realX,
|
4809 | 4896 | realY : snapStatus.realY,
|
4810 | 4897 | dx : snapStatus.dx,
|
|
4834 | 4921 | if (typeof options.resistance === 'number') { inertia.resistance = options.resistance;}
|
4835 | 4922 | if (typeof options.minSpeed === 'number') { inertia.minSpeed = options.minSpeed ;}
|
4836 | 4923 | if (typeof options.endSpeed === 'number') { inertia.endSpeed = options.endSpeed ;}
|
| 4924 | + if (typeof options.smoothEndDuration === 'number') { inertia.smoothEndDuration = options.smoothEndDuration ;} |
4837 | 4925 |
|
4838 | 4926 | if (typeof options.zeroResumeDelta === 'boolean') { inertia.zeroResumeDelta = options.zeroResumeDelta ;}
|
4839 | 4927 |
|
|
0 commit comments