|
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 | + restrictOffset = { left: 0, right: 0, top: 0, bottom: 0 }, |
| 76 | + snapOffset = { x: 0, y: 0}, |
| 77 | + |
74 | 78 | tmpXY = {}, // reduce object creation in getXY()
|
75 | 79 |
|
76 | 80 | inertiaStatus = {
|
|
168 | 172 | anchors : [],
|
169 | 173 | paths : [],
|
170 | 174 |
|
| 175 | + elementOrigin: null, |
| 176 | + |
171 | 177 | arrayTypes : /^anchors$|^paths$|^actions$/,
|
172 |
| - objectTypes : /^grid$|^gridOffset$/, |
| 178 | + objectTypes : /^grid$|^gridOffset$|^elementOrigin$/, |
173 | 179 | stringTypes : /^mode$/,
|
174 | 180 | numberTypes : /^range$/,
|
175 | 181 | boolTypes : /^endOnly$/
|
|
182 | 188 | gesture: null,
|
183 | 189 | endOnly: false
|
184 | 190 | },
|
185 |
| - restrictEnabled: true, |
| 191 | + restrictEnabled: false, |
186 | 192 |
|
187 | 193 | autoScroll: {
|
188 | 194 | container : window, // the item that is scrolled (Window or HTMLElement)
|
|
1094 | 1100 | return (axis === 'xy' || thisAxis === 'xy' || thisAxis === axis);
|
1095 | 1101 | }
|
1096 | 1102 |
|
| 1103 | + function checkSnap (interactable, action) { |
| 1104 | + var options = interactable.options; |
| 1105 | + |
| 1106 | + action = action || prepared; |
| 1107 | + |
| 1108 | + if (/^resize/.test(action)) { |
| 1109 | + action = 'resize'; |
| 1110 | + } |
| 1111 | + |
| 1112 | + return (options.snapEnabled && indexOf(options.snap.actions, action) !== -1); |
| 1113 | + } |
| 1114 | + |
| 1115 | + function checkRestrict (interactable, action) { |
| 1116 | + var options = interactable.options; |
| 1117 | + |
| 1118 | + action = action || prepared; |
| 1119 | + |
| 1120 | + if (/^resize/.test(action)) { |
| 1121 | + action = 'resize'; |
| 1122 | + } |
| 1123 | + |
| 1124 | + return options.restrictEnabled && options.restrict[action]; |
| 1125 | + } |
| 1126 | + |
1097 | 1127 | function collectDrops (event, element) {
|
1098 | 1128 | var drops = [],
|
1099 | 1129 | elements = [],
|
|
1387 | 1417 | client.x -= origin.x;
|
1388 | 1418 | client.y -= origin.y;
|
1389 | 1419 |
|
1390 |
| - if (options.snapEnabled && indexOf(options.snap.actions, action) !== -1) { |
| 1420 | + if (checkSnap(target) && !(phase === 'start' && options.snap.elementOrigin)) { |
1391 | 1421 |
|
1392 | 1422 | this.snap = {
|
1393 | 1423 | range : snapStatus.range,
|
|
1409 | 1439 | }
|
1410 | 1440 | }
|
1411 | 1441 |
|
1412 |
| - if (target.options.restrict[action] && restrictStatus.restricted) { |
| 1442 | + if (checkRestrict(target) && !(phase === 'start' && options.restrict.elementRect) && restrictStatus.restricted) { |
1413 | 1443 | page.x += restrictStatus.dx;
|
1414 | 1444 | page.y += restrictStatus.dy;
|
1415 | 1445 | client.x += restrictStatus.dx;
|
|
2088 | 2118 |
|
2089 | 2119 | range = typeof anchor.range === 'number'? anchor.range: snap.range;
|
2090 | 2120 |
|
2091 |
| - dx = anchor.x - page.x; |
2092 |
| - dy = anchor.y - page.y; |
| 2121 | + dx = anchor.x - page.x + snapOffset.x; |
| 2122 | + dy = anchor.y - page.y + snapOffset.y; |
2093 | 2123 | distance = hypot(dx, dy);
|
2094 | 2124 |
|
2095 | 2125 | inRange = distance < range;
|
|
2134 | 2164 | status.dy = closest.dy;
|
2135 | 2165 | }
|
2136 | 2166 | else if (snap.mode === 'grid') {
|
2137 |
| - var gridx = Math.round((page.x - snap.gridOffset.x) / snap.grid.x), |
2138 |
| - gridy = Math.round((page.y - snap.gridOffset.y) / snap.grid.y), |
| 2167 | + var gridx = Math.round((page.x - snap.gridOffset.x - snapOffset.x) / snap.grid.x), |
| 2168 | + gridy = Math.round((page.y - snap.gridOffset.y - snapOffset.y) / snap.grid.y), |
2139 | 2169 |
|
2140 |
| - newX = gridx * snap.grid.x + snap.gridOffset.x, |
2141 |
| - newY = gridy * snap.grid.y + snap.gridOffset.y; |
| 2170 | + newX = gridx * snap.grid.x + snap.gridOffset.x + snapOffset.x, |
| 2171 | + newY = gridy * snap.grid.y + snap.gridOffset.y + snapOffset.y; |
2142 | 2172 |
|
2143 | 2173 | dx = newX - page.x;
|
2144 | 2174 | dy = newY - page.y;
|
|
2163 | 2193 | }
|
2164 | 2194 |
|
2165 | 2195 | function setRestriction (event, status) {
|
2166 |
| - var action = interact.currentAction() || prepared, |
2167 |
| - restriction = target && target.options.restrict[action], |
| 2196 | + var restrict = target && target.options.restrict, |
| 2197 | + restriction = restrict && restrict[prepared], |
2168 | 2198 | page;
|
2169 | 2199 |
|
| 2200 | + if (!restriction) { |
| 2201 | + return status; |
| 2202 | + } |
| 2203 | + |
2170 | 2204 | status = status || restrictStatus;
|
2171 | 2205 |
|
2172 | 2206 | page = status.useStatusXY
|
|
2185 | 2219 | status.dy = 0;
|
2186 | 2220 | status.restricted = false;
|
2187 | 2221 |
|
2188 |
| - if (!action || !restriction) { |
2189 |
| - return status; |
2190 |
| - } |
2191 |
| - |
2192 | 2222 | var rect;
|
2193 | 2223 |
|
2194 | 2224 | if (restriction === 'parent') {
|
|
2221 | 2251 | }
|
2222 | 2252 | }
|
2223 | 2253 |
|
2224 |
| - status.dx = Math.max(Math.min(rect.right , page.x), rect.left) - page.x; |
2225 |
| - status.dy = Math.max(Math.min(rect.bottom, page.y), rect.top ) - page.y; |
| 2254 | + status.dx = Math.max(Math.min(rect.right - restrictOffset.right , page.x), rect.left + restrictOffset.left) - page.x; |
| 2255 | + status.dy = Math.max(Math.min(rect.bottom - restrictOffset.bottom, page.y), rect.top + restrictOffset.top ) - page.y; |
2226 | 2256 | status.restricted = true;
|
2227 | 2257 |
|
2228 | 2258 | return status;
|
|
2338 | 2368 | }
|
2339 | 2369 |
|
2340 | 2370 | if (prepared && target) {
|
2341 |
| - var shouldRestrict = target.options.restrictEnabled && (!target.options.restrict.endOnly || preEnd), |
| 2371 | + var shouldRestrict = checkRestrict(target) && (!target.options.restrict.endOnly || preEnd), |
2342 | 2372 | starting = !(dragging || resizing || gesturing),
|
2343 | 2373 | snapEvent = starting? downEvent: event;
|
2344 | 2374 |
|
2345 | 2375 | if (starting) {
|
2346 | 2376 | prevEvent = downEvent;
|
| 2377 | + |
| 2378 | + var rect = target.getRect(), |
| 2379 | + snap = target.options.snap, |
| 2380 | + restrict = target.options.restrict; |
| 2381 | + |
| 2382 | + if (rect) { |
| 2383 | + startOffset.left = startCoords.pageX - rect.left; |
| 2384 | + startOffset.top = startCoords.pageY - rect.top; |
| 2385 | + |
| 2386 | + startOffset.right = rect.right - startCoords.pageX; |
| 2387 | + startOffset.bottom = rect.bottom - startCoords.pageY; |
| 2388 | + } |
| 2389 | + else { |
| 2390 | + startOffset.left = startOffset.top = startOffset.right = startOffset.bottom = 0; |
| 2391 | + } |
| 2392 | + |
| 2393 | + if (rect && snap.elementOrigin) { |
| 2394 | + snapOffset.x = startOffset.left + (rect.width * snap.elementOrigin.x); |
| 2395 | + snapOffset.y = startOffset.top + (rect.height * snap.elementOrigin.y); |
| 2396 | + } |
| 2397 | + else { |
| 2398 | + snapOffset.x = snapOffset.y = 0; |
| 2399 | + } |
| 2400 | + |
| 2401 | + if (rect && restrict.elementRect) { |
| 2402 | + restrictOffset.left = startOffset.left - (rect.width * restrict.elementRect.left); |
| 2403 | + restrictOffset.top = startOffset.top - (rect.height * restrict.elementRect.top); |
| 2404 | + |
| 2405 | + restrictOffset.right = startOffset.right - (rect.width * (1 - restrict.elementRect.right)); |
| 2406 | + restrictOffset.bottom = startOffset.bottom - (rect.height * (1 - restrict.elementRect.bottom)); |
| 2407 | + } |
| 2408 | + else { |
| 2409 | + restrictOffset.left = restrictOffset.top = restrictOffset.right = restrictOffset.bottom = 0; |
| 2410 | + } |
2347 | 2411 | }
|
2348 | 2412 |
|
2349 | 2413 | if (!shouldRestrict) {
|
2350 | 2414 | restrictStatus.restricted = false;
|
2351 | 2415 | }
|
2352 | 2416 |
|
2353 | 2417 | // check for snap
|
2354 |
| - if (target.options.snapEnabled |
2355 |
| - && indexOf(target.options.snap.actions, prepared) !== -1 |
2356 |
| - && (!target.options.snap.endOnly || preEnd)) { |
| 2418 | + if (checkSnap(target) && (!target.options.snap.endOnly || preEnd)) { |
2357 | 2419 |
|
2358 | 2420 | setSnapping(snapEvent);
|
2359 | 2421 |
|
|
2871 | 2933 | }
|
2872 | 2934 | }
|
2873 | 2935 |
|
2874 |
| - if (options.restrictEnabled && options.restrict.endOnly) { |
| 2936 | + if (checkRestrict(target) && target.options.restrict.endOnly) { |
2875 | 2937 | var restrict = setRestriction(event, statusObject);
|
2876 | 2938 |
|
2877 | 2939 | if (restrict.restricted) {
|
|
2899 | 2961 | return;
|
2900 | 2962 | }
|
2901 | 2963 |
|
2902 |
| - if ((options.snapEnabled && options.snap.endOnly) |
2903 |
| - || (options.restrictEnabled && options.restrict.endOnly)) { |
| 2964 | + if ((checkSnap(target) && target.options.snap.endOnly) |
| 2965 | + || (checkRestrict(target) && target.options.restrict.endOnly)) { |
2904 | 2966 | // fire a move event at the snapped coordinates
|
2905 | 2967 | pointerMove(event, true);
|
2906 | 2968 | }
|
|
3629 | 3691 | snap.grid = this.validateSetting('snap', 'grid' , options.grid);
|
3630 | 3692 | snap.gridOffset = this.validateSetting('snap', 'gridOffset', options.gridOffset);
|
3631 | 3693 | snap.anchors = this.validateSetting('snap', 'anchors' , options.anchors);
|
| 3694 | + snap.elementOrigin = this.validateSetting('snap', 'elementOrigin' , options.elementOrigin); |
3632 | 3695 |
|
3633 | 3696 | this.options.snapEnabled = true;
|
3634 | 3697 | this.options.snap = snap;
|
|
3977 | 4040 | return this.options.restrict;
|
3978 | 4041 | }
|
3979 | 4042 |
|
3980 |
| - if (newValue instanceof Object) { |
| 4043 | + if (typeof newValue === 'boolean') { |
| 4044 | + defaultOptions.restrictEnabled = newValue; |
| 4045 | + } |
| 4046 | + else if (newValue instanceof Object) { |
3981 | 4047 | var newRestrictions = {};
|
3982 | 4048 |
|
3983 | 4049 | if (newValue.drag instanceof Object || /^parent$|^self$/.test(newValue.drag)) {
|
|
3994 | 4060 | newRestrictions.endOnly = newValue.endOnly;
|
3995 | 4061 | }
|
3996 | 4062 |
|
| 4063 | + if (newValue.elementRect instanceof Object) { |
| 4064 | + newRestrictions.elementRect = newValue.elementRect; |
| 4065 | + } |
| 4066 | + |
3997 | 4067 | this.options.restrictEnabled = true;
|
3998 | 4068 | this.options.restrict = newRestrictions;
|
3999 | 4069 | }
|
4000 |
| - |
4001 | 4070 | else if (newValue === null) {
|
4002 | 4071 | delete this.options.restrict;
|
4003 | 4072 | delete this.options.restrictEnabled;
|
|
4886 | 4955 | if (options.anchors instanceof Array ) { snap.anchors = options.anchors; }
|
4887 | 4956 | if (options.grid instanceof Object) { snap.grid = options.grid; }
|
4888 | 4957 | if (options.gridOffset instanceof Object) { snap.gridOffset = options.gridOffset; }
|
| 4958 | + if (options.elementOrigin instanceof Object) { snap.elementOrigin = options.elementOrigin; } |
4889 | 4959 |
|
4890 | 4960 | return interact;
|
4891 | 4961 | }
|
|
5093 | 5163 | return defaultOptions.restrict;
|
5094 | 5164 | }
|
5095 | 5165 |
|
5096 |
| - if (newValue instanceof Object) { |
| 5166 | + if (typeof newValue === 'boolean') { |
| 5167 | + defaultOptions.restrictEnabled = newValue; |
| 5168 | + } |
| 5169 | + else if (newValue instanceof Object) { |
5097 | 5170 | if (newValue.drag instanceof Object || /^parent$|^self$/.test(newValue.drag)) {
|
5098 | 5171 | defaults.drag = newValue.drag;
|
5099 | 5172 | }
|
|
5107 | 5180 | if (typeof newValue.endOnly === 'boolean') {
|
5108 | 5181 | defaults.endOnly = newValue.endOnly;
|
5109 | 5182 | }
|
5110 |
| - } |
5111 | 5183 |
|
| 5184 | + if (newValue.elementRect instanceof Object) { |
| 5185 | + defaults.elementRect = newValue.elementRect; |
| 5186 | + } |
| 5187 | + |
| 5188 | + defaultOptions.restrictEnabled = true; |
| 5189 | + } |
5112 | 5190 | else if (newValue === null) {
|
5113 | 5191 | defaults.drag = defaults.resize = defaults.gesture = null;
|
5114 | 5192 | defaults.endOnly = false;
|
|
0 commit comments