|
71 | 71 | tapTime = 0, // time of the most recent tap event
|
72 | 72 | prevTap = null,
|
73 | 73 |
|
| 74 | + startOffset = { left: 0, right: 0, top: 0, bottom: 0 }, |
| 75 | + |
74 | 76 | tmpXY = {}, // reduce object creation in getXY()
|
75 | 77 |
|
76 | 78 | inertiaStatus = {
|
|
162 | 164 | anchors : [],
|
163 | 165 | paths : [],
|
164 | 166 |
|
| 167 | + elementOrigin: { x: 0, y: 0 }, |
| 168 | + |
165 | 169 | arrayTypes : /^anchors$|^paths$|^actions$/,
|
166 |
| - objectTypes : /^grid$|^gridOffset$/, |
| 170 | + objectTypes : /^grid$|^gridOffset$|^elementOrigin$/, |
167 | 171 | stringTypes : /^mode$/,
|
168 | 172 | numberTypes : /^range$/,
|
169 | 173 | boolTypes : /^endOnly$/
|
|
1041 | 1045 | return (axis === 'xy' || thisAxis === 'xy' || thisAxis === axis);
|
1042 | 1046 | }
|
1043 | 1047 |
|
| 1048 | + function checkSnap (interactable, action) { |
| 1049 | + var options = interactable.options; |
| 1050 | + |
| 1051 | + action = action || prepared; |
| 1052 | + |
| 1053 | + return (options.snapEnabled && indexOf(options.snap.actions, action) !== -1); |
| 1054 | + } |
| 1055 | + |
| 1056 | + function checkRestrict (interactable, action) { |
| 1057 | + var options = interactable.options; |
| 1058 | + |
| 1059 | + action = action || prepared; |
| 1060 | + |
| 1061 | + return options.restrictEnabled && options.restrict[action]; |
| 1062 | + } |
| 1063 | + |
1044 | 1064 | function collectDrops (event, element) {
|
1045 | 1065 | var drops = [],
|
1046 | 1066 | elements = [],
|
|
1323 | 1343 | client.x -= origin.x;
|
1324 | 1344 | client.y -= origin.y;
|
1325 | 1345 |
|
1326 |
| - if (options.snapEnabled && indexOf(options.snap.actions, action) !== -1) { |
| 1346 | + if (checkSnap(target) && !(phase === 'start' && options.snap.elementOrigin)) { |
1327 | 1347 |
|
1328 | 1348 | this.snap = {
|
1329 | 1349 | range : snapStatus.range,
|
|
1345 | 1365 | }
|
1346 | 1366 | }
|
1347 | 1367 |
|
1348 |
| - if (target.options.restrict[action] && restrictStatus.restricted) { |
| 1368 | + if (checkRestrict(target) && restrictStatus.restricted) { |
1349 | 1369 | page.x += restrictStatus.dx;
|
1350 | 1370 | page.y += restrictStatus.dy;
|
1351 | 1371 | client.x += restrictStatus.dx;
|
|
1980 | 2000 | status.realX = page.x;
|
1981 | 2001 | status.realY = page.y;
|
1982 | 2002 |
|
| 2003 | + var elementOffsetX = 0, |
| 2004 | + elementOffsetY = 0; |
| 2005 | + |
| 2006 | + if (snap.elementOrigin) { |
| 2007 | + var rect = target.getRect(); |
| 2008 | + |
| 2009 | + elementOffsetX = startOffset.left + (rect.width * snap.elementOrigin.x); |
| 2010 | + elementOffsetY = startOffset.top + (rect.height * snap.elementOrigin.y); |
| 2011 | + } |
| 2012 | + |
1983 | 2013 | // change to infinite range when range is negative
|
1984 | 2014 | if (snap.range < 0) { snap.range = Infinity; }
|
1985 | 2015 |
|
|
2017 | 2047 |
|
2018 | 2048 | range = typeof anchor.range === 'number'? anchor.range: snap.range;
|
2019 | 2049 |
|
2020 |
| - dx = anchor.x - page.x; |
2021 |
| - dy = anchor.y - page.y; |
| 2050 | + dx = anchor.x - page.x + elementOffsetX; |
| 2051 | + dy = anchor.y - page.y + elementOffsetY; |
2022 | 2052 | distance = hypot(dx, dy);
|
2023 | 2053 |
|
2024 | 2054 | inRange = distance < range;
|
|
2063 | 2093 | status.dy = closest.dy;
|
2064 | 2094 | }
|
2065 | 2095 | else if (snap.mode === 'grid') {
|
2066 |
| - var gridx = Math.round((page.x - snap.gridOffset.x) / snap.grid.x), |
2067 |
| - gridy = Math.round((page.y - snap.gridOffset.y) / snap.grid.y), |
| 2096 | + var gridx = Math.round((page.x - snap.gridOffset.x - elementOffsetX) / snap.grid.x), |
| 2097 | + gridy = Math.round((page.y - snap.gridOffset.y - elementOffsetY) / snap.grid.y), |
2068 | 2098 |
|
2069 |
| - newX = gridx * snap.grid.x + snap.gridOffset.x, |
2070 |
| - newY = gridy * snap.grid.y + snap.gridOffset.y; |
| 2099 | + newX = gridx * snap.grid.x + snap.gridOffset.x + elementOffsetX, |
| 2100 | + newY = gridy * snap.grid.y + snap.gridOffset.y + elementOffsetY; |
2071 | 2101 |
|
2072 | 2102 | dx = newX - page.x;
|
2073 | 2103 | dy = newY - page.y;
|
|
2092 | 2122 | }
|
2093 | 2123 |
|
2094 | 2124 | function setRestriction (event, status) {
|
2095 |
| - var action = interact.currentAction() || prepared, |
2096 |
| - restriction = target && target.options.restrict[action], |
| 2125 | + var restrict = target && target.options.restrict, |
| 2126 | + restriction = restrict && restrict[prepared], |
2097 | 2127 | page;
|
2098 | 2128 |
|
| 2129 | + if (!restriction) { |
| 2130 | + return status; |
| 2131 | + } |
| 2132 | + |
2099 | 2133 | status = status || restrictStatus;
|
2100 | 2134 |
|
2101 | 2135 | page = status.useStatusXY
|
|
2111 | 2145 | status.dy = 0;
|
2112 | 2146 | status.restricted = false;
|
2113 | 2147 |
|
2114 |
| - if (!action || !restriction) { |
2115 |
| - return status; |
| 2148 | + var elementOffset = {}; |
| 2149 | + |
| 2150 | + if (restrict.elementRect) { |
| 2151 | + var elementRect = target.getRect(); |
| 2152 | + |
| 2153 | + elementOffset.left = startOffset.left - (elementRect.width * restrict.elementRect.left); |
| 2154 | + elementOffset.top = startOffset.top - (elementRect.height * restrict.elementRect.top); |
| 2155 | + |
| 2156 | + elementOffset.right = startOffset.right - (elementRect.width * (1 - restrict.elementRect.right)); |
| 2157 | + elementOffset.bottom = startOffset.bottom - (elementRect.height * (1 - restrict.elementRect.bottom)); |
2116 | 2158 | }
|
2117 | 2159 |
|
2118 | 2160 | var rect;
|
|
2147 | 2189 | }
|
2148 | 2190 | }
|
2149 | 2191 |
|
2150 |
| - status.dx = Math.max(Math.min(rect.right , page.x), rect.left) - page.x; |
2151 |
| - status.dy = Math.max(Math.min(rect.bottom, page.y), rect.top ) - page.y; |
| 2192 | + status.dx = Math.max(Math.min(rect.right - elementOffset.right , page.x), rect.left + elementOffset.left) - page.x; |
| 2193 | + status.dy = Math.max(Math.min(rect.bottom - elementOffset.bottom, page.y), rect.top + elementOffset.top ) - page.y; |
2152 | 2194 | status.restricted = true;
|
2153 | 2195 |
|
2154 | 2196 | return status;
|
|
2264 | 2306 | }
|
2265 | 2307 |
|
2266 | 2308 | if (prepared && target) {
|
2267 |
| - var shouldRestrict = target.options.restrictEnabled && (!target.options.restrict.endOnly || preEnd), |
| 2309 | + var shouldRestrict = checkRestrict(target) && (!target.options.restrict.endOnly || preEnd), |
2268 | 2310 | starting = !(dragging || resizing || gesturing),
|
2269 | 2311 | snapEvent = starting? downEvent: event;
|
2270 | 2312 |
|
2271 | 2313 | if (starting) {
|
2272 | 2314 | prevEvent = downEvent;
|
| 2315 | + |
| 2316 | + var rect = target.getRect() || { left: 0, right: 0, top: 0, bottom: 0 }; |
| 2317 | + |
| 2318 | + startOffset.left = startCoords.pageX - rect.left; |
| 2319 | + startOffset.top = startCoords.pageY - rect.top; |
| 2320 | + |
| 2321 | + startOffset.right = rect.right - startCoords.pageX; |
| 2322 | + startOffset.bottom = rect.bottom - startCoords.pageY; |
2273 | 2323 | }
|
2274 | 2324 |
|
2275 | 2325 | if (!shouldRestrict) {
|
2276 | 2326 | restrictStatus.restricted = false;
|
2277 | 2327 | }
|
2278 | 2328 |
|
2279 | 2329 | // check for snap
|
2280 |
| - if (target.options.snapEnabled |
2281 |
| - && indexOf(target.options.snap.actions, prepared) !== -1 |
2282 |
| - && (!target.options.snap.endOnly || preEnd)) { |
| 2330 | + if (checkSnap(target) && (!target.options.snap.endOnly || preEnd)) { |
2283 | 2331 |
|
2284 | 2332 | setSnapping(snapEvent);
|
2285 | 2333 |
|
|
2775 | 2823 | }
|
2776 | 2824 | }
|
2777 | 2825 |
|
2778 |
| - if (target.options.restrictEnabled && target.options.restrict.endOnly) { |
| 2826 | + if (checkRestrict(target) && target.options.restrict.endOnly) { |
2779 | 2827 | var restrict = setRestriction(event, statusObject);
|
2780 | 2828 |
|
2781 | 2829 | inertiaStatus.modifiedXe += restrict.dx;
|
|
2788 | 2836 | return;
|
2789 | 2837 | }
|
2790 | 2838 |
|
2791 |
| - if ((target.options.snapEnabled && target.options.snap.endOnly) |
2792 |
| - || (target.options.restrictEnabled && target.options.restrict.endOnly)) { |
| 2839 | + if ((checkSnap(target) && target.options.snap.endOnly) |
| 2840 | + || (checkRestrict(target) && target.options.restrict.endOnly)) { |
2793 | 2841 | // fire a move event at the snapped coordinates
|
2794 | 2842 | pointerMove(event, true);
|
2795 | 2843 | }
|
|
3516 | 3564 | snap.grid = this.validateSetting('snap', 'grid' , options.grid);
|
3517 | 3565 | snap.gridOffset = this.validateSetting('snap', 'gridOffset', options.gridOffset);
|
3518 | 3566 | snap.anchors = this.validateSetting('snap', 'anchors' , options.anchors);
|
| 3567 | + snap.elementOrigin = this.validateSetting('snap', 'elementOrigin' , options.elementOrigin); |
3519 | 3568 |
|
3520 | 3569 | this.options.snapEnabled = true;
|
3521 | 3570 | this.options.snap = snap;
|
|
3879 | 3928 | newRestrictions.endOnly = newValue.endOnly;
|
3880 | 3929 | }
|
3881 | 3930 |
|
| 3931 | + if (newValue.elementRect instanceof Object) { |
| 3932 | + newRestrictions.elementRect = newValue.elementRect; |
| 3933 | + } |
| 3934 | + |
3882 | 3935 | this.options.restrictEnabled = true;
|
3883 | 3936 | this.options.restrict = newRestrictions;
|
3884 | 3937 | }
|
|
4769 | 4822 | if (options.anchors instanceof Array ) { snap.anchors = options.anchors; }
|
4770 | 4823 | if (options.grid instanceof Object) { snap.grid = options.grid; }
|
4771 | 4824 | if (options.gridOffset instanceof Object) { snap.gridOffset = options.gridOffset; }
|
| 4825 | + if (options.elementOrigin instanceof Object) { snap.elementOrigin = options.elementOrigin; } |
4772 | 4826 |
|
4773 | 4827 | return interact;
|
4774 | 4828 | }
|
|
4988 | 5042 | if (typeof newValue.endOnly === 'boolean') {
|
4989 | 5043 | defaults.endOnly = newValue.endOnly;
|
4990 | 5044 | }
|
| 5045 | + |
| 5046 | + if (newValue.elementRect instanceof Object) { |
| 5047 | + defaults.elementRect = newValue.elementRect; |
| 5048 | + } |
4991 | 5049 | }
|
4992 | 5050 |
|
4993 | 5051 | else if (newValue === null) {
|
|
0 commit comments