UNPKG

99.3 kBJavaScriptView Raw
1function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
2
3function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
4
5/*!
6 * Draggable 3.10.3
7 * https://greensock.com
8 *
9 * @license Copyright 2008-2022, GreenSock. All rights reserved.
10 * Subject to the terms at https://greensock.com/standard-license or for
11 * Club GreenSock members, the agreement issued with that membership.
12 * @author: Jack Doyle, jack@greensock.com
13 */
14
15/* eslint-disable */
16import { getGlobalMatrix, Matrix2D } from "./utils/matrix.js";
17
18var gsap,
19 _win,
20 _doc,
21 _docElement,
22 _body,
23 _tempDiv,
24 _placeholderDiv,
25 _coreInitted,
26 _checkPrefix,
27 _toArray,
28 _supportsPassive,
29 _isTouchDevice,
30 _touchEventLookup,
31 _dragCount,
32 _isMultiTouching,
33 _isAndroid,
34 InertiaPlugin,
35 _defaultCursor,
36 _supportsPointer,
37 _windowExists = function _windowExists() {
38 return typeof window !== "undefined";
39},
40 _getGSAP = function _getGSAP() {
41 return gsap || _windowExists() && (gsap = window.gsap) && gsap.registerPlugin && gsap;
42},
43 _isFunction = function _isFunction(value) {
44 return typeof value === "function";
45},
46 _isObject = function _isObject(value) {
47 return typeof value === "object";
48},
49 _isUndefined = function _isUndefined(value) {
50 return typeof value === "undefined";
51},
52 _emptyFunc = function _emptyFunc() {
53 return false;
54},
55 _transformProp = "transform",
56 _transformOriginProp = "transformOrigin",
57 _round = function _round(value) {
58 return Math.round(value * 10000) / 10000;
59},
60 _isArray = Array.isArray,
61 _createElement = function _createElement(type, ns) {
62 var e = _doc.createElementNS ? _doc.createElementNS((ns || "http://www.w3.org/1999/xhtml").replace(/^https/, "http"), type) : _doc.createElement(type); //some servers swap in https for http in the namespace which can break things, making "style" inaccessible.
63
64 return e.style ? e : _doc.createElement(type); //some environments won't allow access to the element's style when created with a namespace in which case we default to the standard createElement() to work around the issue. Also note that when GSAP is embedded directly inside an SVG file, createElement() won't allow access to the style object in Firefox (see https://greensock.com/forums/topic/20215-problem-using-tweenmax-in-standalone-self-containing-svg-file-err-cannot-set-property-csstext-of-undefined/).
65},
66 _RAD2DEG = 180 / Math.PI,
67 _bigNum = 1e20,
68 _identityMatrix = new Matrix2D(),
69 _getTime = Date.now || function () {
70 return new Date().getTime();
71},
72 _renderQueue = [],
73 _lookup = {},
74 //when a Draggable is created, the target gets a unique _gsDragID property that allows gets associated with the Draggable instance for quick lookups in Draggable.get(). This avoids circular references that could cause gc problems.
75_lookupCount = 0,
76 _clickableTagExp = /^(?:a|input|textarea|button|select)$/i,
77 _lastDragTime = 0,
78 _temp1 = {},
79 // a simple object we reuse and populate (usually x/y properties) to conserve memory and improve performance.
80_windowProxy = {},
81 //memory/performance optimization - we reuse this object during autoScroll to store window-related bounds/offsets.
82_copy = function _copy(obj, factor) {
83 var copy = {},
84 p;
85
86 for (p in obj) {
87 copy[p] = factor ? obj[p] * factor : obj[p];
88 }
89
90 return copy;
91},
92 _extend = function _extend(obj, defaults) {
93 for (var p in defaults) {
94 if (!(p in obj)) {
95 obj[p] = defaults[p];
96 }
97 }
98
99 return obj;
100},
101 _setTouchActionForAllDescendants = function _setTouchActionForAllDescendants(elements, value) {
102 var i = elements.length,
103 children;
104
105 while (i--) {
106 value ? elements[i].style.touchAction = value : elements[i].style.removeProperty("touch-action");
107 children = elements[i].children;
108 children && children.length && _setTouchActionForAllDescendants(children, value);
109 }
110},
111 _renderQueueTick = function _renderQueueTick() {
112 return _renderQueue.forEach(function (func) {
113 return func();
114 });
115},
116 _addToRenderQueue = function _addToRenderQueue(func) {
117 _renderQueue.push(func);
118
119 if (_renderQueue.length === 1) {
120 gsap.ticker.add(_renderQueueTick);
121 }
122},
123 _renderQueueTimeout = function _renderQueueTimeout() {
124 return !_renderQueue.length && gsap.ticker.remove(_renderQueueTick);
125},
126 _removeFromRenderQueue = function _removeFromRenderQueue(func) {
127 var i = _renderQueue.length;
128
129 while (i--) {
130 if (_renderQueue[i] === func) {
131 _renderQueue.splice(i, 1);
132 }
133 }
134
135 gsap.to(_renderQueueTimeout, {
136 overwrite: true,
137 delay: 15,
138 duration: 0,
139 onComplete: _renderQueueTimeout,
140 data: "_draggable"
141 }); //remove the "tick" listener only after the render queue is empty for 15 seconds (to improve performance). Adding/removing it constantly for every click/touch wouldn't deliver optimal speed, and we also don't want the ticker to keep calling the render method when things are idle for long periods of time (we want to improve battery life on mobile devices).
142},
143 _setDefaults = function _setDefaults(obj, defaults) {
144 for (var p in defaults) {
145 if (!(p in obj)) {
146 obj[p] = defaults[p];
147 }
148 }
149
150 return obj;
151},
152 _addListener = function _addListener(element, type, func, capture) {
153 if (element.addEventListener) {
154 var touchType = _touchEventLookup[type];
155 capture = capture || (_supportsPassive ? {
156 passive: false
157 } : null);
158 element.addEventListener(touchType || type, func, capture);
159 touchType && type !== touchType && element.addEventListener(type, func, capture); //some browsers actually support both, so must we. But pointer events cover all.
160 }
161},
162 _removeListener = function _removeListener(element, type, func) {
163 if (element.removeEventListener) {
164 var touchType = _touchEventLookup[type];
165 element.removeEventListener(touchType || type, func);
166 touchType && type !== touchType && element.removeEventListener(type, func);
167 }
168},
169 _preventDefault = function _preventDefault(event) {
170 event.preventDefault && event.preventDefault();
171 event.preventManipulation && event.preventManipulation(); //for some Microsoft browsers
172},
173 _hasTouchID = function _hasTouchID(list, ID) {
174 var i = list.length;
175
176 while (i--) {
177 if (list[i].identifier === ID) {
178 return true;
179 }
180 }
181},
182 _onMultiTouchDocumentEnd = function _onMultiTouchDocumentEnd(event) {
183 _isMultiTouching = event.touches && _dragCount < event.touches.length;
184
185 _removeListener(event.target, "touchend", _onMultiTouchDocumentEnd);
186},
187 _onMultiTouchDocument = function _onMultiTouchDocument(event) {
188 _isMultiTouching = event.touches && _dragCount < event.touches.length;
189
190 _addListener(event.target, "touchend", _onMultiTouchDocumentEnd);
191},
192 _getDocScrollTop = function _getDocScrollTop(doc) {
193 return _win.pageYOffset || doc.scrollTop || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
194},
195 _getDocScrollLeft = function _getDocScrollLeft(doc) {
196 return _win.pageXOffset || doc.scrollLeft || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
197},
198 _addScrollListener = function _addScrollListener(e, callback) {
199 _addListener(e, "scroll", callback);
200
201 if (!_isRoot(e.parentNode)) {
202 _addScrollListener(e.parentNode, callback);
203 }
204},
205 _removeScrollListener = function _removeScrollListener(e, callback) {
206 _removeListener(e, "scroll", callback);
207
208 if (!_isRoot(e.parentNode)) {
209 _removeScrollListener(e.parentNode, callback);
210 }
211},
212 _isRoot = function _isRoot(e) {
213 return !!(!e || e === _docElement || e.nodeType === 9 || e === _doc.body || e === _win || !e.nodeType || !e.parentNode);
214},
215 _getMaxScroll = function _getMaxScroll(element, axis) {
216 var dim = axis === "x" ? "Width" : "Height",
217 scroll = "scroll" + dim,
218 client = "client" + dim;
219 return Math.max(0, _isRoot(element) ? Math.max(_docElement[scroll], _body[scroll]) - (_win["inner" + dim] || _docElement[client] || _body[client]) : element[scroll] - element[client]);
220},
221 _recordMaxScrolls = function _recordMaxScrolls(e, skipCurrent) {
222 //records _gsMaxScrollX and _gsMaxScrollY properties for the element and all ancestors up the chain so that we can cap it, otherwise dragging beyond the edges with autoScroll on can endlessly scroll.
223 var x = _getMaxScroll(e, "x"),
224 y = _getMaxScroll(e, "y");
225
226 if (_isRoot(e)) {
227 e = _windowProxy;
228 } else {
229 _recordMaxScrolls(e.parentNode, skipCurrent);
230 }
231
232 e._gsMaxScrollX = x;
233 e._gsMaxScrollY = y;
234
235 if (!skipCurrent) {
236 e._gsScrollX = e.scrollLeft || 0;
237 e._gsScrollY = e.scrollTop || 0;
238 }
239},
240 _setStyle = function _setStyle(element, property, value) {
241 var style = element.style;
242
243 if (!style) {
244 return;
245 }
246
247 if (_isUndefined(style[property])) {
248 property = _checkPrefix(property, element) || property;
249 }
250
251 if (value == null) {
252 style.removeProperty && style.removeProperty(property.replace(/([A-Z])/g, "-$1").toLowerCase());
253 } else {
254 style[property] = value;
255 }
256},
257 _getComputedStyle = function _getComputedStyle(element) {
258 return _win.getComputedStyle(element instanceof Element ? element : element.host || (element.parentNode || {}).host || element);
259},
260 //the "host" stuff helps to accommodate ShadowDom objects.
261_tempRect = {},
262 //reuse to reduce garbage collection tasks
263_parseRect = function _parseRect(e) {
264 //accepts a DOM element, a mouse event, or a rectangle object and returns the corresponding rectangle with left, right, width, height, top, and bottom properties
265 if (e === _win) {
266 _tempRect.left = _tempRect.top = 0;
267 _tempRect.width = _tempRect.right = _docElement.clientWidth || e.innerWidth || _body.clientWidth || 0;
268 _tempRect.height = _tempRect.bottom = (e.innerHeight || 0) - 20 < _docElement.clientHeight ? _docElement.clientHeight : e.innerHeight || _body.clientHeight || 0;
269 return _tempRect;
270 }
271
272 var doc = e.ownerDocument || _doc,
273 r = !_isUndefined(e.pageX) ? {
274 left: e.pageX - _getDocScrollLeft(doc),
275 top: e.pageY - _getDocScrollTop(doc),
276 right: e.pageX - _getDocScrollLeft(doc) + 1,
277 bottom: e.pageY - _getDocScrollTop(doc) + 1
278 } : !e.nodeType && !_isUndefined(e.left) && !_isUndefined(e.top) ? e : _toArray(e)[0].getBoundingClientRect();
279
280 if (_isUndefined(r.right) && !_isUndefined(r.width)) {
281 r.right = r.left + r.width;
282 r.bottom = r.top + r.height;
283 } else if (_isUndefined(r.width)) {
284 //some browsers don't include width and height properties. We can't just set them directly on r because some browsers throw errors, so create a new generic object.
285 r = {
286 width: r.right - r.left,
287 height: r.bottom - r.top,
288 right: r.right,
289 left: r.left,
290 bottom: r.bottom,
291 top: r.top
292 };
293 }
294
295 return r;
296},
297 _dispatchEvent = function _dispatchEvent(target, type, callbackName) {
298 var vars = target.vars,
299 callback = vars[callbackName],
300 listeners = target._listeners[type],
301 result;
302
303 if (_isFunction(callback)) {
304 result = callback.apply(vars.callbackScope || target, vars[callbackName + "Params"] || [target.pointerEvent]);
305 }
306
307 if (listeners && target.dispatchEvent(type) === false) {
308 result = false;
309 }
310
311 return result;
312},
313 _getBounds = function _getBounds(target, context) {
314 //accepts any of the following: a DOM element, jQuery object, selector text, or an object defining bounds as {top, left, width, height} or {minX, maxX, minY, maxY}. Returns an object with left, top, width, and height properties.
315 var e = _toArray(target)[0],
316 top,
317 left,
318 offset;
319
320 if (!e.nodeType && e !== _win) {
321 if (!_isUndefined(target.left)) {
322 offset = {
323 x: 0,
324 y: 0
325 }; //_getOffsetTransformOrigin(context); //the bounds should be relative to the origin
326
327 return {
328 left: target.left - offset.x,
329 top: target.top - offset.y,
330 width: target.width,
331 height: target.height
332 };
333 }
334
335 left = target.min || target.minX || target.minRotation || 0;
336 top = target.min || target.minY || 0;
337 return {
338 left: left,
339 top: top,
340 width: (target.max || target.maxX || target.maxRotation || 0) - left,
341 height: (target.max || target.maxY || 0) - top
342 };
343 }
344
345 return _getElementBounds(e, context);
346},
347 _point1 = {},
348 //we reuse to minimize garbage collection tasks.
349_getElementBounds = function _getElementBounds(element, context) {
350 context = _toArray(context)[0];
351 var isSVG = element.getBBox && element.ownerSVGElement,
352 doc = element.ownerDocument || _doc,
353 left,
354 right,
355 top,
356 bottom,
357 matrix,
358 p1,
359 p2,
360 p3,
361 p4,
362 bbox,
363 width,
364 height,
365 cs,
366 contextParent;
367
368 if (element === _win) {
369 top = _getDocScrollTop(doc);
370 left = _getDocScrollLeft(doc);
371 right = left + (doc.documentElement.clientWidth || element.innerWidth || doc.body.clientWidth || 0);
372 bottom = top + ((element.innerHeight || 0) - 20 < doc.documentElement.clientHeight ? doc.documentElement.clientHeight : element.innerHeight || doc.body.clientHeight || 0); //some browsers (like Firefox) ignore absolutely positioned elements, and collapse the height of the documentElement, so it could be 8px, for example, if you have just an absolutely positioned div. In that case, we use the innerHeight to resolve this.
373 } else if (context === _win || _isUndefined(context)) {
374 return element.getBoundingClientRect();
375 } else {
376 left = top = 0;
377
378 if (isSVG) {
379 bbox = element.getBBox();
380 width = bbox.width;
381 height = bbox.height;
382 } else {
383 if (element.viewBox && (bbox = element.viewBox.baseVal)) {
384 left = bbox.x || 0;
385 top = bbox.y || 0;
386 width = bbox.width;
387 height = bbox.height;
388 }
389
390 if (!width) {
391 cs = _getComputedStyle(element);
392 bbox = cs.boxSizing === "border-box";
393 width = (parseFloat(cs.width) || element.clientWidth || 0) + (bbox ? 0 : parseFloat(cs.borderLeftWidth) + parseFloat(cs.borderRightWidth));
394 height = (parseFloat(cs.height) || element.clientHeight || 0) + (bbox ? 0 : parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth));
395 }
396 }
397
398 right = width;
399 bottom = height;
400 }
401
402 if (element === context) {
403 return {
404 left: left,
405 top: top,
406 width: right - left,
407 height: bottom - top
408 };
409 }
410
411 matrix = getGlobalMatrix(context, true).multiply(getGlobalMatrix(element));
412 p1 = matrix.apply({
413 x: left,
414 y: top
415 });
416 p2 = matrix.apply({
417 x: right,
418 y: top
419 });
420 p3 = matrix.apply({
421 x: right,
422 y: bottom
423 });
424 p4 = matrix.apply({
425 x: left,
426 y: bottom
427 });
428 left = Math.min(p1.x, p2.x, p3.x, p4.x);
429 top = Math.min(p1.y, p2.y, p3.y, p4.y);
430 contextParent = context.parentNode || {};
431 return {
432 left: left + (contextParent.scrollLeft || 0),
433 top: top + (contextParent.scrollTop || 0),
434 width: Math.max(p1.x, p2.x, p3.x, p4.x) - left,
435 height: Math.max(p1.y, p2.y, p3.y, p4.y) - top
436 };
437},
438 _parseInertia = function _parseInertia(draggable, snap, max, min, factor, forceZeroVelocity) {
439 var vars = {},
440 a,
441 i,
442 l;
443
444 if (snap) {
445 if (factor !== 1 && snap instanceof Array) {
446 //some data must be altered to make sense, like if the user passes in an array of rotational values in degrees, we must convert it to radians. Or for scrollLeft and scrollTop, we invert the values.
447 vars.end = a = [];
448 l = snap.length;
449
450 if (_isObject(snap[0])) {
451 //if the array is populated with objects, like points ({x:100, y:200}), make copies before multiplying by the factor, otherwise we'll mess up the originals and the user may reuse it elsewhere.
452 for (i = 0; i < l; i++) {
453 a[i] = _copy(snap[i], factor);
454 }
455 } else {
456 for (i = 0; i < l; i++) {
457 a[i] = snap[i] * factor;
458 }
459 }
460
461 max += 1.1; //allow 1.1 pixels of wiggle room when snapping in order to work around some browser inconsistencies in the way bounds are reported which can make them roughly a pixel off. For example, if "snap:[-$('#menu').width(), 0]" was defined and #menu had a wrapper that was used as the bounds, some browsers would be one pixel off, making the minimum -752 for example when snap was [-753,0], thus instead of snapping to -753, it would snap to 0 since -753 was below the minimum.
462
463 min -= 1.1;
464 } else if (_isFunction(snap)) {
465 vars.end = function (value) {
466 var result = snap.call(draggable, value),
467 copy,
468 p;
469
470 if (factor !== 1) {
471 if (_isObject(result)) {
472 copy = {};
473
474 for (p in result) {
475 copy[p] = result[p] * factor;
476 }
477
478 result = copy;
479 } else {
480 result *= factor;
481 }
482 }
483
484 return result; //we need to ensure that we can scope the function call to the Draggable instance itself so that users can access important values like maxX, minX, maxY, minY, x, and y from within that function.
485 };
486 } else {
487 vars.end = snap;
488 }
489 }
490
491 if (max || max === 0) {
492 vars.max = max;
493 }
494
495 if (min || min === 0) {
496 vars.min = min;
497 }
498
499 if (forceZeroVelocity) {
500 vars.velocity = 0;
501 }
502
503 return vars;
504},
505 _isClickable = function _isClickable(element) {
506 //sometimes it's convenient to mark an element as clickable by adding a data-clickable="true" attribute (in which case we won't preventDefault() the mouse/touch event). This method checks if the element is an <a>, <input>, or <button> or has an onclick or has the data-clickable or contentEditable attribute set to true (or any of its parent elements).
507 var data;
508 return !element || !element.getAttribute || element === _body ? false : (data = element.getAttribute("data-clickable")) === "true" || data !== "false" && (element.onclick || _clickableTagExp.test(element.nodeName + "") || element.getAttribute("contentEditable") === "true") ? true : _isClickable(element.parentNode);
509},
510 _setSelectable = function _setSelectable(elements, selectable) {
511 var i = elements.length,
512 e;
513
514 while (i--) {
515 e = elements[i];
516 e.ondragstart = e.onselectstart = selectable ? null : _emptyFunc;
517 gsap.set(e, {
518 lazy: true,
519 userSelect: selectable ? "text" : "none"
520 });
521 }
522},
523 _isFixed = function _isFixed(element) {
524 if (_getComputedStyle(element).position === "fixed") {
525 return true;
526 }
527
528 element = element.parentNode;
529
530 if (element && element.nodeType === 1) {
531 // avoid document fragments which will throw an error.
532 return _isFixed(element);
533 }
534},
535 _supports3D,
536 _addPaddingBR,
537 //The ScrollProxy class wraps an element's contents into another div (we call it "content") that we either add padding when necessary or apply a translate3d() transform in order to overscroll (scroll past the boundaries). This allows us to simply set the scrollTop/scrollLeft (or top/left for easier reverse-axis orientation, which is what we do in Draggable) and it'll do all the work for us. For example, if we tried setting scrollTop to -100 on a normal DOM element, it wouldn't work - it'd look the same as setting it to 0, but if we set scrollTop of a ScrollProxy to -100, it'll give the correct appearance by either setting paddingTop of the wrapper to 100 or applying a 100-pixel translateY.
538ScrollProxy = function ScrollProxy(element, vars) {
539 element = gsap.utils.toArray(element)[0];
540 vars = vars || {};
541 var content = document.createElement("div"),
542 style = content.style,
543 node = element.firstChild,
544 offsetTop = 0,
545 offsetLeft = 0,
546 prevTop = element.scrollTop,
547 prevLeft = element.scrollLeft,
548 scrollWidth = element.scrollWidth,
549 scrollHeight = element.scrollHeight,
550 extraPadRight = 0,
551 maxLeft = 0,
552 maxTop = 0,
553 elementWidth,
554 elementHeight,
555 contentHeight,
556 nextNode,
557 transformStart,
558 transformEnd;
559
560 if (_supports3D && vars.force3D !== false) {
561 transformStart = "translate3d(";
562 transformEnd = "px,0px)";
563 } else if (_transformProp) {
564 transformStart = "translate(";
565 transformEnd = "px)";
566 }
567
568 this.scrollTop = function (value, force) {
569 if (!arguments.length) {
570 return -this.top();
571 }
572
573 this.top(-value, force);
574 };
575
576 this.scrollLeft = function (value, force) {
577 if (!arguments.length) {
578 return -this.left();
579 }
580
581 this.left(-value, force);
582 };
583
584 this.left = function (value, force) {
585 if (!arguments.length) {
586 return -(element.scrollLeft + offsetLeft);
587 }
588
589 var dif = element.scrollLeft - prevLeft,
590 oldOffset = offsetLeft;
591
592 if ((dif > 2 || dif < -2) && !force) {
593 //if the user interacts with the scrollbar (or something else scrolls it, like the mouse wheel), we should kill any tweens of the ScrollProxy.
594 prevLeft = element.scrollLeft;
595 gsap.killTweensOf(this, {
596 left: 1,
597 scrollLeft: 1
598 });
599 this.left(-prevLeft);
600
601 if (vars.onKill) {
602 vars.onKill();
603 }
604
605 return;
606 }
607
608 value = -value; //invert because scrolling works in the opposite direction
609
610 if (value < 0) {
611 offsetLeft = value - 0.5 | 0;
612 value = 0;
613 } else if (value > maxLeft) {
614 offsetLeft = value - maxLeft | 0;
615 value = maxLeft;
616 } else {
617 offsetLeft = 0;
618 }
619
620 if (offsetLeft || oldOffset) {
621 if (!this._skip) {
622 style[_transformProp] = transformStart + -offsetLeft + "px," + -offsetTop + transformEnd;
623 }
624
625 if (offsetLeft + extraPadRight >= 0) {
626 style.paddingRight = offsetLeft + extraPadRight + "px";
627 }
628 }
629
630 element.scrollLeft = value | 0;
631 prevLeft = element.scrollLeft; //don't merge this with the line above because some browsers adjust the scrollLeft after it's set, so in order to be 100% accurate in tracking it, we need to ask the browser to report it.
632 };
633
634 this.top = function (value, force) {
635 if (!arguments.length) {
636 return -(element.scrollTop + offsetTop);
637 }
638
639 var dif = element.scrollTop - prevTop,
640 oldOffset = offsetTop;
641
642 if ((dif > 2 || dif < -2) && !force) {
643 //if the user interacts with the scrollbar (or something else scrolls it, like the mouse wheel), we should kill any tweens of the ScrollProxy.
644 prevTop = element.scrollTop;
645 gsap.killTweensOf(this, {
646 top: 1,
647 scrollTop: 1
648 });
649 this.top(-prevTop);
650
651 if (vars.onKill) {
652 vars.onKill();
653 }
654
655 return;
656 }
657
658 value = -value; //invert because scrolling works in the opposite direction
659
660 if (value < 0) {
661 offsetTop = value - 0.5 | 0;
662 value = 0;
663 } else if (value > maxTop) {
664 offsetTop = value - maxTop | 0;
665 value = maxTop;
666 } else {
667 offsetTop = 0;
668 }
669
670 if (offsetTop || oldOffset) {
671 if (!this._skip) {
672 style[_transformProp] = transformStart + -offsetLeft + "px," + -offsetTop + transformEnd;
673 }
674 }
675
676 element.scrollTop = value | 0;
677 prevTop = element.scrollTop;
678 };
679
680 this.maxScrollTop = function () {
681 return maxTop;
682 };
683
684 this.maxScrollLeft = function () {
685 return maxLeft;
686 };
687
688 this.disable = function () {
689 node = content.firstChild;
690
691 while (node) {
692 nextNode = node.nextSibling;
693 element.appendChild(node);
694 node = nextNode;
695 }
696
697 if (element === content.parentNode) {
698 //in case disable() is called when it's already disabled.
699 element.removeChild(content);
700 }
701 };
702
703 this.enable = function () {
704 node = element.firstChild;
705
706 if (node === content) {
707 return;
708 }
709
710 while (node) {
711 nextNode = node.nextSibling;
712 content.appendChild(node);
713 node = nextNode;
714 }
715
716 element.appendChild(content);
717 this.calibrate();
718 };
719
720 this.calibrate = function (force) {
721 var widthMatches = element.clientWidth === elementWidth,
722 cs,
723 x,
724 y;
725 prevTop = element.scrollTop;
726 prevLeft = element.scrollLeft;
727
728 if (widthMatches && element.clientHeight === elementHeight && content.offsetHeight === contentHeight && scrollWidth === element.scrollWidth && scrollHeight === element.scrollHeight && !force) {
729 return; //no need to recalculate things if the width and height haven't changed.
730 }
731
732 if (offsetTop || offsetLeft) {
733 x = this.left();
734 y = this.top();
735 this.left(-element.scrollLeft);
736 this.top(-element.scrollTop);
737 }
738
739 cs = _getComputedStyle(element); //first, we need to remove any width constraints to see how the content naturally flows so that we can see if it's wider than the containing element. If so, we've got to record the amount of overage so that we can apply that as padding in order for browsers to correctly handle things. Then we switch back to a width of 100% (without that, some browsers don't flow the content correctly)
740
741 if (!widthMatches || force) {
742 style.display = "block";
743 style.width = "auto";
744 style.paddingRight = "0px";
745 extraPadRight = Math.max(0, element.scrollWidth - element.clientWidth); //if the content is wider than the container, we need to add the paddingLeft and paddingRight in order for things to behave correctly.
746
747 if (extraPadRight) {
748 extraPadRight += parseFloat(cs.paddingLeft) + (_addPaddingBR ? parseFloat(cs.paddingRight) : 0);
749 }
750 }
751
752 style.display = "inline-block";
753 style.position = "relative";
754 style.overflow = "visible";
755 style.verticalAlign = "top";
756 style.boxSizing = "content-box";
757 style.width = "100%";
758 style.paddingRight = extraPadRight + "px"; //some browsers neglect to factor in the bottom padding when calculating the scrollHeight, so we need to add that padding to the content when that happens. Allow a 2px margin for error
759
760 if (_addPaddingBR) {
761 style.paddingBottom = cs.paddingBottom;
762 }
763
764 elementWidth = element.clientWidth;
765 elementHeight = element.clientHeight;
766 scrollWidth = element.scrollWidth;
767 scrollHeight = element.scrollHeight;
768 maxLeft = element.scrollWidth - elementWidth;
769 maxTop = element.scrollHeight - elementHeight;
770 contentHeight = content.offsetHeight;
771 style.display = "block";
772
773 if (x || y) {
774 this.left(x);
775 this.top(y);
776 }
777 };
778
779 this.content = content;
780 this.element = element;
781 this._skip = false;
782 this.enable();
783},
784 _initCore = function _initCore(required) {
785 if (_windowExists() && document.body) {
786 var nav = window && window.navigator;
787 _win = window;
788 _doc = document;
789 _docElement = _doc.documentElement;
790 _body = _doc.body;
791 _tempDiv = _createElement("div");
792 _supportsPointer = !!window.PointerEvent;
793 _placeholderDiv = _createElement("div");
794 _placeholderDiv.style.cssText = "visibility:hidden;height:1px;top:-1px;pointer-events:none;position:relative;clear:both;cursor:grab";
795 _defaultCursor = _placeholderDiv.style.cursor === "grab" ? "grab" : "move";
796 _isAndroid = nav && nav.userAgent.toLowerCase().indexOf("android") !== -1; //Android handles touch events in an odd way and it's virtually impossible to "feature test" so we resort to UA sniffing
797
798 _isTouchDevice = "ontouchstart" in _docElement && "orientation" in _win || nav && (nav.MaxTouchPoints > 0 || nav.msMaxTouchPoints > 0);
799
800 _addPaddingBR = function () {
801 //this function is in charge of analyzing browser behavior related to padding. It sets the _addPaddingBR to true if the browser doesn't normally factor in the bottom or right padding on the element inside the scrolling area, and it sets _addPaddingLeft to true if it's a browser that requires the extra offset (offsetLeft) to be added to the paddingRight (like Opera).
802 var div = _createElement("div"),
803 child = _createElement("div"),
804 childStyle = child.style,
805 parent = _body,
806 val;
807
808 childStyle.display = "inline-block";
809 childStyle.position = "relative";
810 div.style.cssText = child.innerHTML = "width:90px;height:40px;padding:10px;overflow:auto;visibility:hidden";
811 div.appendChild(child);
812 parent.appendChild(div);
813 val = child.offsetHeight + 18 > div.scrollHeight; //div.scrollHeight should be child.offsetHeight + 20 because of the 10px of padding on each side, but some browsers ignore one side. We allow a 2px margin of error.
814
815 parent.removeChild(div);
816 return val;
817 }();
818
819 _touchEventLookup = function (types) {
820 //we create an object that makes it easy to translate touch event types into their "pointer" counterparts if we're in a browser that uses those instead. Like IE10 uses "MSPointerDown" instead of "touchstart", for example.
821 var standard = types.split(","),
822 converted = ("onpointerdown" in _tempDiv ? "pointerdown,pointermove,pointerup,pointercancel" : "onmspointerdown" in _tempDiv ? "MSPointerDown,MSPointerMove,MSPointerUp,MSPointerCancel" : types).split(","),
823 obj = {},
824 i = 4;
825
826 while (--i > -1) {
827 obj[standard[i]] = converted[i];
828 obj[converted[i]] = standard[i];
829 } //to avoid problems in iOS 9, test to see if the browser supports the "passive" option on addEventListener().
830
831
832 try {
833 _docElement.addEventListener("test", null, Object.defineProperty({}, "passive", {
834 get: function get() {
835 _supportsPassive = 1;
836 }
837 }));
838 } catch (e) {}
839
840 return obj;
841 }("touchstart,touchmove,touchend,touchcancel");
842
843 _addListener(_doc, "touchcancel", _emptyFunc); //some older Android devices intermittently stop dispatching "touchmove" events if we don't listen for "touchcancel" on the document. Very strange indeed.
844
845
846 _addListener(_win, "touchmove", _emptyFunc); //works around Safari bugs that still allow the page to scroll even when we preventDefault() on the touchmove event.
847
848
849 _body && _body.addEventListener("touchstart", _emptyFunc); //works around Safari bug: https://greensock.com/forums/topic/21450-draggable-in-iframe-on-mobile-is-buggy/
850
851 _addListener(_doc, "contextmenu", function () {
852 for (var p in _lookup) {
853 if (_lookup[p].isPressed) {
854 _lookup[p].endDrag();
855 }
856 }
857 });
858
859 gsap = _coreInitted = _getGSAP();
860 }
861
862 if (gsap) {
863 InertiaPlugin = gsap.plugins.inertia;
864 _checkPrefix = gsap.utils.checkPrefix;
865 _transformProp = _checkPrefix(_transformProp);
866 _transformOriginProp = _checkPrefix(_transformOriginProp);
867 _toArray = gsap.utils.toArray;
868 _supports3D = !!_checkPrefix("perspective");
869 } else if (required) {
870 console.warn("Please gsap.registerPlugin(Draggable)");
871 }
872};
873
874var EventDispatcher = /*#__PURE__*/function () {
875 function EventDispatcher(target) {
876 this._listeners = {};
877 this.target = target || this;
878 }
879
880 var _proto = EventDispatcher.prototype;
881
882 _proto.addEventListener = function addEventListener(type, callback) {
883 var list = this._listeners[type] || (this._listeners[type] = []);
884
885 if (!~list.indexOf(callback)) {
886 list.push(callback);
887 }
888 };
889
890 _proto.removeEventListener = function removeEventListener(type, callback) {
891 var list = this._listeners[type],
892 i = list && list.indexOf(callback) || -1;
893 i > -1 && list.splice(i, 1);
894 };
895
896 _proto.dispatchEvent = function dispatchEvent(type) {
897 var _this = this;
898
899 var result;
900 (this._listeners[type] || []).forEach(function (callback) {
901 return callback.call(_this, {
902 type: type,
903 target: _this.target
904 }) === false && (result = false);
905 });
906 return result; //if any of the callbacks return false, pass that along.
907 };
908
909 return EventDispatcher;
910}();
911
912export var Draggable = /*#__PURE__*/function (_EventDispatcher) {
913 _inheritsLoose(Draggable, _EventDispatcher);
914
915 function Draggable(target, vars) {
916 var _this2;
917
918 _this2 = _EventDispatcher.call(this) || this;
919 _coreInitted || _initCore(1);
920 target = _toArray(target)[0]; //in case the target is a selector object or selector text
921
922 if (!InertiaPlugin) {
923 InertiaPlugin = gsap.plugins.inertia;
924 }
925
926 _this2.vars = vars = _copy(vars || {});
927 _this2.target = target;
928 _this2.x = _this2.y = _this2.rotation = 0;
929 _this2.dragResistance = parseFloat(vars.dragResistance) || 0;
930 _this2.edgeResistance = isNaN(vars.edgeResistance) ? 1 : parseFloat(vars.edgeResistance) || 0;
931 _this2.lockAxis = vars.lockAxis;
932 _this2.autoScroll = vars.autoScroll || 0;
933 _this2.lockedAxis = null;
934 _this2.allowEventDefault = !!vars.allowEventDefault;
935 gsap.getProperty(target, "x"); // to ensure that transforms are instantiated.
936
937 var type = (vars.type || "x,y").toLowerCase(),
938 xyMode = ~type.indexOf("x") || ~type.indexOf("y"),
939 rotationMode = type.indexOf("rotation") !== -1,
940 xProp = rotationMode ? "rotation" : xyMode ? "x" : "left",
941 yProp = xyMode ? "y" : "top",
942 allowX = !!(~type.indexOf("x") || ~type.indexOf("left") || type === "scroll"),
943 allowY = !!(~type.indexOf("y") || ~type.indexOf("top") || type === "scroll"),
944 minimumMovement = vars.minimumMovement || 2,
945 self = _assertThisInitialized(_this2),
946 triggers = _toArray(vars.trigger || vars.handle || target),
947 killProps = {},
948 dragEndTime = 0,
949 checkAutoScrollBounds = false,
950 autoScrollMarginTop = vars.autoScrollMarginTop || 40,
951 autoScrollMarginRight = vars.autoScrollMarginRight || 40,
952 autoScrollMarginBottom = vars.autoScrollMarginBottom || 40,
953 autoScrollMarginLeft = vars.autoScrollMarginLeft || 40,
954 isClickable = vars.clickableTest || _isClickable,
955 clickTime = 0,
956 gsCache = target._gsap || gsap.core.getCache(target),
957 isFixed = _isFixed(target),
958 getPropAsNum = function getPropAsNum(property, unit) {
959 return parseFloat(gsCache.get(target, property, unit));
960 },
961 ownerDoc = target.ownerDocument || _doc,
962 enabled,
963 scrollProxy,
964 startPointerX,
965 startPointerY,
966 startElementX,
967 startElementY,
968 hasBounds,
969 hasDragCallback,
970 hasMoveCallback,
971 maxX,
972 minX,
973 maxY,
974 minY,
975 touch,
976 touchID,
977 rotationOrigin,
978 dirty,
979 old,
980 snapX,
981 snapY,
982 snapXY,
983 isClicking,
984 touchEventTarget,
985 matrix,
986 interrupted,
987 allowNativeTouchScrolling,
988 touchDragAxis,
989 isDispatching,
990 clickDispatch,
991 trustedClickDispatch,
992 isPreventingDefault,
993 innerMatrix,
994 onContextMenu = function onContextMenu(e) {
995 //used to prevent long-touch from triggering a context menu.
996 // (self.isPressed && e.which < 2) && self.endDrag() // previously ended drag when context menu was triggered, but instead we should just stop propagation and prevent the default event behavior.
997 _preventDefault(e);
998
999 e.stopImmediatePropagation && e.stopImmediatePropagation();
1000 return false;
1001 },
1002 //this method gets called on every tick of TweenLite.ticker which allows us to synchronize the renders to the core engine (which is typically synchronized with the display refresh via requestAnimationFrame). This is an optimization - it's better than applying the values inside the "mousemove" or "touchmove" event handler which may get called many times inbetween refreshes.
1003 render = function render(suppressEvents) {
1004 if (self.autoScroll && self.isDragging && (checkAutoScrollBounds || dirty)) {
1005 var e = target,
1006 autoScrollFactor = self.autoScroll * 15,
1007 //multiplying by 15 just gives us a better "feel" speed-wise.
1008 parent,
1009 isRoot,
1010 rect,
1011 pointerX,
1012 pointerY,
1013 changeX,
1014 changeY,
1015 gap;
1016 checkAutoScrollBounds = false;
1017 _windowProxy.scrollTop = _win.pageYOffset != null ? _win.pageYOffset : ownerDoc.documentElement.scrollTop != null ? ownerDoc.documentElement.scrollTop : ownerDoc.body.scrollTop;
1018 _windowProxy.scrollLeft = _win.pageXOffset != null ? _win.pageXOffset : ownerDoc.documentElement.scrollLeft != null ? ownerDoc.documentElement.scrollLeft : ownerDoc.body.scrollLeft;
1019 pointerX = self.pointerX - _windowProxy.scrollLeft;
1020 pointerY = self.pointerY - _windowProxy.scrollTop;
1021
1022 while (e && !isRoot) {
1023 //walk up the chain and sense wherever the pointer is within 40px of an edge that's scrollable.
1024 isRoot = _isRoot(e.parentNode);
1025 parent = isRoot ? _windowProxy : e.parentNode;
1026 rect = isRoot ? {
1027 bottom: Math.max(_docElement.clientHeight, _win.innerHeight || 0),
1028 right: Math.max(_docElement.clientWidth, _win.innerWidth || 0),
1029 left: 0,
1030 top: 0
1031 } : parent.getBoundingClientRect();
1032 changeX = changeY = 0;
1033
1034 if (allowY) {
1035 gap = parent._gsMaxScrollY - parent.scrollTop;
1036
1037 if (gap < 0) {
1038 changeY = gap;
1039 } else if (pointerY > rect.bottom - autoScrollMarginBottom && gap) {
1040 checkAutoScrollBounds = true;
1041 changeY = Math.min(gap, autoScrollFactor * (1 - Math.max(0, rect.bottom - pointerY) / autoScrollMarginBottom) | 0);
1042 } else if (pointerY < rect.top + autoScrollMarginTop && parent.scrollTop) {
1043 checkAutoScrollBounds = true;
1044 changeY = -Math.min(parent.scrollTop, autoScrollFactor * (1 - Math.max(0, pointerY - rect.top) / autoScrollMarginTop) | 0);
1045 }
1046
1047 if (changeY) {
1048 parent.scrollTop += changeY;
1049 }
1050 }
1051
1052 if (allowX) {
1053 gap = parent._gsMaxScrollX - parent.scrollLeft;
1054
1055 if (gap < 0) {
1056 changeX = gap;
1057 } else if (pointerX > rect.right - autoScrollMarginRight && gap) {
1058 checkAutoScrollBounds = true;
1059 changeX = Math.min(gap, autoScrollFactor * (1 - Math.max(0, rect.right - pointerX) / autoScrollMarginRight) | 0);
1060 } else if (pointerX < rect.left + autoScrollMarginLeft && parent.scrollLeft) {
1061 checkAutoScrollBounds = true;
1062 changeX = -Math.min(parent.scrollLeft, autoScrollFactor * (1 - Math.max(0, pointerX - rect.left) / autoScrollMarginLeft) | 0);
1063 }
1064
1065 if (changeX) {
1066 parent.scrollLeft += changeX;
1067 }
1068 }
1069
1070 if (isRoot && (changeX || changeY)) {
1071 _win.scrollTo(parent.scrollLeft, parent.scrollTop);
1072
1073 setPointerPosition(self.pointerX + changeX, self.pointerY + changeY);
1074 }
1075
1076 e = parent;
1077 }
1078 }
1079
1080 if (dirty) {
1081 var x = self.x,
1082 y = self.y;
1083
1084 if (rotationMode) {
1085 self.deltaX = x - parseFloat(gsCache.rotation);
1086 self.rotation = x;
1087 gsCache.rotation = x + "deg";
1088 gsCache.renderTransform(1, gsCache);
1089 } else {
1090 if (scrollProxy) {
1091 if (allowY) {
1092 self.deltaY = y - scrollProxy.top();
1093 scrollProxy.top(y);
1094 }
1095
1096 if (allowX) {
1097 self.deltaX = x - scrollProxy.left();
1098 scrollProxy.left(x);
1099 }
1100 } else if (xyMode) {
1101 if (allowY) {
1102 self.deltaY = y - parseFloat(gsCache.y);
1103 gsCache.y = y + "px";
1104 }
1105
1106 if (allowX) {
1107 self.deltaX = x - parseFloat(gsCache.x);
1108 gsCache.x = x + "px";
1109 }
1110
1111 gsCache.renderTransform(1, gsCache);
1112 } else {
1113 if (allowY) {
1114 self.deltaY = y - parseFloat(target.style.top || 0);
1115 target.style.top = y + "px";
1116 }
1117
1118 if (allowX) {
1119 self.deltaX = x - parseFloat(target.style.left || 0);
1120 target.style.left = x + "px";
1121 }
1122 }
1123 }
1124
1125 if (hasDragCallback && !suppressEvents && !isDispatching) {
1126 isDispatching = true; //in case onDrag has an update() call (avoid endless loop)
1127
1128 if (_dispatchEvent(self, "drag", "onDrag") === false) {
1129 if (allowX) {
1130 self.x -= self.deltaX;
1131 }
1132
1133 if (allowY) {
1134 self.y -= self.deltaY;
1135 }
1136
1137 render(true);
1138 }
1139
1140 isDispatching = false;
1141 }
1142 }
1143
1144 dirty = false;
1145 },
1146 //copies the x/y from the element (whether that be transforms, top/left, or ScrollProxy's top/left) to the Draggable's x and y (and rotation if necessary) properties so that they reflect reality and it also (optionally) applies any snapping necessary. This is used by the InertiaPlugin tween in an onUpdate to ensure things are synced and snapped.
1147 syncXY = function syncXY(skipOnUpdate, skipSnap) {
1148 var x = self.x,
1149 y = self.y,
1150 snappedValue,
1151 cs;
1152
1153 if (!target._gsap) {
1154 //just in case the _gsap cache got wiped, like if the user called clearProps on the transform or something (very rare).
1155 gsCache = gsap.core.getCache(target);
1156 }
1157
1158 gsCache.uncache && gsap.getProperty(target, "x"); // trigger a re-cache
1159
1160 if (xyMode) {
1161 self.x = parseFloat(gsCache.x);
1162 self.y = parseFloat(gsCache.y);
1163 } else if (rotationMode) {
1164 self.x = self.rotation = parseFloat(gsCache.rotation);
1165 } else if (scrollProxy) {
1166 self.y = scrollProxy.top();
1167 self.x = scrollProxy.left();
1168 } else {
1169 self.y = parseFloat(target.style.top || (cs = _getComputedStyle(target)) && cs.top) || 0;
1170 self.x = parseFloat(target.style.left || (cs || {}).left) || 0;
1171 }
1172
1173 if ((snapX || snapY || snapXY) && !skipSnap && (self.isDragging || self.isThrowing)) {
1174 if (snapXY) {
1175 _temp1.x = self.x;
1176 _temp1.y = self.y;
1177 snappedValue = snapXY(_temp1);
1178
1179 if (snappedValue.x !== self.x) {
1180 self.x = snappedValue.x;
1181 dirty = true;
1182 }
1183
1184 if (snappedValue.y !== self.y) {
1185 self.y = snappedValue.y;
1186 dirty = true;
1187 }
1188 }
1189
1190 if (snapX) {
1191 snappedValue = snapX(self.x);
1192
1193 if (snappedValue !== self.x) {
1194 self.x = snappedValue;
1195
1196 if (rotationMode) {
1197 self.rotation = snappedValue;
1198 }
1199
1200 dirty = true;
1201 }
1202 }
1203
1204 if (snapY) {
1205 snappedValue = snapY(self.y);
1206
1207 if (snappedValue !== self.y) {
1208 self.y = snappedValue;
1209 }
1210
1211 dirty = true;
1212 }
1213 }
1214
1215 dirty && render(true);
1216
1217 if (!skipOnUpdate) {
1218 self.deltaX = self.x - x;
1219 self.deltaY = self.y - y;
1220
1221 _dispatchEvent(self, "throwupdate", "onThrowUpdate");
1222 }
1223 },
1224 buildSnapFunc = function buildSnapFunc(snap, min, max, factor) {
1225 if (min == null) {
1226 min = -_bigNum;
1227 }
1228
1229 if (max == null) {
1230 max = _bigNum;
1231 }
1232
1233 if (_isFunction(snap)) {
1234 return function (n) {
1235 var edgeTolerance = !self.isPressed ? 1 : 1 - self.edgeResistance; //if we're tweening, disable the edgeTolerance because it's already factored into the tweening values (we don't want to apply it multiple times)
1236
1237 return snap.call(self, n > max ? max + (n - max) * edgeTolerance : n < min ? min + (n - min) * edgeTolerance : n) * factor;
1238 };
1239 }
1240
1241 if (_isArray(snap)) {
1242 return function (n) {
1243 var i = snap.length,
1244 closest = 0,
1245 absDif = _bigNum,
1246 val,
1247 dif;
1248
1249 while (--i > -1) {
1250 val = snap[i];
1251 dif = val - n;
1252
1253 if (dif < 0) {
1254 dif = -dif;
1255 }
1256
1257 if (dif < absDif && val >= min && val <= max) {
1258 closest = i;
1259 absDif = dif;
1260 }
1261 }
1262
1263 return snap[closest];
1264 };
1265 }
1266
1267 return isNaN(snap) ? function (n) {
1268 return n;
1269 } : function () {
1270 return snap * factor;
1271 };
1272 },
1273 buildPointSnapFunc = function buildPointSnapFunc(snap, minX, maxX, minY, maxY, radius, factor) {
1274 radius = radius && radius < _bigNum ? radius * radius : _bigNum; //so we don't have to Math.sqrt() in the functions. Performance optimization.
1275
1276 if (_isFunction(snap)) {
1277 return function (point) {
1278 var edgeTolerance = !self.isPressed ? 1 : 1 - self.edgeResistance,
1279 x = point.x,
1280 y = point.y,
1281 result,
1282 dx,
1283 dy; //if we're tweening, disable the edgeTolerance because it's already factored into the tweening values (we don't want to apply it multiple times)
1284
1285 point.x = x = x > maxX ? maxX + (x - maxX) * edgeTolerance : x < minX ? minX + (x - minX) * edgeTolerance : x;
1286 point.y = y = y > maxY ? maxY + (y - maxY) * edgeTolerance : y < minY ? minY + (y - minY) * edgeTolerance : y;
1287 result = snap.call(self, point);
1288
1289 if (result !== point) {
1290 point.x = result.x;
1291 point.y = result.y;
1292 }
1293
1294 if (factor !== 1) {
1295 point.x *= factor;
1296 point.y *= factor;
1297 }
1298
1299 if (radius < _bigNum) {
1300 dx = point.x - x;
1301 dy = point.y - y;
1302
1303 if (dx * dx + dy * dy > radius) {
1304 point.x = x;
1305 point.y = y;
1306 }
1307 }
1308
1309 return point;
1310 };
1311 }
1312
1313 if (_isArray(snap)) {
1314 return function (p) {
1315 var i = snap.length,
1316 closest = 0,
1317 minDist = _bigNum,
1318 x,
1319 y,
1320 point,
1321 dist;
1322
1323 while (--i > -1) {
1324 point = snap[i];
1325 x = point.x - p.x;
1326 y = point.y - p.y;
1327 dist = x * x + y * y;
1328
1329 if (dist < minDist) {
1330 closest = i;
1331 minDist = dist;
1332 }
1333 }
1334
1335 return minDist <= radius ? snap[closest] : p;
1336 };
1337 }
1338
1339 return function (n) {
1340 return n;
1341 };
1342 },
1343 calculateBounds = function calculateBounds() {
1344 var bounds, targetBounds, snap, snapIsRaw;
1345 hasBounds = false;
1346
1347 if (scrollProxy) {
1348 scrollProxy.calibrate();
1349 self.minX = minX = -scrollProxy.maxScrollLeft();
1350 self.minY = minY = -scrollProxy.maxScrollTop();
1351 self.maxX = maxX = self.maxY = maxY = 0;
1352 hasBounds = true;
1353 } else if (!!vars.bounds) {
1354 bounds = _getBounds(vars.bounds, target.parentNode); //could be a selector/jQuery object or a DOM element or a generic object like {top:0, left:100, width:1000, height:800} or {minX:100, maxX:1100, minY:0, maxY:800}
1355
1356 if (rotationMode) {
1357 self.minX = minX = bounds.left;
1358 self.maxX = maxX = bounds.left + bounds.width;
1359 self.minY = minY = self.maxY = maxY = 0;
1360 } else if (!_isUndefined(vars.bounds.maxX) || !_isUndefined(vars.bounds.maxY)) {
1361 bounds = vars.bounds;
1362 self.minX = minX = bounds.minX;
1363 self.minY = minY = bounds.minY;
1364 self.maxX = maxX = bounds.maxX;
1365 self.maxY = maxY = bounds.maxY;
1366 } else {
1367 targetBounds = _getBounds(target, target.parentNode);
1368 self.minX = minX = Math.round(getPropAsNum(xProp, "px") + bounds.left - targetBounds.left);
1369 self.minY = minY = Math.round(getPropAsNum(yProp, "px") + bounds.top - targetBounds.top);
1370 self.maxX = maxX = Math.round(minX + (bounds.width - targetBounds.width));
1371 self.maxY = maxY = Math.round(minY + (bounds.height - targetBounds.height));
1372 }
1373
1374 if (minX > maxX) {
1375 self.minX = maxX;
1376 self.maxX = maxX = minX;
1377 minX = self.minX;
1378 }
1379
1380 if (minY > maxY) {
1381 self.minY = maxY;
1382 self.maxY = maxY = minY;
1383 minY = self.minY;
1384 }
1385
1386 if (rotationMode) {
1387 self.minRotation = minX;
1388 self.maxRotation = maxX;
1389 }
1390
1391 hasBounds = true;
1392 }
1393
1394 if (vars.liveSnap) {
1395 snap = vars.liveSnap === true ? vars.snap || {} : vars.liveSnap;
1396 snapIsRaw = _isArray(snap) || _isFunction(snap);
1397
1398 if (rotationMode) {
1399 snapX = buildSnapFunc(snapIsRaw ? snap : snap.rotation, minX, maxX, 1);
1400 snapY = null;
1401 } else {
1402 if (snap.points) {
1403 snapXY = buildPointSnapFunc(snapIsRaw ? snap : snap.points, minX, maxX, minY, maxY, snap.radius, scrollProxy ? -1 : 1);
1404 } else {
1405 if (allowX) {
1406 snapX = buildSnapFunc(snapIsRaw ? snap : snap.x || snap.left || snap.scrollLeft, minX, maxX, scrollProxy ? -1 : 1);
1407 }
1408
1409 if (allowY) {
1410 snapY = buildSnapFunc(snapIsRaw ? snap : snap.y || snap.top || snap.scrollTop, minY, maxY, scrollProxy ? -1 : 1);
1411 }
1412 }
1413 }
1414 }
1415 },
1416 onThrowComplete = function onThrowComplete() {
1417 self.isThrowing = false;
1418
1419 _dispatchEvent(self, "throwcomplete", "onThrowComplete");
1420 },
1421 onThrowInterrupt = function onThrowInterrupt() {
1422 self.isThrowing = false;
1423 },
1424 animate = function animate(inertia, forceZeroVelocity) {
1425 var snap, snapIsRaw, tween, overshootTolerance;
1426
1427 if (inertia && InertiaPlugin) {
1428 if (inertia === true) {
1429 snap = vars.snap || vars.liveSnap || {};
1430 snapIsRaw = _isArray(snap) || _isFunction(snap);
1431 inertia = {
1432 resistance: (vars.throwResistance || vars.resistance || 1000) / (rotationMode ? 10 : 1)
1433 };
1434
1435 if (rotationMode) {
1436 inertia.rotation = _parseInertia(self, snapIsRaw ? snap : snap.rotation, maxX, minX, 1, forceZeroVelocity);
1437 } else {
1438 if (allowX) {
1439 inertia[xProp] = _parseInertia(self, snapIsRaw ? snap : snap.points || snap.x || snap.left, maxX, minX, scrollProxy ? -1 : 1, forceZeroVelocity || self.lockedAxis === "x");
1440 }
1441
1442 if (allowY) {
1443 inertia[yProp] = _parseInertia(self, snapIsRaw ? snap : snap.points || snap.y || snap.top, maxY, minY, scrollProxy ? -1 : 1, forceZeroVelocity || self.lockedAxis === "y");
1444 }
1445
1446 if (snap.points || _isArray(snap) && _isObject(snap[0])) {
1447 inertia.linkedProps = xProp + "," + yProp;
1448 inertia.radius = snap.radius; //note: we also disable liveSnapping while throwing if there's a "radius" defined, otherwise it looks weird to have the item thrown past a snapping point but live-snapping mid-tween. We do this by altering the onUpdateParams so that "skipSnap" parameter is true for syncXY.
1449 }
1450 }
1451 }
1452
1453 self.isThrowing = true;
1454 overshootTolerance = !isNaN(vars.overshootTolerance) ? vars.overshootTolerance : vars.edgeResistance === 1 ? 0 : 1 - self.edgeResistance + 0.2;
1455
1456 if (!inertia.duration) {
1457 inertia.duration = {
1458 max: Math.max(vars.minDuration || 0, "maxDuration" in vars ? vars.maxDuration : 2),
1459 min: !isNaN(vars.minDuration) ? vars.minDuration : overshootTolerance === 0 || _isObject(inertia) && inertia.resistance > 1000 ? 0 : 0.5,
1460 overshoot: overshootTolerance
1461 };
1462 }
1463
1464 self.tween = tween = gsap.to(scrollProxy || target, {
1465 inertia: inertia,
1466 data: "_draggable",
1467 onComplete: onThrowComplete,
1468 onInterrupt: onThrowInterrupt,
1469 onUpdate: vars.fastMode ? _dispatchEvent : syncXY,
1470 onUpdateParams: vars.fastMode ? [self, "onthrowupdate", "onThrowUpdate"] : snap && snap.radius ? [false, true] : []
1471 });
1472
1473 if (!vars.fastMode) {
1474 if (scrollProxy) {
1475 scrollProxy._skip = true; // Microsoft browsers have a bug that causes them to briefly render the position incorrectly (it flashes to the end state when we seek() the tween even though we jump right back to the current position, and this only seems to happen when we're affecting both top and left), so we set a _suspendTransforms flag to prevent it from actually applying the values in the ScrollProxy.
1476 }
1477
1478 tween.render(1e9, true, true); // force to the end. Remember, the duration will likely change upon initting because that's when InertiaPlugin calculates it.
1479
1480 syncXY(true, true);
1481 self.endX = self.x;
1482 self.endY = self.y;
1483
1484 if (rotationMode) {
1485 self.endRotation = self.x;
1486 }
1487
1488 tween.play(0);
1489 syncXY(true, true);
1490
1491 if (scrollProxy) {
1492 scrollProxy._skip = false; //Microsoft browsers have a bug that causes them to briefly render the position incorrectly (it flashes to the end state when we seek() the tween even though we jump right back to the current position, and this only seems to happen when we're affecting both top and left), so we set a _suspendTransforms flag to prevent it from actually applying the values in the ScrollProxy.
1493 }
1494 }
1495 } else if (hasBounds) {
1496 self.applyBounds();
1497 }
1498 },
1499 updateMatrix = function updateMatrix(shiftStart) {
1500 var start = matrix,
1501 p;
1502 matrix = getGlobalMatrix(target.parentNode, true);
1503
1504 if (shiftStart && self.isPressed && !matrix.equals(start || new Matrix2D())) {
1505 //if the matrix changes WHILE the element is pressed, we must adjust the startPointerX and startPointerY accordingly, so we invert the original matrix and figure out where the pointerX and pointerY were in the global space, then apply the new matrix to get the updated coordinates.
1506 p = start.inverse().apply({
1507 x: startPointerX,
1508 y: startPointerY
1509 });
1510 matrix.apply(p, p);
1511 startPointerX = p.x;
1512 startPointerY = p.y;
1513 }
1514
1515 if (matrix.equals(_identityMatrix)) {
1516 //if there are no transforms, we can optimize performance by not factoring in the matrix
1517 matrix = null;
1518 }
1519 },
1520 recordStartPositions = function recordStartPositions() {
1521 var edgeTolerance = 1 - self.edgeResistance,
1522 offsetX = isFixed ? _getDocScrollLeft(ownerDoc) : 0,
1523 offsetY = isFixed ? _getDocScrollTop(ownerDoc) : 0,
1524 parsedOrigin,
1525 x,
1526 y;
1527 updateMatrix(false);
1528 _point1.x = self.pointerX - offsetX;
1529 _point1.y = self.pointerY - offsetY;
1530 matrix && matrix.apply(_point1, _point1);
1531 startPointerX = _point1.x; //translate to local coordinate system
1532
1533 startPointerY = _point1.y;
1534
1535 if (dirty) {
1536 setPointerPosition(self.pointerX, self.pointerY);
1537 render(true);
1538 }
1539
1540 innerMatrix = getGlobalMatrix(target);
1541
1542 if (scrollProxy) {
1543 calculateBounds();
1544 startElementY = scrollProxy.top();
1545 startElementX = scrollProxy.left();
1546 } else {
1547 //if the element is in the process of tweening, don't force snapping to occur because it could make it jump. Imagine the user throwing, then before it's done, clicking on the element in its inbetween state.
1548 if (isTweening()) {
1549 syncXY(true, true);
1550 calculateBounds();
1551 } else {
1552 self.applyBounds();
1553 }
1554
1555 if (rotationMode) {
1556 parsedOrigin = target.ownerSVGElement ? [gsCache.xOrigin - target.getBBox().x, gsCache.yOrigin - target.getBBox().y] : (_getComputedStyle(target)[_transformOriginProp] || "0 0").split(" ");
1557 rotationOrigin = self.rotationOrigin = getGlobalMatrix(target).apply({
1558 x: parseFloat(parsedOrigin[0]) || 0,
1559 y: parseFloat(parsedOrigin[1]) || 0
1560 });
1561 syncXY(true, true);
1562 x = self.pointerX - rotationOrigin.x - offsetX;
1563 y = rotationOrigin.y - self.pointerY + offsetY;
1564 startElementX = self.x; //starting rotation (x always refers to rotation in type:"rotation", measured in degrees)
1565
1566 startElementY = self.y = Math.atan2(y, x) * _RAD2DEG;
1567 } else {
1568 //parent = !isFixed && target.parentNode;
1569 //startScrollTop = parent ? parent.scrollTop || 0 : 0;
1570 //startScrollLeft = parent ? parent.scrollLeft || 0 : 0;
1571 startElementY = getPropAsNum(yProp, "px"); //record the starting top and left values so that we can just add the mouse's movement to them later.
1572
1573 startElementX = getPropAsNum(xProp, "px");
1574 }
1575 }
1576
1577 if (hasBounds && edgeTolerance) {
1578 if (startElementX > maxX) {
1579 startElementX = maxX + (startElementX - maxX) / edgeTolerance;
1580 } else if (startElementX < minX) {
1581 startElementX = minX - (minX - startElementX) / edgeTolerance;
1582 }
1583
1584 if (!rotationMode) {
1585 if (startElementY > maxY) {
1586 startElementY = maxY + (startElementY - maxY) / edgeTolerance;
1587 } else if (startElementY < minY) {
1588 startElementY = minY - (minY - startElementY) / edgeTolerance;
1589 }
1590 }
1591 }
1592
1593 self.startX = startElementX = _round(startElementX);
1594 self.startY = startElementY = _round(startElementY);
1595 },
1596 isTweening = function isTweening() {
1597 return self.tween && self.tween.isActive();
1598 },
1599 removePlaceholder = function removePlaceholder() {
1600 if (_placeholderDiv.parentNode && !isTweening() && !self.isDragging) {
1601 //_placeholderDiv just props open auto-scrolling containers so they don't collapse as the user drags left/up. We remove it after dragging (and throwing, if necessary) finishes.
1602 _placeholderDiv.parentNode.removeChild(_placeholderDiv);
1603 }
1604 },
1605 //called when the mouse is pressed (or touch starts)
1606 onPress = function onPress(e, force) {
1607 var i;
1608
1609 if (!enabled || self.isPressed || !e || (e.type === "mousedown" || e.type === "pointerdown") && !force && _getTime() - clickTime < 30 && _touchEventLookup[self.pointerEvent.type]) {
1610 //when we DON'T preventDefault() in order to accommodate touch-scrolling and the user just taps, many browsers also fire a mousedown/mouseup sequence AFTER the touchstart/touchend sequence, thus it'd result in two quick "click" events being dispatched. This line senses that condition and halts it on the subsequent mousedown.
1611 isPreventingDefault && e && enabled && _preventDefault(e); // in some browsers, we must listen for multiple event types like touchstart, pointerdown, mousedown. The first time this function is called, we record whether or not we _preventDefault() so that on duplicate calls, we can do the same if necessary.
1612
1613 return;
1614 }
1615
1616 interrupted = isTweening();
1617 self.pointerEvent = e;
1618
1619 if (_touchEventLookup[e.type]) {
1620 //note: on iOS, BOTH touchmove and mousemove are dispatched, but the mousemove has pageY and pageX of 0 which would mess up the calculations and needlessly hurt performance.
1621 touchEventTarget = ~e.type.indexOf("touch") ? e.currentTarget || e.target : ownerDoc; //pointer-based touches (for Microsoft browsers) don't remain locked to the original target like other browsers, so we must use the document instead. The event type would be "MSPointerDown" or "pointerdown".
1622
1623 _addListener(touchEventTarget, "touchend", onRelease);
1624
1625 _addListener(touchEventTarget, "touchmove", onMove);
1626
1627 _addListener(touchEventTarget, "touchcancel", onRelease);
1628
1629 _addListener(ownerDoc, "touchstart", _onMultiTouchDocument);
1630 } else {
1631 touchEventTarget = null;
1632
1633 _addListener(ownerDoc, "mousemove", onMove); //attach these to the document instead of the box itself so that if the user's mouse moves too quickly (and off of the box), things still work.
1634
1635 }
1636
1637 touchDragAxis = null;
1638
1639 if (!_supportsPointer || !touchEventTarget) {
1640 _addListener(ownerDoc, "mouseup", onRelease);
1641
1642 e && e.target && _addListener(e.target, "mouseup", onRelease); //we also have to listen directly on the element because some browsers don't bubble up the event to the _doc on elements with contentEditable="true"
1643 }
1644
1645 isClicking = isClickable.call(self, e.target) && vars.dragClickables === false && !force;
1646
1647 if (isClicking) {
1648 _addListener(e.target, "change", onRelease); //in some browsers, when you mousedown on a <select> element, no mouseup gets dispatched! So we listen for a "change" event instead.
1649
1650
1651 _dispatchEvent(self, "pressInit", "onPressInit");
1652
1653 _dispatchEvent(self, "press", "onPress");
1654
1655 _setSelectable(triggers, true); //accommodates things like inputs and elements with contentEditable="true" (otherwise user couldn't drag to select text)
1656
1657
1658 isPreventingDefault = false;
1659 return;
1660 }
1661
1662 allowNativeTouchScrolling = !touchEventTarget || allowX === allowY || self.vars.allowNativeTouchScrolling === false || self.vars.allowContextMenu && e && (e.ctrlKey || e.which > 2) ? false : allowX ? "y" : "x"; //note: in Chrome, right-clicking (for a context menu) fires onPress and it doesn't have the event.which set properly, so we must look for event.ctrlKey. If the user wants to allow context menus we should of course sense it here and not allow native touch scrolling.
1663
1664 isPreventingDefault = !allowNativeTouchScrolling && !self.allowEventDefault;
1665
1666 if (isPreventingDefault) {
1667 _preventDefault(e);
1668
1669 _addListener(_win, "touchforcechange", _preventDefault); //works around safari bug: https://greensock.com/forums/topic/21450-draggable-in-iframe-on-mobile-is-buggy/
1670
1671 }
1672
1673 if (e.changedTouches) {
1674 //touch events store the data slightly differently
1675 e = touch = e.changedTouches[0];
1676 touchID = e.identifier;
1677 } else if (e.pointerId) {
1678 touchID = e.pointerId; //for some Microsoft browsers
1679 } else {
1680 touch = touchID = null;
1681 }
1682
1683 _dragCount++;
1684
1685 _addToRenderQueue(render); //causes the Draggable to render on each "tick" of TweenLite.ticker (performance optimization - updating values in a mousemove can cause them to happen too frequently, like multiple times between frame redraws which is wasteful, and it also prevents values from updating properly in IE8)
1686
1687
1688 startPointerY = self.pointerY = e.pageY; //record the starting x and y so that we can calculate the movement from the original in _onMouseMove
1689
1690 startPointerX = self.pointerX = e.pageX;
1691
1692 _dispatchEvent(self, "pressInit", "onPressInit");
1693
1694 if (allowNativeTouchScrolling || self.autoScroll) {
1695 _recordMaxScrolls(target.parentNode);
1696 }
1697
1698 if (target.parentNode && self.autoScroll && !scrollProxy && !rotationMode && target.parentNode._gsMaxScrollX && !_placeholderDiv.parentNode && !target.getBBox) {
1699 //add a placeholder div to prevent the parent container from collapsing when the user drags the element left.
1700 _placeholderDiv.style.width = target.parentNode.scrollWidth + "px";
1701 target.parentNode.appendChild(_placeholderDiv);
1702 }
1703
1704 recordStartPositions();
1705 self.tween && self.tween.kill();
1706 self.isThrowing = false;
1707 gsap.killTweensOf(scrollProxy || target, killProps, true); //in case the user tries to drag it before the last tween is done.
1708
1709 scrollProxy && gsap.killTweensOf(target, {
1710 scrollTo: 1
1711 }, true); //just in case the original target's scroll position is being tweened somewhere else.
1712
1713 self.tween = self.lockedAxis = null;
1714
1715 if (vars.zIndexBoost || !rotationMode && !scrollProxy && vars.zIndexBoost !== false) {
1716 target.style.zIndex = Draggable.zIndex++;
1717 }
1718
1719 self.isPressed = true;
1720 hasDragCallback = !!(vars.onDrag || self._listeners.drag);
1721 hasMoveCallback = !!(vars.onMove || self._listeners.move);
1722
1723 if (vars.cursor !== false || vars.activeCursor) {
1724 i = triggers.length;
1725
1726 while (--i > -1) {
1727 gsap.set(triggers[i], {
1728 cursor: vars.activeCursor || vars.cursor || (_defaultCursor === "grab" ? "grabbing" : _defaultCursor)
1729 });
1730 }
1731 }
1732
1733 _dispatchEvent(self, "press", "onPress");
1734 },
1735 //called every time the mouse/touch moves
1736 onMove = function onMove(e) {
1737 var originalEvent = e,
1738 touches,
1739 pointerX,
1740 pointerY,
1741 i,
1742 dx,
1743 dy;
1744
1745 if (!enabled || _isMultiTouching || !self.isPressed || !e) {
1746 isPreventingDefault && e && enabled && _preventDefault(e); // in some browsers, we must listen for multiple event types like touchmove, pointermove, mousemove. The first time this function is called, we record whether or not we _preventDefault() so that on duplicate calls, we can do the same if necessary.
1747
1748 return;
1749 }
1750
1751 self.pointerEvent = e;
1752 touches = e.changedTouches;
1753
1754 if (touches) {
1755 //touch events store the data slightly differently
1756 e = touches[0];
1757
1758 if (e !== touch && e.identifier !== touchID) {
1759 //Usually changedTouches[0] will be what we're looking for, but in case it's not, look through the rest of the array...(and Android browsers don't reuse the event like iOS)
1760 i = touches.length;
1761
1762 while (--i > -1 && (e = touches[i]).identifier !== touchID && e.target !== target) {} // Some Android devices dispatch a touchstart AND pointerdown initially, and then only pointermove thus the touchID may not match because it was grabbed from the touchstart event whereas the pointer event is the one that the browser dispatches for move, so if the event target matches this Draggable's target, let it through.
1763
1764
1765 if (i < 0) {
1766 return;
1767 }
1768 }
1769 } else if (e.pointerId && touchID && e.pointerId !== touchID) {
1770 //for some Microsoft browsers, we must attach the listener to the doc rather than the trigger so that when the finger moves outside the bounds of the trigger, things still work. So if the event we're receiving has a pointerId that doesn't match the touchID, ignore it (for multi-touch)
1771 return;
1772 }
1773
1774 if (touchEventTarget && allowNativeTouchScrolling && !touchDragAxis) {
1775 //Android browsers force us to decide on the first "touchmove" event if we should allow the default (scrolling) behavior or preventDefault(). Otherwise, a "touchcancel" will be fired and then no "touchmove" or "touchend" will fire during the scrolling (no good).
1776 _point1.x = e.pageX - (isFixed ? _getDocScrollLeft(ownerDoc) : 0);
1777 _point1.y = e.pageY - (isFixed ? _getDocScrollTop(ownerDoc) : 0);
1778 matrix && matrix.apply(_point1, _point1);
1779 pointerX = _point1.x;
1780 pointerY = _point1.y;
1781 dx = Math.abs(pointerX - startPointerX);
1782 dy = Math.abs(pointerY - startPointerY);
1783
1784 if (dx !== dy && (dx > minimumMovement || dy > minimumMovement) || _isAndroid && allowNativeTouchScrolling === touchDragAxis) {
1785 touchDragAxis = dx > dy && allowX ? "x" : "y";
1786
1787 if (allowNativeTouchScrolling && touchDragAxis !== allowNativeTouchScrolling) {
1788 _addListener(_win, "touchforcechange", _preventDefault); // prevents native touch scrolling from taking over if the user started dragging in the other direction in iOS Safari
1789
1790 }
1791
1792 if (self.vars.lockAxisOnTouchScroll !== false && allowX && allowY) {
1793 self.lockedAxis = touchDragAxis === "x" ? "y" : "x";
1794 _isFunction(self.vars.onLockAxis) && self.vars.onLockAxis.call(self, originalEvent);
1795 }
1796
1797 if (_isAndroid && allowNativeTouchScrolling === touchDragAxis) {
1798 onRelease(originalEvent);
1799 return;
1800 }
1801 }
1802 }
1803
1804 if (!self.allowEventDefault && (!allowNativeTouchScrolling || touchDragAxis && allowNativeTouchScrolling !== touchDragAxis) && originalEvent.cancelable !== false) {
1805 _preventDefault(originalEvent);
1806
1807 isPreventingDefault = true;
1808 } else if (isPreventingDefault) {
1809 isPreventingDefault = false;
1810 }
1811
1812 if (self.autoScroll) {
1813 checkAutoScrollBounds = true;
1814 }
1815
1816 setPointerPosition(e.pageX, e.pageY, hasMoveCallback);
1817 },
1818 setPointerPosition = function setPointerPosition(pointerX, pointerY, invokeOnMove) {
1819 var dragTolerance = 1 - self.dragResistance,
1820 edgeTolerance = 1 - self.edgeResistance,
1821 prevPointerX = self.pointerX,
1822 prevPointerY = self.pointerY,
1823 prevStartElementY = startElementY,
1824 prevX = self.x,
1825 prevY = self.y,
1826 prevEndX = self.endX,
1827 prevEndY = self.endY,
1828 prevEndRotation = self.endRotation,
1829 prevDirty = dirty,
1830 xChange,
1831 yChange,
1832 x,
1833 y,
1834 dif,
1835 temp;
1836 self.pointerX = pointerX;
1837 self.pointerY = pointerY;
1838
1839 if (isFixed) {
1840 pointerX -= _getDocScrollLeft(ownerDoc);
1841 pointerY -= _getDocScrollTop(ownerDoc);
1842 }
1843
1844 if (rotationMode) {
1845 y = Math.atan2(rotationOrigin.y - pointerY, pointerX - rotationOrigin.x) * _RAD2DEG;
1846 dif = self.y - y;
1847
1848 if (dif > 180) {
1849 startElementY -= 360;
1850 self.y = y;
1851 } else if (dif < -180) {
1852 startElementY += 360;
1853 self.y = y;
1854 }
1855
1856 if (self.x !== startElementX || Math.abs(startElementY - y) > minimumMovement) {
1857 self.y = y;
1858 x = startElementX + (startElementY - y) * dragTolerance;
1859 } else {
1860 x = startElementX;
1861 }
1862 } else {
1863 if (matrix) {
1864 temp = pointerX * matrix.a + pointerY * matrix.c + matrix.e;
1865 pointerY = pointerX * matrix.b + pointerY * matrix.d + matrix.f;
1866 pointerX = temp;
1867 }
1868
1869 yChange = pointerY - startPointerY;
1870 xChange = pointerX - startPointerX;
1871
1872 if (yChange < minimumMovement && yChange > -minimumMovement) {
1873 yChange = 0;
1874 }
1875
1876 if (xChange < minimumMovement && xChange > -minimumMovement) {
1877 xChange = 0;
1878 }
1879
1880 if ((self.lockAxis || self.lockedAxis) && (xChange || yChange)) {
1881 temp = self.lockedAxis;
1882
1883 if (!temp) {
1884 self.lockedAxis = temp = allowX && Math.abs(xChange) > Math.abs(yChange) ? "y" : allowY ? "x" : null;
1885
1886 if (temp && _isFunction(self.vars.onLockAxis)) {
1887 self.vars.onLockAxis.call(self, self.pointerEvent);
1888 }
1889 }
1890
1891 if (temp === "y") {
1892 yChange = 0;
1893 } else if (temp === "x") {
1894 xChange = 0;
1895 }
1896 }
1897
1898 x = _round(startElementX + xChange * dragTolerance);
1899 y = _round(startElementY + yChange * dragTolerance);
1900 }
1901
1902 if ((snapX || snapY || snapXY) && (self.x !== x || self.y !== y && !rotationMode)) {
1903 if (snapXY) {
1904 _temp1.x = x;
1905 _temp1.y = y;
1906 temp = snapXY(_temp1);
1907 x = _round(temp.x);
1908 y = _round(temp.y);
1909 }
1910
1911 if (snapX) {
1912 x = _round(snapX(x));
1913 }
1914
1915 if (snapY) {
1916 y = _round(snapY(y));
1917 }
1918 }
1919
1920 if (hasBounds) {
1921 if (x > maxX) {
1922 x = maxX + Math.round((x - maxX) * edgeTolerance);
1923 } else if (x < minX) {
1924 x = minX + Math.round((x - minX) * edgeTolerance);
1925 }
1926
1927 if (!rotationMode) {
1928 if (y > maxY) {
1929 y = Math.round(maxY + (y - maxY) * edgeTolerance);
1930 } else if (y < minY) {
1931 y = Math.round(minY + (y - minY) * edgeTolerance);
1932 }
1933 }
1934 }
1935
1936 if (self.x !== x || self.y !== y && !rotationMode) {
1937 if (rotationMode) {
1938 self.endRotation = self.x = self.endX = x;
1939 dirty = true;
1940 } else {
1941 if (allowY) {
1942 self.y = self.endY = y;
1943 dirty = true; //a flag that indicates we need to render the target next time the TweenLite.ticker dispatches a "tick" event (typically on a requestAnimationFrame) - this is a performance optimization (we shouldn't render on every move because sometimes many move events can get dispatched between screen refreshes, and that'd be wasteful to render every time)
1944 }
1945
1946 if (allowX) {
1947 self.x = self.endX = x;
1948 dirty = true;
1949 }
1950 }
1951
1952 if (!invokeOnMove || _dispatchEvent(self, "move", "onMove") !== false) {
1953 if (!self.isDragging && self.isPressed) {
1954 self.isDragging = true;
1955
1956 _dispatchEvent(self, "dragstart", "onDragStart");
1957 }
1958 } else {
1959 //revert because the onMove returned false!
1960 self.pointerX = prevPointerX;
1961 self.pointerY = prevPointerY;
1962 startElementY = prevStartElementY;
1963 self.x = prevX;
1964 self.y = prevY;
1965 self.endX = prevEndX;
1966 self.endY = prevEndY;
1967 self.endRotation = prevEndRotation;
1968 dirty = prevDirty;
1969 }
1970 }
1971 },
1972 //called when the mouse/touch is released
1973 onRelease = function onRelease(e, force) {
1974 if (!enabled || !self.isPressed || e && touchID != null && !force && (e.pointerId && e.pointerId !== touchID && e.target !== target || e.changedTouches && !_hasTouchID(e.changedTouches, touchID))) {
1975 //for some Microsoft browsers, we must attach the listener to the doc rather than the trigger so that when the finger moves outside the bounds of the trigger, things still work. So if the event we're receiving has a pointerId that doesn't match the touchID, ignore it (for multi-touch)
1976 isPreventingDefault && e && enabled && _preventDefault(e); // in some browsers, we must listen for multiple event types like touchend, pointerup, mouseup. The first time this function is called, we record whether or not we _preventDefault() so that on duplicate calls, we can do the same if necessary.
1977
1978 return;
1979 }
1980
1981 self.isPressed = false;
1982 var originalEvent = e,
1983 wasDragging = self.isDragging,
1984 isContextMenuRelease = self.vars.allowContextMenu && e && (e.ctrlKey || e.which > 2),
1985 placeholderDelayedCall = gsap.delayedCall(0.001, removePlaceholder),
1986 touches,
1987 i,
1988 syntheticEvent,
1989 eventTarget,
1990 syntheticClick;
1991
1992 if (touchEventTarget) {
1993 _removeListener(touchEventTarget, "touchend", onRelease);
1994
1995 _removeListener(touchEventTarget, "touchmove", onMove);
1996
1997 _removeListener(touchEventTarget, "touchcancel", onRelease);
1998
1999 _removeListener(ownerDoc, "touchstart", _onMultiTouchDocument);
2000 } else {
2001 _removeListener(ownerDoc, "mousemove", onMove);
2002 }
2003
2004 _removeListener(_win, "touchforcechange", _preventDefault);
2005
2006 if (!_supportsPointer || !touchEventTarget) {
2007 _removeListener(ownerDoc, "mouseup", onRelease);
2008
2009 e && e.target && _removeListener(e.target, "mouseup", onRelease);
2010 }
2011
2012 dirty = false;
2013
2014 if (wasDragging) {
2015 dragEndTime = _lastDragTime = _getTime();
2016 self.isDragging = false;
2017 }
2018
2019 if (isClicking && !isContextMenuRelease) {
2020 if (e) {
2021 _removeListener(e.target, "change", onRelease);
2022
2023 self.pointerEvent = originalEvent;
2024 }
2025
2026 _setSelectable(triggers, false);
2027
2028 _dispatchEvent(self, "release", "onRelease");
2029
2030 _dispatchEvent(self, "click", "onClick");
2031
2032 isClicking = false;
2033 return;
2034 }
2035
2036 _removeFromRenderQueue(render);
2037
2038 i = triggers.length;
2039
2040 while (--i > -1) {
2041 _setStyle(triggers[i], "cursor", vars.cursor || (vars.cursor !== false ? _defaultCursor : null));
2042 }
2043
2044 _dragCount--;
2045
2046 if (e) {
2047 touches = e.changedTouches;
2048
2049 if (touches) {
2050 //touch events store the data slightly differently
2051 e = touches[0];
2052
2053 if (e !== touch && e.identifier !== touchID) {
2054 //Usually changedTouches[0] will be what we're looking for, but in case it's not, look through the rest of the array...(and Android browsers don't reuse the event like iOS)
2055 i = touches.length;
2056
2057 while (--i > -1 && (e = touches[i]).identifier !== touchID && e.target !== target) {}
2058
2059 if (i < 0) {
2060 return;
2061 }
2062 }
2063 }
2064
2065 self.pointerEvent = originalEvent;
2066 self.pointerX = e.pageX;
2067 self.pointerY = e.pageY;
2068 }
2069
2070 if (isContextMenuRelease && originalEvent) {
2071 _preventDefault(originalEvent);
2072
2073 isPreventingDefault = true;
2074
2075 _dispatchEvent(self, "release", "onRelease");
2076 } else if (originalEvent && !wasDragging) {
2077 isPreventingDefault = false;
2078
2079 if (interrupted && (vars.snap || vars.bounds)) {
2080 //otherwise, if the user clicks on the object while it's animating to a snapped position, and then releases without moving 3 pixels, it will just stay there (it should animate/snap)
2081 animate(vars.inertia || vars.throwProps);
2082 }
2083
2084 _dispatchEvent(self, "release", "onRelease");
2085
2086 if ((!_isAndroid || originalEvent.type !== "touchmove") && originalEvent.type.indexOf("cancel") === -1) {
2087 //to accommodate native scrolling on Android devices, we have to immediately call onRelease() on the first touchmove event, but that shouldn't trigger a "click".
2088 _dispatchEvent(self, "click", "onClick");
2089
2090 if (_getTime() - clickTime < 300) {
2091 _dispatchEvent(self, "doubleclick", "onDoubleClick");
2092 }
2093
2094 eventTarget = originalEvent.target || target; //old IE uses srcElement
2095
2096 clickTime = _getTime();
2097
2098 syntheticClick = function syntheticClick() {
2099 // some browsers (like Firefox) won't trust script-generated clicks, so if the user tries to click on a video to play it, for example, it simply won't work. Since a regular "click" event will most likely be generated anyway (one that has its isTrusted flag set to true), we must slightly delay our script-generated click so that the "real"/trusted one is prioritized. Remember, when there are duplicate events in quick succession, we suppress all but the first one. Some browsers don't even trigger the "real" one at all, so our synthetic one is a safety valve that ensures that no matter what, a click event does get dispatched.
2100 if (clickTime !== clickDispatch && self.enabled() && !self.isPressed && !originalEvent.defaultPrevented) {
2101 if (eventTarget.click) {
2102 //some browsers (like mobile Safari) don't properly trigger the click event
2103 eventTarget.click();
2104 } else if (ownerDoc.createEvent) {
2105 syntheticEvent = ownerDoc.createEvent("MouseEvents");
2106 syntheticEvent.initMouseEvent("click", true, true, _win, 1, self.pointerEvent.screenX, self.pointerEvent.screenY, self.pointerX, self.pointerY, false, false, false, false, 0, null);
2107 eventTarget.dispatchEvent(syntheticEvent);
2108 }
2109 }
2110 };
2111
2112 if (!_isAndroid && !originalEvent.defaultPrevented) {
2113 //iOS Safari requires the synthetic click to happen immediately or else it simply won't work, but Android doesn't play nice.
2114 gsap.delayedCall(0.05, syntheticClick); //in addition to the iOS bug workaround, there's a Firefox issue with clicking on things like a video to play, so we must fake a click event in a slightly delayed fashion. Previously, we listened for the "click" event with "capture" false which solved the video-click-to-play issue, but it would allow the "click" event to be dispatched twice like if you were using a jQuery.click() because that was handled in the capture phase, thus we had to switch to the capture phase to avoid the double-dispatching, but do the delayed synthetic click. Don't fire it too fast (like 0.00001) because we want to give the native event a chance to fire first as it's "trusted".
2115 }
2116 }
2117 } else {
2118 animate(vars.inertia || vars.throwProps); //will skip if inertia/throwProps isn't defined or InertiaPlugin isn't loaded.
2119
2120 if (!self.allowEventDefault && originalEvent && (vars.dragClickables !== false || !isClickable.call(self, originalEvent.target)) && wasDragging && (!allowNativeTouchScrolling || touchDragAxis && allowNativeTouchScrolling === touchDragAxis) && originalEvent.cancelable !== false) {
2121 isPreventingDefault = true;
2122
2123 _preventDefault(originalEvent);
2124 } else {
2125 isPreventingDefault = false;
2126 }
2127
2128 _dispatchEvent(self, "release", "onRelease");
2129 }
2130
2131 isTweening() && placeholderDelayedCall.duration(self.tween.duration()); //sync the timing so that the placeholder DIV gets
2132
2133 wasDragging && _dispatchEvent(self, "dragend", "onDragEnd");
2134 return true;
2135 },
2136 updateScroll = function updateScroll(e) {
2137 if (e && self.isDragging && !scrollProxy) {
2138 var parent = e.target || target.parentNode,
2139 deltaX = parent.scrollLeft - parent._gsScrollX,
2140 deltaY = parent.scrollTop - parent._gsScrollY;
2141
2142 if (deltaX || deltaY) {
2143 if (matrix) {
2144 startPointerX -= deltaX * matrix.a + deltaY * matrix.c;
2145 startPointerY -= deltaY * matrix.d + deltaX * matrix.b;
2146 } else {
2147 startPointerX -= deltaX;
2148 startPointerY -= deltaY;
2149 }
2150
2151 parent._gsScrollX += deltaX;
2152 parent._gsScrollY += deltaY;
2153 setPointerPosition(self.pointerX, self.pointerY);
2154 }
2155 }
2156 },
2157 onClick = function onClick(e) {
2158 //this was a huge pain in the neck to align all the various browsers and their behaviors. Chrome, Firefox, Safari, Opera, Android, and Microsoft Edge all handle events differently! Some will only trigger native behavior (like checkbox toggling) from trusted events. Others don't even support isTrusted, but require 2 events to flow through before triggering native behavior. Edge treats everything as trusted but also mandates that 2 flow through to trigger the correct native behavior.
2159 var time = _getTime(),
2160 recentlyClicked = time - clickTime < 100,
2161 recentlyDragged = time - dragEndTime < 50,
2162 alreadyDispatched = recentlyClicked && clickDispatch === clickTime,
2163 defaultPrevented = self.pointerEvent && self.pointerEvent.defaultPrevented,
2164 alreadyDispatchedTrusted = recentlyClicked && trustedClickDispatch === clickTime,
2165 trusted = e.isTrusted || e.isTrusted == null && recentlyClicked && alreadyDispatched; //note: Safari doesn't support isTrusted, and it won't properly execute native behavior (like toggling checkboxes) on the first synthetic "click" event - we must wait for the 2nd and treat it as trusted (but stop propagation at that point). Confusing, I know. Don't you love cross-browser compatibility challenges?
2166
2167
2168 if ((alreadyDispatched || recentlyDragged && self.vars.suppressClickOnDrag !== false) && e.stopImmediatePropagation) {
2169 e.stopImmediatePropagation();
2170 }
2171
2172 if (recentlyClicked && !(self.pointerEvent && self.pointerEvent.defaultPrevented) && (!alreadyDispatched || trusted && !alreadyDispatchedTrusted)) {
2173 //let the first click pass through unhindered. Let the next one only if it's trusted, then no more (stop quick-succession ones)
2174 if (trusted && alreadyDispatched) {
2175 trustedClickDispatch = clickTime;
2176 }
2177
2178 clickDispatch = clickTime;
2179 return;
2180 }
2181
2182 if (self.isPressed || recentlyDragged || recentlyClicked) {
2183 if (!trusted || !e.detail || !recentlyClicked || defaultPrevented) {
2184 _preventDefault(e);
2185 }
2186 }
2187
2188 if (!recentlyClicked && !recentlyDragged) {
2189 // for script-triggered event dispatches, like element.click()
2190 e && e.target && (self.pointerEvent = e);
2191
2192 _dispatchEvent(self, "click", "onClick");
2193 }
2194 },
2195 localizePoint = function localizePoint(p) {
2196 return matrix ? {
2197 x: p.x * matrix.a + p.y * matrix.c + matrix.e,
2198 y: p.x * matrix.b + p.y * matrix.d + matrix.f
2199 } : {
2200 x: p.x,
2201 y: p.y
2202 };
2203 };
2204
2205 old = Draggable.get(target);
2206 old && old.kill(); // avoids duplicates (an element can only be controlled by one Draggable)
2207 //give the user access to start/stop dragging...
2208
2209 _this2.startDrag = function (event, align) {
2210 var r1, r2, p1, p2;
2211 onPress(event || self.pointerEvent, true); //if the pointer isn't on top of the element, adjust things accordingly
2212
2213 if (align && !self.hitTest(event || self.pointerEvent)) {
2214 r1 = _parseRect(event || self.pointerEvent);
2215 r2 = _parseRect(target);
2216 p1 = localizePoint({
2217 x: r1.left + r1.width / 2,
2218 y: r1.top + r1.height / 2
2219 });
2220 p2 = localizePoint({
2221 x: r2.left + r2.width / 2,
2222 y: r2.top + r2.height / 2
2223 });
2224 startPointerX -= p1.x - p2.x;
2225 startPointerY -= p1.y - p2.y;
2226 }
2227
2228 if (!self.isDragging) {
2229 self.isDragging = true;
2230
2231 _dispatchEvent(self, "dragstart", "onDragStart");
2232 }
2233 };
2234
2235 _this2.drag = onMove;
2236
2237 _this2.endDrag = function (e) {
2238 return onRelease(e || self.pointerEvent, true);
2239 };
2240
2241 _this2.timeSinceDrag = function () {
2242 return self.isDragging ? 0 : (_getTime() - dragEndTime) / 1000;
2243 };
2244
2245 _this2.timeSinceClick = function () {
2246 return (_getTime() - clickTime) / 1000;
2247 };
2248
2249 _this2.hitTest = function (target, threshold) {
2250 return Draggable.hitTest(self.target, target, threshold);
2251 };
2252
2253 _this2.getDirection = function (from, diagonalThreshold) {
2254 //from can be "start" (default), "velocity", or an element
2255 var mode = from === "velocity" && InertiaPlugin ? from : _isObject(from) && !rotationMode ? "element" : "start",
2256 xChange,
2257 yChange,
2258 ratio,
2259 direction,
2260 r1,
2261 r2;
2262
2263 if (mode === "element") {
2264 r1 = _parseRect(self.target);
2265 r2 = _parseRect(from);
2266 }
2267
2268 xChange = mode === "start" ? self.x - startElementX : mode === "velocity" ? InertiaPlugin.getVelocity(target, xProp) : r1.left + r1.width / 2 - (r2.left + r2.width / 2);
2269
2270 if (rotationMode) {
2271 return xChange < 0 ? "counter-clockwise" : "clockwise";
2272 } else {
2273 diagonalThreshold = diagonalThreshold || 2;
2274 yChange = mode === "start" ? self.y - startElementY : mode === "velocity" ? InertiaPlugin.getVelocity(target, yProp) : r1.top + r1.height / 2 - (r2.top + r2.height / 2);
2275 ratio = Math.abs(xChange / yChange);
2276 direction = ratio < 1 / diagonalThreshold ? "" : xChange < 0 ? "left" : "right";
2277
2278 if (ratio < diagonalThreshold) {
2279 if (direction !== "") {
2280 direction += "-";
2281 }
2282
2283 direction += yChange < 0 ? "up" : "down";
2284 }
2285 }
2286
2287 return direction;
2288 };
2289
2290 _this2.applyBounds = function (newBounds, sticky) {
2291 var x, y, forceZeroVelocity, e, parent, isRoot;
2292
2293 if (newBounds && vars.bounds !== newBounds) {
2294 vars.bounds = newBounds;
2295 return self.update(true, sticky);
2296 }
2297
2298 syncXY(true);
2299 calculateBounds();
2300
2301 if (hasBounds && !isTweening()) {
2302 x = self.x;
2303 y = self.y;
2304
2305 if (x > maxX) {
2306 x = maxX;
2307 } else if (x < minX) {
2308 x = minX;
2309 }
2310
2311 if (y > maxY) {
2312 y = maxY;
2313 } else if (y < minY) {
2314 y = minY;
2315 }
2316
2317 if (self.x !== x || self.y !== y) {
2318 forceZeroVelocity = true;
2319 self.x = self.endX = x;
2320
2321 if (rotationMode) {
2322 self.endRotation = x;
2323 } else {
2324 self.y = self.endY = y;
2325 }
2326
2327 dirty = true;
2328 render(true);
2329
2330 if (self.autoScroll && !self.isDragging) {
2331 _recordMaxScrolls(target.parentNode);
2332
2333 e = target;
2334 _windowProxy.scrollTop = _win.pageYOffset != null ? _win.pageYOffset : ownerDoc.documentElement.scrollTop != null ? ownerDoc.documentElement.scrollTop : ownerDoc.body.scrollTop;
2335 _windowProxy.scrollLeft = _win.pageXOffset != null ? _win.pageXOffset : ownerDoc.documentElement.scrollLeft != null ? ownerDoc.documentElement.scrollLeft : ownerDoc.body.scrollLeft;
2336
2337 while (e && !isRoot) {
2338 //walk up the chain and sense wherever the scrollTop/scrollLeft exceeds the maximum.
2339 isRoot = _isRoot(e.parentNode);
2340 parent = isRoot ? _windowProxy : e.parentNode;
2341
2342 if (allowY && parent.scrollTop > parent._gsMaxScrollY) {
2343 parent.scrollTop = parent._gsMaxScrollY;
2344 }
2345
2346 if (allowX && parent.scrollLeft > parent._gsMaxScrollX) {
2347 parent.scrollLeft = parent._gsMaxScrollX;
2348 }
2349
2350 e = parent;
2351 }
2352 }
2353 }
2354
2355 if (self.isThrowing && (forceZeroVelocity || self.endX > maxX || self.endX < minX || self.endY > maxY || self.endY < minY)) {
2356 animate(vars.inertia || vars.throwProps, forceZeroVelocity);
2357 }
2358 }
2359
2360 return self;
2361 };
2362
2363 _this2.update = function (applyBounds, sticky, ignoreExternalChanges) {
2364 if (sticky && self.isPressed) {
2365 // in case the element was repositioned in the document flow, thus its x/y may be identical but its position is actually quite different.
2366 var m = getGlobalMatrix(target),
2367 p = innerMatrix.apply({
2368 x: self.x - startElementX,
2369 y: self.y - startElementY
2370 }),
2371 m2 = getGlobalMatrix(target.parentNode, true);
2372 m2.apply({
2373 x: m.e - p.x,
2374 y: m.f - p.y
2375 }, p);
2376 self.x -= p.x - m2.e;
2377 self.y -= p.y - m2.f;
2378 render(true);
2379 recordStartPositions();
2380 }
2381
2382 var x = self.x,
2383 y = self.y;
2384 updateMatrix(!sticky);
2385
2386 if (applyBounds) {
2387 self.applyBounds();
2388 } else {
2389 dirty && ignoreExternalChanges && render(true);
2390 syncXY(true);
2391 }
2392
2393 if (sticky) {
2394 setPointerPosition(self.pointerX, self.pointerY);
2395 dirty && render(true);
2396 }
2397
2398 if (self.isPressed && !sticky && (allowX && Math.abs(x - self.x) > 0.01 || allowY && Math.abs(y - self.y) > 0.01 && !rotationMode)) {
2399 recordStartPositions();
2400 }
2401
2402 if (self.autoScroll) {
2403 _recordMaxScrolls(target.parentNode, self.isDragging);
2404
2405 checkAutoScrollBounds = self.isDragging;
2406 render(true); //in case reparenting occurred.
2407
2408 _removeScrollListener(target, updateScroll);
2409
2410 _addScrollListener(target, updateScroll);
2411 }
2412
2413 return self;
2414 };
2415
2416 _this2.enable = function (type) {
2417 var setVars = {
2418 lazy: true
2419 },
2420 id,
2421 i,
2422 trigger;
2423
2424 if (vars.cursor !== false) {
2425 setVars.cursor = vars.cursor || _defaultCursor;
2426 }
2427
2428 if (gsap.utils.checkPrefix("touchCallout")) {
2429 setVars.touchCallout = "none";
2430 }
2431
2432 if (type !== "soft") {
2433 _setTouchActionForAllDescendants(triggers, allowX === allowY ? "none" : vars.allowNativeTouchScrolling && target.scrollHeight === target.clientHeight === (target.scrollWidth === target.clientHeight) || vars.allowEventDefault ? "manipulation" : allowX ? "pan-y" : "pan-x"); // Some browsers like Internet Explorer will fire a pointercancel event when the user attempts to drag when touchAction is "manipulate" because it's perceived as a pan. If the element has scrollable content in only one direction, we should use pan-x or pan-y accordingly so that the pointercancel doesn't prevent dragging.
2434
2435
2436 i = triggers.length;
2437
2438 while (--i > -1) {
2439 trigger = triggers[i];
2440 _supportsPointer || _addListener(trigger, "mousedown", onPress);
2441
2442 _addListener(trigger, "touchstart", onPress);
2443
2444 _addListener(trigger, "click", onClick, true); //note: used to pass true for capture but it prevented click-to-play-video functionality in Firefox.
2445
2446
2447 gsap.set(trigger, setVars);
2448
2449 if (trigger.getBBox && trigger.ownerSVGElement) {
2450 // a bug in chrome doesn't respect touch-action on SVG elements - it only works if we set it on the parent SVG.
2451 gsap.set(trigger.ownerSVGElement, {
2452 touchAction: allowX === allowY ? "none" : vars.allowNativeTouchScrolling || vars.allowEventDefault ? "manipulation" : allowX ? "pan-y" : "pan-x"
2453 });
2454 }
2455
2456 vars.allowContextMenu || _addListener(trigger, "contextmenu", onContextMenu);
2457 }
2458
2459 _setSelectable(triggers, false);
2460 }
2461
2462 _addScrollListener(target, updateScroll);
2463
2464 enabled = true;
2465
2466 if (InertiaPlugin && type !== "soft") {
2467 InertiaPlugin.track(scrollProxy || target, xyMode ? "x,y" : rotationMode ? "rotation" : "top,left");
2468 }
2469
2470 target._gsDragID = id = "d" + _lookupCount++;
2471 _lookup[id] = self;
2472
2473 if (scrollProxy) {
2474 scrollProxy.enable();
2475 scrollProxy.element._gsDragID = id;
2476 }
2477
2478 (vars.bounds || rotationMode) && recordStartPositions();
2479 vars.bounds && self.applyBounds();
2480 return self;
2481 };
2482
2483 _this2.disable = function (type) {
2484 var dragging = self.isDragging,
2485 i = triggers.length,
2486 trigger;
2487
2488 while (--i > -1) {
2489 _setStyle(triggers[i], "cursor", null);
2490 }
2491
2492 if (type !== "soft") {
2493 _setTouchActionForAllDescendants(triggers, null);
2494
2495 i = triggers.length;
2496
2497 while (--i > -1) {
2498 trigger = triggers[i];
2499
2500 _setStyle(trigger, "touchCallout", null);
2501
2502 _removeListener(trigger, "mousedown", onPress);
2503
2504 _removeListener(trigger, "touchstart", onPress);
2505
2506 _removeListener(trigger, "click", onClick);
2507
2508 _removeListener(trigger, "contextmenu", onContextMenu);
2509 }
2510
2511 _setSelectable(triggers, true);
2512
2513 if (touchEventTarget) {
2514 _removeListener(touchEventTarget, "touchcancel", onRelease);
2515
2516 _removeListener(touchEventTarget, "touchend", onRelease);
2517
2518 _removeListener(touchEventTarget, "touchmove", onMove);
2519 }
2520
2521 _removeListener(ownerDoc, "mouseup", onRelease);
2522
2523 _removeListener(ownerDoc, "mousemove", onMove);
2524 }
2525
2526 _removeScrollListener(target, updateScroll);
2527
2528 enabled = false;
2529 InertiaPlugin && type !== "soft" && InertiaPlugin.untrack(scrollProxy || target, xyMode ? "x,y" : rotationMode ? "rotation" : "top,left");
2530 scrollProxy && scrollProxy.disable();
2531
2532 _removeFromRenderQueue(render);
2533
2534 self.isDragging = self.isPressed = isClicking = false;
2535 dragging && _dispatchEvent(self, "dragend", "onDragEnd");
2536 return self;
2537 };
2538
2539 _this2.enabled = function (value, type) {
2540 return arguments.length ? value ? self.enable(type) : self.disable(type) : enabled;
2541 };
2542
2543 _this2.kill = function () {
2544 self.isThrowing = false;
2545 self.tween && self.tween.kill();
2546 self.disable();
2547 gsap.set(triggers, {
2548 clearProps: "userSelect"
2549 });
2550 delete _lookup[target._gsDragID];
2551 return self;
2552 };
2553
2554 if (~type.indexOf("scroll")) {
2555 scrollProxy = _this2.scrollProxy = new ScrollProxy(target, _extend({
2556 onKill: function onKill() {
2557 //ScrollProxy's onKill() gets called if/when the ScrollProxy senses that the user interacted with the scroll position manually (like using the scrollbar). IE9 doesn't fire the "mouseup" properly when users drag the scrollbar of an element, so this works around that issue.
2558 self.isPressed && onRelease(null);
2559 }
2560 }, vars)); //a bug in many Android devices' stock browser causes scrollTop to get forced back to 0 after it is altered via JS, so we set overflow to "hidden" on mobile/touch devices (they hide the scroll bar anyway). That works around the bug. (This bug is discussed at https://code.google.com/p/android/issues/detail?id=19625)
2561
2562 target.style.overflowY = allowY && !_isTouchDevice ? "auto" : "hidden";
2563 target.style.overflowX = allowX && !_isTouchDevice ? "auto" : "hidden";
2564 target = scrollProxy.content;
2565 }
2566
2567 if (rotationMode) {
2568 killProps.rotation = 1;
2569 } else {
2570 if (allowX) {
2571 killProps[xProp] = 1;
2572 }
2573
2574 if (allowY) {
2575 killProps[yProp] = 1;
2576 }
2577 }
2578
2579 gsCache.force3D = "force3D" in vars ? vars.force3D : true; //otherwise, normal dragging would be in 2D and then as soon as it's released and there's an inertia tween, it'd jump to 3D which can create an initial jump due to the work the browser must to do layerize it.
2580
2581 _this2.enable();
2582
2583 return _this2;
2584 }
2585
2586 Draggable.register = function register(core) {
2587 gsap = core;
2588
2589 _initCore();
2590 };
2591
2592 Draggable.create = function create(targets, vars) {
2593 _coreInitted || _initCore(true);
2594 return _toArray(targets).map(function (target) {
2595 return new Draggable(target, vars);
2596 });
2597 };
2598
2599 Draggable.get = function get(target) {
2600 return _lookup[(_toArray(target)[0] || {})._gsDragID];
2601 };
2602
2603 Draggable.timeSinceDrag = function timeSinceDrag() {
2604 return (_getTime() - _lastDragTime) / 1000;
2605 };
2606
2607 Draggable.hitTest = function hitTest(obj1, obj2, threshold) {
2608 if (obj1 === obj2) {
2609 return false;
2610 }
2611
2612 var r1 = _parseRect(obj1),
2613 r2 = _parseRect(obj2),
2614 top = r1.top,
2615 left = r1.left,
2616 right = r1.right,
2617 bottom = r1.bottom,
2618 width = r1.width,
2619 height = r1.height,
2620 isOutside = r2.left > right || r2.right < left || r2.top > bottom || r2.bottom < top,
2621 overlap,
2622 area,
2623 isRatio;
2624
2625 if (isOutside || !threshold) {
2626 return !isOutside;
2627 }
2628
2629 isRatio = (threshold + "").indexOf("%") !== -1;
2630 threshold = parseFloat(threshold) || 0;
2631 overlap = {
2632 left: Math.max(left, r2.left),
2633 top: Math.max(top, r2.top)
2634 };
2635 overlap.width = Math.min(right, r2.right) - overlap.left;
2636 overlap.height = Math.min(bottom, r2.bottom) - overlap.top;
2637
2638 if (overlap.width < 0 || overlap.height < 0) {
2639 return false;
2640 }
2641
2642 if (isRatio) {
2643 threshold *= 0.01;
2644 area = overlap.width * overlap.height;
2645 return area >= width * height * threshold || area >= r2.width * r2.height * threshold;
2646 }
2647
2648 return overlap.width > threshold && overlap.height > threshold;
2649 };
2650
2651 return Draggable;
2652}(EventDispatcher);
2653
2654_setDefaults(Draggable.prototype, {
2655 pointerX: 0,
2656 pointerY: 0,
2657 startX: 0,
2658 startY: 0,
2659 deltaX: 0,
2660 deltaY: 0,
2661 isDragging: false,
2662 isPressed: false
2663});
2664
2665Draggable.zIndex = 1000;
2666Draggable.version = "3.10.3";
2667_getGSAP() && gsap.registerPlugin(Draggable);
2668export { Draggable as default };
\No newline at end of file