interactjs
Version:
Drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)
1,467 lines (1,411 loc) • 254 kB
JavaScript
/**
* interact.js 1.10.27
*
* Copyright (c) 2012-present Taye Adeyemi <dev@taye.me>
* Released under the MIT License.
* https://raw.github.com/taye/interact.js/main/LICENSE
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.interact = factory());
})(this, (function () { 'use strict';
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
Object.defineProperty(subClass, "prototype", {
writable: false
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
} else if (call !== void 0) {
throw new TypeError("Derived constructors may only return object or undefined");
}
return _assertThisInitialized(self);
}
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
function _superPropBase(object, property) {
while (!Object.prototype.hasOwnProperty.call(object, property)) {
object = _getPrototypeOf(object);
if (object === null) break;
}
return object;
}
function _get() {
if (typeof Reflect !== "undefined" && Reflect.get) {
_get = Reflect.get.bind();
} else {
_get = function _get(target, property, receiver) {
var base = _superPropBase(target, property);
if (!base) return;
var desc = Object.getOwnPropertyDescriptor(base, property);
if (desc.get) {
return desc.get.call(arguments.length < 3 ? target : receiver);
}
return desc.value;
};
}
return _get.apply(this, arguments);
}
function _toPrimitive(input, hint) {
if (typeof input !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (typeof res !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return typeof key === "symbol" ? key : String(key);
}
var isWindow = (function (thing) {
return !!(thing && thing.Window) && thing instanceof thing.Window;
});
var realWindow = undefined;
var win = undefined;
function init$3(window) {
// get wrapped window if using Shadow DOM polyfill
realWindow = window;
// create a TextNode
var el = window.document.createTextNode('');
// check if it's wrapped by a polyfill
if (el.ownerDocument !== window.document && typeof window.wrap === 'function' && window.wrap(el) === el) {
// use wrapped window
window = window.wrap(window);
}
win = window;
}
if (typeof window !== 'undefined' && !!window) {
init$3(window);
}
function getWindow(node) {
if (isWindow(node)) {
return node;
}
var rootNode = node.ownerDocument || node;
return rootNode.defaultView || win.window;
}
var window$1 = function window(thing) {
return thing === win || isWindow(thing);
};
var docFrag = function docFrag(thing) {
return object(thing) && thing.nodeType === 11;
};
var object = function object(thing) {
return !!thing && _typeof(thing) === 'object';
};
var func = function func(thing) {
return typeof thing === 'function';
};
var number = function number(thing) {
return typeof thing === 'number';
};
var bool = function bool(thing) {
return typeof thing === 'boolean';
};
var string = function string(thing) {
return typeof thing === 'string';
};
var element = function element(thing) {
if (!thing || _typeof(thing) !== 'object') {
return false;
}
var _window = getWindow(thing) || win;
return /object|function/.test(typeof Element === "undefined" ? "undefined" : _typeof(Element)) ? thing instanceof Element || thing instanceof _window.Element : thing.nodeType === 1 && typeof thing.nodeName === 'string';
};
var plainObject = function plainObject(thing) {
return object(thing) && !!thing.constructor && /function Object\b/.test(thing.constructor.toString());
};
var array = function array(thing) {
return object(thing) && typeof thing.length !== 'undefined' && func(thing.splice);
};
var is = {
window: window$1,
docFrag: docFrag,
object: object,
func: func,
number: number,
bool: bool,
string: string,
element: element,
plainObject: plainObject,
array: array
};
function install$g(scope) {
var actions = scope.actions,
Interactable = scope.Interactable,
defaults = scope.defaults;
Interactable.prototype.draggable = drag.draggable;
actions.map.drag = drag;
actions.methodDict.drag = 'draggable';
defaults.actions.drag = drag.defaults;
}
function beforeMove(_ref) {
var interaction = _ref.interaction;
if (interaction.prepared.name !== 'drag') return;
var axis = interaction.prepared.axis;
if (axis === 'x') {
interaction.coords.cur.page.y = interaction.coords.start.page.y;
interaction.coords.cur.client.y = interaction.coords.start.client.y;
interaction.coords.velocity.client.y = 0;
interaction.coords.velocity.page.y = 0;
} else if (axis === 'y') {
interaction.coords.cur.page.x = interaction.coords.start.page.x;
interaction.coords.cur.client.x = interaction.coords.start.client.x;
interaction.coords.velocity.client.x = 0;
interaction.coords.velocity.page.x = 0;
}
}
function move$1(_ref2) {
var iEvent = _ref2.iEvent,
interaction = _ref2.interaction;
if (interaction.prepared.name !== 'drag') return;
var axis = interaction.prepared.axis;
if (axis === 'x' || axis === 'y') {
var opposite = axis === 'x' ? 'y' : 'x';
iEvent.page[opposite] = interaction.coords.start.page[opposite];
iEvent.client[opposite] = interaction.coords.start.client[opposite];
iEvent.delta[opposite] = 0;
}
}
var draggable = function draggable(options) {
if (is.object(options)) {
this.options.drag.enabled = options.enabled !== false;
this.setPerAction('drag', options);
this.setOnEvents('drag', options);
if (/^(xy|x|y|start)$/.test(options.lockAxis)) {
this.options.drag.lockAxis = options.lockAxis;
}
if (/^(xy|x|y)$/.test(options.startAxis)) {
this.options.drag.startAxis = options.startAxis;
}
return this;
}
if (is.bool(options)) {
this.options.drag.enabled = options;
return this;
}
return this.options.drag;
};
var drag = {
id: 'actions/drag',
install: install$g,
listeners: {
'interactions:before-action-move': beforeMove,
'interactions:action-resume': beforeMove,
// dragmove
'interactions:action-move': move$1,
'auto-start:check': function autoStartCheck(arg) {
var interaction = arg.interaction,
interactable = arg.interactable,
buttons = arg.buttons;
var dragOptions = interactable.options.drag;
if (!(dragOptions && dragOptions.enabled) ||
// check mouseButton setting if the pointer is down
interaction.pointerIsDown && /mouse|pointer/.test(interaction.pointerType) && (buttons & interactable.options.drag.mouseButtons) === 0) {
return undefined;
}
arg.action = {
name: 'drag',
axis: dragOptions.lockAxis === 'start' ? dragOptions.startAxis : dragOptions.lockAxis
};
return false;
}
},
draggable: draggable,
beforeMove: beforeMove,
move: move$1,
defaults: {
startAxis: 'xy',
lockAxis: 'xy'
},
getCursor: function getCursor() {
return 'move';
},
filterEventType: function filterEventType(type) {
return type.search('drag') === 0;
}
};
var drag$1 = drag;
var domObjects = {
init: init$2,
document: null,
DocumentFragment: null,
SVGElement: null,
SVGSVGElement: null,
SVGElementInstance: null,
Element: null,
HTMLElement: null,
Event: null,
Touch: null,
PointerEvent: null
};
function blank() {}
var domObjects$1 = domObjects;
function init$2(window) {
var win = window;
domObjects.document = win.document;
domObjects.DocumentFragment = win.DocumentFragment || blank;
domObjects.SVGElement = win.SVGElement || blank;
domObjects.SVGSVGElement = win.SVGSVGElement || blank;
domObjects.SVGElementInstance = win.SVGElementInstance || blank;
domObjects.Element = win.Element || blank;
domObjects.HTMLElement = win.HTMLElement || domObjects.Element;
domObjects.Event = win.Event;
domObjects.Touch = win.Touch || blank;
domObjects.PointerEvent = win.PointerEvent || win.MSPointerEvent;
}
var browser = {
init: init$1,
supportsTouch: null,
supportsPointerEvent: null,
isIOS7: null,
isIOS: null,
isIe9: null,
isOperaMobile: null,
prefixedMatchesSelector: null,
pEventTypes: null,
wheelEvent: null
};
function init$1(window) {
var Element = domObjects$1.Element;
var navigator = window.navigator || {};
// Does the browser support touch input?
browser.supportsTouch = 'ontouchstart' in window || is.func(window.DocumentTouch) && domObjects$1.document instanceof window.DocumentTouch;
// Does the browser support PointerEvents
// https://github.com/taye/interact.js/issues/703#issuecomment-471570492
browser.supportsPointerEvent = navigator.pointerEnabled !== false && !!domObjects$1.PointerEvent;
browser.isIOS = /iP(hone|od|ad)/.test(navigator.platform);
// scrolling doesn't change the result of getClientRects on iOS 7
browser.isIOS7 = /iP(hone|od|ad)/.test(navigator.platform) && /OS 7[^\d]/.test(navigator.appVersion);
browser.isIe9 = /MSIE 9/.test(navigator.userAgent);
// Opera Mobile must be handled differently
browser.isOperaMobile = navigator.appName === 'Opera' && browser.supportsTouch && /Presto/.test(navigator.userAgent);
// prefix matchesSelector
browser.prefixedMatchesSelector = 'matches' in Element.prototype ? 'matches' : 'webkitMatchesSelector' in Element.prototype ? 'webkitMatchesSelector' : 'mozMatchesSelector' in Element.prototype ? 'mozMatchesSelector' : 'oMatchesSelector' in Element.prototype ? 'oMatchesSelector' : 'msMatchesSelector';
browser.pEventTypes = browser.supportsPointerEvent ? domObjects$1.PointerEvent === window.MSPointerEvent ? {
up: 'MSPointerUp',
down: 'MSPointerDown',
over: 'mouseover',
out: 'mouseout',
move: 'MSPointerMove',
cancel: 'MSPointerCancel'
} : {
up: 'pointerup',
down: 'pointerdown',
over: 'pointerover',
out: 'pointerout',
move: 'pointermove',
cancel: 'pointercancel'
} : null;
// because Webkit and Opera still use 'mousewheel' event type
browser.wheelEvent = domObjects$1.document && 'onmousewheel' in domObjects$1.document ? 'mousewheel' : 'wheel';
}
var browser$1 = browser;
function nodeContains(parent, child) {
if (parent.contains) {
return parent.contains(child);
}
while (child) {
if (child === parent) {
return true;
}
child = child.parentNode;
}
return false;
}
function closest(element, selector) {
while (is.element(element)) {
if (matchesSelector(element, selector)) {
return element;
}
element = parentNode(element);
}
return null;
}
function parentNode(node) {
var parent = node.parentNode;
if (is.docFrag(parent)) {
// skip past #shado-root fragments
// tslint:disable-next-line
while ((parent = parent.host) && is.docFrag(parent)) {
continue;
}
return parent;
}
return parent;
}
function matchesSelector(element, selector) {
// remove /deep/ from selectors if shadowDOM polyfill is used
if (win !== realWindow) {
selector = selector.replace(/\/deep\//g, ' ');
}
return element[browser$1.prefixedMatchesSelector](selector);
}
var getParent = function getParent(el) {
return el.parentNode || el.host;
};
// Test for the element that's "above" all other qualifiers
function indexOfDeepestElement(elements) {
var deepestNodeParents = [];
var deepestNodeIndex;
for (var i = 0; i < elements.length; i++) {
var currentNode = elements[i];
var deepestNode = elements[deepestNodeIndex];
// node may appear in elements array multiple times
if (!currentNode || i === deepestNodeIndex) {
continue;
}
if (!deepestNode) {
deepestNodeIndex = i;
continue;
}
var currentNodeParent = getParent(currentNode);
var deepestNodeParent = getParent(deepestNode);
// check if the deepest or current are document.documentElement/rootElement
// - if the current node is, do nothing and continue
if (currentNodeParent === currentNode.ownerDocument) {
continue;
}
// - if deepest is, update with the current node and continue to next
else if (deepestNodeParent === currentNode.ownerDocument) {
deepestNodeIndex = i;
continue;
}
// compare zIndex of siblings
if (currentNodeParent === deepestNodeParent) {
if (zIndexIsHigherThan(currentNode, deepestNode)) {
deepestNodeIndex = i;
}
continue;
}
// populate the ancestry array for the latest deepest node
deepestNodeParents = deepestNodeParents.length ? deepestNodeParents : getNodeParents(deepestNode);
var ancestryStart = void 0;
// if the deepest node is an HTMLElement and the current node is a non root svg element
if (deepestNode instanceof domObjects$1.HTMLElement && currentNode instanceof domObjects$1.SVGElement && !(currentNode instanceof domObjects$1.SVGSVGElement)) {
// TODO: is this check necessary? Was this for HTML elements embedded in SVG?
if (currentNode === deepestNodeParent) {
continue;
}
ancestryStart = currentNode.ownerSVGElement;
} else {
ancestryStart = currentNode;
}
var currentNodeParents = getNodeParents(ancestryStart, deepestNode.ownerDocument);
var commonIndex = 0;
// get (position of closest common ancestor) + 1
while (currentNodeParents[commonIndex] && currentNodeParents[commonIndex] === deepestNodeParents[commonIndex]) {
commonIndex++;
}
var parents = [currentNodeParents[commonIndex - 1], currentNodeParents[commonIndex], deepestNodeParents[commonIndex]];
if (parents[0]) {
var child = parents[0].lastChild;
while (child) {
if (child === parents[1]) {
deepestNodeIndex = i;
deepestNodeParents = currentNodeParents;
break;
} else if (child === parents[2]) {
break;
}
child = child.previousSibling;
}
}
}
return deepestNodeIndex;
}
function getNodeParents(node, limit) {
var parents = [];
var parent = node;
var parentParent;
while ((parentParent = getParent(parent)) && parent !== limit && parentParent !== parent.ownerDocument) {
parents.unshift(parent);
parent = parentParent;
}
return parents;
}
function zIndexIsHigherThan(higherNode, lowerNode) {
var higherIndex = parseInt(getWindow(higherNode).getComputedStyle(higherNode).zIndex, 10) || 0;
var lowerIndex = parseInt(getWindow(lowerNode).getComputedStyle(lowerNode).zIndex, 10) || 0;
return higherIndex >= lowerIndex;
}
function matchesUpTo(element, selector, limit) {
while (is.element(element)) {
if (matchesSelector(element, selector)) {
return true;
}
element = parentNode(element);
if (element === limit) {
return matchesSelector(element, selector);
}
}
return false;
}
function getActualElement(element) {
return element.correspondingUseElement || element;
}
function getScrollXY(relevantWindow) {
relevantWindow = relevantWindow || win;
return {
x: relevantWindow.scrollX || relevantWindow.document.documentElement.scrollLeft,
y: relevantWindow.scrollY || relevantWindow.document.documentElement.scrollTop
};
}
function getElementClientRect(element) {
var clientRect = element instanceof domObjects$1.SVGElement ? element.getBoundingClientRect() : element.getClientRects()[0];
return clientRect && {
left: clientRect.left,
right: clientRect.right,
top: clientRect.top,
bottom: clientRect.bottom,
width: clientRect.width || clientRect.right - clientRect.left,
height: clientRect.height || clientRect.bottom - clientRect.top
};
}
function getElementRect(element) {
var clientRect = getElementClientRect(element);
if (!browser$1.isIOS7 && clientRect) {
var scroll = getScrollXY(getWindow(element));
clientRect.left += scroll.x;
clientRect.right += scroll.x;
clientRect.top += scroll.y;
clientRect.bottom += scroll.y;
}
return clientRect;
}
function getPath(node) {
var path = [];
while (node) {
path.push(node);
node = parentNode(node);
}
return path;
}
function trySelector(value) {
if (!is.string(value)) {
return false;
}
// an exception will be raised if it is invalid
domObjects$1.document.querySelector(value);
return true;
}
function extend(dest, source) {
for (var prop in source) {
dest[prop] = source[prop];
}
var ret = dest;
return ret;
}
function getStringOptionResult(value, target, element) {
if (value === 'parent') {
return parentNode(element);
}
if (value === 'self') {
return target.getRect(element);
}
return closest(element, value);
}
function resolveRectLike(value, target, element, functionArgs) {
var returnValue = value;
if (is.string(returnValue)) {
returnValue = getStringOptionResult(returnValue, target, element);
} else if (is.func(returnValue)) {
returnValue = returnValue.apply(void 0, functionArgs);
}
if (is.element(returnValue)) {
returnValue = getElementRect(returnValue);
}
return returnValue;
}
function rectToXY(rect) {
return rect && {
x: 'x' in rect ? rect.x : rect.left,
y: 'y' in rect ? rect.y : rect.top
};
}
function xywhToTlbr(rect) {
if (rect && !('left' in rect && 'top' in rect)) {
rect = extend({}, rect);
rect.left = rect.x || 0;
rect.top = rect.y || 0;
rect.right = rect.right || rect.left + rect.width;
rect.bottom = rect.bottom || rect.top + rect.height;
}
return rect;
}
function tlbrToXywh(rect) {
if (rect && !('x' in rect && 'y' in rect)) {
rect = extend({}, rect);
rect.x = rect.left || 0;
rect.y = rect.top || 0;
rect.width = rect.width || (rect.right || 0) - rect.x;
rect.height = rect.height || (rect.bottom || 0) - rect.y;
}
return rect;
}
function addEdges(edges, rect, delta) {
if (edges.left) {
rect.left += delta.x;
}
if (edges.right) {
rect.right += delta.x;
}
if (edges.top) {
rect.top += delta.y;
}
if (edges.bottom) {
rect.bottom += delta.y;
}
rect.width = rect.right - rect.left;
rect.height = rect.bottom - rect.top;
}
function getOriginXY(target, element, actionName) {
var actionOptions = actionName && target.options[actionName];
var actionOrigin = actionOptions && actionOptions.origin;
var origin = actionOrigin || target.options.origin;
var originRect = resolveRectLike(origin, target, element, [target && element]);
return rectToXY(originRect) || {
x: 0,
y: 0
};
}
function normalize(type, listeners) {
var filter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (_typeOrPrefix) {
return true;
};
var result = arguments.length > 3 ? arguments[3] : undefined;
result = result || {};
if (is.string(type) && type.search(' ') !== -1) {
type = split(type);
}
if (is.array(type)) {
type.forEach(function (t) {
return normalize(t, listeners, filter, result);
});
return result;
}
// before: type = [{ drag: () => {} }], listeners = undefined
// after: type = '' , listeners = [{ drag: () => {} }]
if (is.object(type)) {
listeners = type;
type = '';
}
if (is.func(listeners) && filter(type)) {
result[type] = result[type] || [];
result[type].push(listeners);
} else if (is.array(listeners)) {
for (var _i2 = 0, _listeners2 = listeners; _i2 < _listeners2.length; _i2++) {
var l = _listeners2[_i2];
normalize(type, l, filter, result);
}
} else if (is.object(listeners)) {
for (var prefix in listeners) {
var combinedTypes = split(prefix).map(function (p) {
return "".concat(type).concat(p);
});
normalize(combinedTypes, listeners[prefix], filter, result);
}
}
return result;
}
function split(type) {
return type.trim().split(/ +/);
}
var hypot = (function (x, y) {
return Math.sqrt(x * x + y * y);
});
var VENDOR_PREFIXES = ['webkit', 'moz'];
function pointerExtend(dest, source) {
dest.__set || (dest.__set = {});
var _loop = function _loop(prop) {
// skip deprecated prefixed properties
if (VENDOR_PREFIXES.some(function (prefix) {
return prop.indexOf(prefix) === 0;
})) return 1; // continue
if (typeof dest[prop] !== 'function' && prop !== '__set') {
Object.defineProperty(dest, prop, {
get: function get() {
if (prop in dest.__set) return dest.__set[prop];
return dest.__set[prop] = source[prop];
},
set: function set(value) {
dest.__set[prop] = value;
},
configurable: true
});
}
};
for (var prop in source) {
if (_loop(prop)) continue;
}
return dest;
}
function copyCoords(dest, src) {
dest.page = dest.page || {};
dest.page.x = src.page.x;
dest.page.y = src.page.y;
dest.client = dest.client || {};
dest.client.x = src.client.x;
dest.client.y = src.client.y;
dest.timeStamp = src.timeStamp;
}
function setCoordDeltas(targetObj, prev, cur) {
targetObj.page.x = cur.page.x - prev.page.x;
targetObj.page.y = cur.page.y - prev.page.y;
targetObj.client.x = cur.client.x - prev.client.x;
targetObj.client.y = cur.client.y - prev.client.y;
targetObj.timeStamp = cur.timeStamp - prev.timeStamp;
}
function setCoordVelocity(targetObj, delta) {
var dt = Math.max(delta.timeStamp / 1000, 0.001);
targetObj.page.x = delta.page.x / dt;
targetObj.page.y = delta.page.y / dt;
targetObj.client.x = delta.client.x / dt;
targetObj.client.y = delta.client.y / dt;
targetObj.timeStamp = dt;
}
function setZeroCoords(targetObj) {
targetObj.page.x = 0;
targetObj.page.y = 0;
targetObj.client.x = 0;
targetObj.client.y = 0;
}
function isNativePointer(pointer) {
return pointer instanceof domObjects$1.Event || pointer instanceof domObjects$1.Touch;
}
// Get specified X/Y coords for mouse or event.touches[0]
function getXY(type, pointer, xy) {
xy = xy || {};
type = type || 'page';
xy.x = pointer[type + 'X'];
xy.y = pointer[type + 'Y'];
return xy;
}
function getPageXY(pointer, page) {
page = page || {
x: 0,
y: 0
};
// Opera Mobile handles the viewport and scrolling oddly
if (browser$1.isOperaMobile && isNativePointer(pointer)) {
getXY('screen', pointer, page);
page.x += window.scrollX;
page.y += window.scrollY;
} else {
getXY('page', pointer, page);
}
return page;
}
function getClientXY(pointer, client) {
client = client || {};
if (browser$1.isOperaMobile && isNativePointer(pointer)) {
// Opera Mobile handles the viewport and scrolling oddly
getXY('screen', pointer, client);
} else {
getXY('client', pointer, client);
}
return client;
}
function getPointerId(pointer) {
return is.number(pointer.pointerId) ? pointer.pointerId : pointer.identifier;
}
function setCoords(dest, pointers, timeStamp) {
var pointer = pointers.length > 1 ? pointerAverage(pointers) : pointers[0];
getPageXY(pointer, dest.page);
getClientXY(pointer, dest.client);
dest.timeStamp = timeStamp;
}
function getTouchPair(event) {
var touches = [];
// array of touches is supplied
if (is.array(event)) {
touches[0] = event[0];
touches[1] = event[1];
}
// an event
else {
if (event.type === 'touchend') {
if (event.touches.length === 1) {
touches[0] = event.touches[0];
touches[1] = event.changedTouches[0];
} else if (event.touches.length === 0) {
touches[0] = event.changedTouches[0];
touches[1] = event.changedTouches[1];
}
} else {
touches[0] = event.touches[0];
touches[1] = event.touches[1];
}
}
return touches;
}
function pointerAverage(pointers) {
var average = {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
screenX: 0,
screenY: 0
};
for (var _i2 = 0; _i2 < pointers.length; _i2++) {
var pointer = pointers[_i2];
for (var prop in average) {
average[prop] += pointer[prop];
}
}
for (var _prop in average) {
average[_prop] /= pointers.length;
}
return average;
}
function touchBBox(event) {
if (!event.length) {
return null;
}
var touches = getTouchPair(event);
var minX = Math.min(touches[0].pageX, touches[1].pageX);
var minY = Math.min(touches[0].pageY, touches[1].pageY);
var maxX = Math.max(touches[0].pageX, touches[1].pageX);
var maxY = Math.max(touches[0].pageY, touches[1].pageY);
return {
x: minX,
y: minY,
left: minX,
top: minY,
right: maxX,
bottom: maxY,
width: maxX - minX,
height: maxY - minY
};
}
function touchDistance(event, deltaSource) {
var sourceX = deltaSource + 'X';
var sourceY = deltaSource + 'Y';
var touches = getTouchPair(event);
var dx = touches[0][sourceX] - touches[1][sourceX];
var dy = touches[0][sourceY] - touches[1][sourceY];
return hypot(dx, dy);
}
function touchAngle(event, deltaSource) {
var sourceX = deltaSource + 'X';
var sourceY = deltaSource + 'Y';
var touches = getTouchPair(event);
var dx = touches[1][sourceX] - touches[0][sourceX];
var dy = touches[1][sourceY] - touches[0][sourceY];
var angle = 180 * Math.atan2(dy, dx) / Math.PI;
return angle;
}
function getPointerType(pointer) {
return is.string(pointer.pointerType) ? pointer.pointerType : is.number(pointer.pointerType) ? [undefined, undefined, 'touch', 'pen', 'mouse'][pointer.pointerType] :
// if the PointerEvent API isn't available, then the "pointer" must
// be either a MouseEvent, TouchEvent, or Touch object
/touch/.test(pointer.type || '') || pointer instanceof domObjects$1.Touch ? 'touch' : 'mouse';
}
// [ event.target, event.currentTarget ]
function getEventTargets(event) {
var path = is.func(event.composedPath) ? event.composedPath() : event.path;
return [getActualElement(path ? path[0] : event.target), getActualElement(event.currentTarget)];
}
function newCoords() {
return {
page: {
x: 0,
y: 0
},
client: {
x: 0,
y: 0
},
timeStamp: 0
};
}
function coordsToEvent(coords) {
var event = {
coords: coords,
get page() {
return this.coords.page;
},
get client() {
return this.coords.client;
},
get timeStamp() {
return this.coords.timeStamp;
},
get pageX() {
return this.coords.page.x;
},
get pageY() {
return this.coords.page.y;
},
get clientX() {
return this.coords.client.x;
},
get clientY() {
return this.coords.client.y;
},
get pointerId() {
return this.coords.pointerId;
},
get target() {
return this.coords.target;
},
get type() {
return this.coords.type;
},
get pointerType() {
return this.coords.pointerType;
},
get buttons() {
return this.coords.buttons;
},
preventDefault: function preventDefault() {}
};
return event;
}
var BaseEvent = /*#__PURE__*/function () {
function BaseEvent(interaction) {
_classCallCheck(this, BaseEvent);
/** @internal */
this.immediatePropagationStopped = false;
this.propagationStopped = false;
this._interaction = interaction;
}
_createClass(BaseEvent, [{
key: "preventDefault",
value: function preventDefault() {}
/**
* Don't call any other listeners (even on the current target)
*/
}, {
key: "stopPropagation",
value: function stopPropagation() {
this.propagationStopped = true;
}
/**
* Don't call listeners on the remaining targets
*/
}, {
key: "stopImmediatePropagation",
value: function stopImmediatePropagation() {
this.immediatePropagationStopped = this.propagationStopped = true;
}
}]);
return BaseEvent;
}();
// defined outside of class definition to avoid assignment of undefined during
// construction
// getters and setters defined here to support typescript 3.6 and below which
// don't support getter and setters in .d.ts files
Object.defineProperty(BaseEvent.prototype, 'interaction', {
get: function get() {
return this._interaction._proxy;
},
set: function set() {}
});
var remove = function remove(array, target) {
return array.splice(array.indexOf(target), 1);
};
var merge = function merge(target, source) {
for (var _i2 = 0; _i2 < source.length; _i2++) {
var item = source[_i2];
target.push(item);
}
return target;
};
var from = function from(source) {
return merge([], source);
};
var findIndex = function findIndex(array, func) {
for (var i = 0; i < array.length; i++) {
if (func(array[i], i, array)) {
return i;
}
}
return -1;
};
var find = function find(array, func) {
return array[findIndex(array, func)];
};
var DropEvent = /*#__PURE__*/function (_BaseEvent) {
_inherits(DropEvent, _BaseEvent);
var _super = _createSuper(DropEvent);
/**
* Class of events fired on dropzones during drags with acceptable targets.
*/
function DropEvent(dropState, dragEvent, type) {
var _this;
_classCallCheck(this, DropEvent);
_this = _super.call(this, dragEvent._interaction);
_this.dropzone = void 0;
_this.dragEvent = void 0;
_this.relatedTarget = void 0;
_this.draggable = void 0;
_this.propagationStopped = false;
_this.immediatePropagationStopped = false;
var _ref = type === 'dragleave' ? dropState.prev : dropState.cur,
element = _ref.element,
dropzone = _ref.dropzone;
_this.type = type;
_this.target = element;
_this.currentTarget = element;
_this.dropzone = dropzone;
_this.dragEvent = dragEvent;
_this.relatedTarget = dragEvent.target;
_this.draggable = dragEvent.interactable;
_this.timeStamp = dragEvent.timeStamp;
return _this;
}
/**
* If this is a `dropactivate` event, the dropzone element will be
* deactivated.
*
* If this is a `dragmove` or `dragenter`, a `dragleave` will be fired on the
* dropzone element and more.
*/
_createClass(DropEvent, [{
key: "reject",
value: function reject() {
var _this2 = this;
var dropState = this._interaction.dropState;
if (this.type !== 'dropactivate' && (!this.dropzone || dropState.cur.dropzone !== this.dropzone || dropState.cur.element !== this.target)) {
return;
}
dropState.prev.dropzone = this.dropzone;
dropState.prev.element = this.target;
dropState.rejected = true;
dropState.events.enter = null;
this.stopImmediatePropagation();
if (this.type === 'dropactivate') {
var activeDrops = dropState.activeDrops;
var index = findIndex(activeDrops, function (_ref2) {
var dropzone = _ref2.dropzone,
element = _ref2.element;
return dropzone === _this2.dropzone && element === _this2.target;
});
dropState.activeDrops.splice(index, 1);
var deactivateEvent = new DropEvent(dropState, this.dragEvent, 'dropdeactivate');
deactivateEvent.dropzone = this.dropzone;
deactivateEvent.target = this.target;
this.dropzone.fire(deactivateEvent);
} else {
this.dropzone.fire(new DropEvent(dropState, this.dragEvent, 'dragleave'));
}
}
}, {
key: "preventDefault",
value: function preventDefault() {}
}, {
key: "stopPropagation",
value: function stopPropagation() {
this.propagationStopped = true;
}
}, {
key: "stopImmediatePropagation",
value: function stopImmediatePropagation() {
this.immediatePropagationStopped = this.propagationStopped = true;
}
}]);
return DropEvent;
}(BaseEvent);
function install$f(scope) {
var actions = scope.actions,
interact = scope.interactStatic,
Interactable = scope.Interactable,
defaults = scope.defaults;
scope.usePlugin(drag$1);
Interactable.prototype.dropzone = function (options) {
return dropzoneMethod(this, options);
};
Interactable.prototype.dropCheck = function (dragEvent, event, draggable, draggableElement, dropElement, rect) {
return dropCheckMethod(this, dragEvent, event, draggable, draggableElement, dropElement, rect);
};
interact.dynamicDrop = function (newValue) {
if (is.bool(newValue)) {
// if (dragging && scope.dynamicDrop !== newValue && !newValue) {
// calcRects(dropzones)
// }
scope.dynamicDrop = newValue;
return interact;
}
return scope.dynamicDrop;
};
extend(actions.phaselessTypes, {
dragenter: true,
dragleave: true,
dropactivate: true,
dropdeactivate: true,
dropmove: true,
drop: true
});
actions.methodDict.drop = 'dropzone';
scope.dynamicDrop = false;
defaults.actions.drop = drop.defaults;
}
function collectDropzones(_ref, draggableElement) {
var interactables = _ref.interactables;
var drops = [];
// collect all dropzones and their elements which qualify for a drop
for (var _i2 = 0, _interactables$list2 = interactables.list; _i2 < _interactables$list2.length; _i2++) {
var _dropzone = _interactables$list2[_i2];
if (!_dropzone.options.drop.enabled) {
continue;
}
var accept = _dropzone.options.drop.accept;
// test the draggable draggableElement against the dropzone's accept setting
if (is.element(accept) && accept !== draggableElement || is.string(accept) && !matchesSelector(draggableElement, accept) || is.func(accept) && !accept({
dropzone: _dropzone,
draggableElement: draggableElement
})) {
continue;
}
for (var _i4 = 0, _dropzone$getAllEleme2 = _dropzone.getAllElements(); _i4 < _dropzone$getAllEleme2.length; _i4++) {
var dropzoneElement = _dropzone$getAllEleme2[_i4];
if (dropzoneElement !== draggableElement) {
drops.push({
dropzone: _dropzone,
element: dropzoneElement,
rect: _dropzone.getRect(dropzoneElement)
});
}
}
}
return drops;
}
function fireActivationEvents(activeDrops, event) {
// loop through all active dropzones and trigger event
for (var _i6 = 0, _activeDrops$slice2 = activeDrops.slice(); _i6 < _activeDrops$slice2.length; _i6++) {
var _activeDrops$slice2$_ = _activeDrops$slice2[_i6],
_dropzone2 = _activeDrops$slice2$_.dropzone,
element = _activeDrops$slice2$_.element;
event.dropzone = _dropzone2;
// set current element as event target
event.target = element;
_dropzone2.fire(event);
event.propagationStopped = event.immediatePropagationStopped = false;
}
}
// return a new array of possible drops. getActiveDrops should always be
// called when a drag has just started or a drag event happens while
// dynamicDrop is true
function getActiveDrops(scope, dragElement) {
// get dropzones and their elements that could receive the draggable
var activeDrops = collectDropzones(scope, dragElement);
for (var _i8 = 0; _i8 < activeDrops.length; _i8++) {
var activeDrop = activeDrops[_i8];
activeDrop.rect = activeDrop.dropzone.getRect(activeDrop.element);
}
return activeDrops;
}
function getDrop(_ref2, dragEvent, pointerEvent) {
var dropState = _ref2.dropState,
draggable = _ref2.interactable,
dragElement = _ref2.element;
var validDrops = [];
// collect all dropzones and their elements which qualify for a drop
for (var _i10 = 0, _dropState$activeDrop2 = dropState.activeDrops; _i10 < _dropState$activeDrop2.length; _i10++) {
var _dropState$activeDrop3 = _dropState$activeDrop2[_i10],
_dropzone3 = _dropState$activeDrop3.dropzone,
dropzoneElement = _dropState$activeDrop3.element,
_rect = _dropState$activeDrop3.rect;
var isValid = _dropzone3.dropCheck(dragEvent, pointerEvent, draggable, dragElement, dropzoneElement, _rect);
validDrops.push(isValid ? dropzoneElement : null);
} // get the most appropriate dropzone based on DOM depth and order
var dropIndex = indexOfDeepestElement(validDrops);
return dropState.activeDrops[dropIndex] || null;
}
function getDropEvents(interaction, _pointerEvent, dragEvent) {
var dropState = interaction.dropState;
var dropEvents = {
enter: null,
leave: null,
activate: null,
deactivate: null,
move: null,
drop: null
};
if (dragEvent.type === 'dragstart') {
dropEvents.activate = new DropEvent(dropState, dragEvent, 'dropactivate');
dropEvents.activate.target = null;
dropEvents.activate.dropzone = null;
}
if (dragEvent.type === 'dragend') {
dropEvents.deactivate = new DropEvent(dropState, dragEvent, 'dropdeactivate');
dropEvents.deactivate.target = null;
dropEvents.deactivate.dropzone = null;
}
if (dropState.rejected) {
return dropEvents;
}
if (dropState.cur.element !== dropState.prev.element) {
// if there was a previous dropzone, create a dragleave event
if (dropState.prev.dropzone) {
dropEvents.leave = new DropEvent(dropState, dragEvent, 'dragleave');
dragEvent.dragLeave = dropEvents.leave.target = dropState.prev.element;
dragEvent.prevDropzone = dropEvents.leave.dropzone = dropState.prev.dropzone;
}
// if dropzone is not null, create a dragenter event
if (dropState.cur.dropzone) {
dropEvents.enter = new DropEvent(dropState, dragEvent, 'dragenter');
dragEvent.dragEnter = dropState.cur.element;
dragEvent.dropzone = dropState.cur.dropzone;
}
}
if (dragEvent.type === 'dragend' && dropState.cur.dropzone) {
dropEvents.drop = new DropEvent(dropState, dragEvent, 'drop');
dragEvent.dropzone = dropState.cur.dropzone;
dragEvent.relatedTarget = dropState.cur.element;
}
if (dragEvent.type === 'dragmove' && dropState.cur.dropzone) {
dropEvents.move = new DropEvent(dropState, dragEvent, 'dropmove');
dragEvent.dropzone = dropState.cur.dropzone;
}
return dropEvents;
}
function fireDropEvents(interaction, events) {
var dropState = interaction.dropState;
var activeDrops = dropState.activeDrops,
cur = dropState.cur,
prev = dropState.prev;
if (events.leave) {
prev.dropzone.fire(events.leave);
}
if (events.enter) {
cur.dropzone.fire(events.enter);
}
if (events.move) {
cur.dropzone.fire(events.move);
}
if (events.drop) {
cur.dropzone.fire(events.drop);
}
if (events.deactivate) {
fireActivationEvents(activeDrops, events.deactivate);
}
dropState.prev.dropzone = cur.dropzone;
dropState.prev.element = cur.element;
}
function onEventCreated(_ref3, scope) {
var interaction = _ref3.interaction,
iEvent = _ref3.iEvent,
event = _ref3.event;
if (iEvent.type !== 'dragmove' && iEvent.type !== 'dragend') {
return;
}
var dropState = interaction.dropState;
if (scope.dynamicDrop) {
dropState.activeDrops = getActiveDrops(scope, interaction.element);
}
var dragEvent = iEvent;
var dropResult = getDrop(interaction, dragEvent, event);
// update rejected status
dropState.rejected = dropState.rejected && !!dropResult && dropResult.dropzone === dropState.cur.dropzone && dropResult.element === dropState.cur.element;
dropState.cur.dropzone = dropResult && dropResult.dropzone;
dropState.cur.element = dropResult && dropResult.element;
dropState.events = getDropEvents(interaction, event, dragEvent);
}
function dropzoneMethod(interactable, options) {
if (is.object(options)) {
interactable.options.drop.enabled = options.enabled !== false;
if (options.listeners) {
var normalized = normalize(options.listeners);
// rename 'drop' to '' as it will be prefixed with 'drop'
var corrected = Object.keys(normalized).reduce(function (acc, type) {
var correctedType = /^(enter|leave)/.test(type) ? "drag".concat(type) : /^(activate|deactivate|move)/.test(type) ? "drop".concat(type) : type;
acc[correctedType] = normalized[type];
return acc;
}, {});
var prevListeners = interactable.options.drop.listeners;
prevListeners && interactable.off(prevListeners);
interactable.on(corrected);
interactable.options.drop.listeners = corrected;
}
if (is.func(options.ondrop)) {
interactable.on('drop', options.ondrop);
}
if (is.func(options.ondropactivate)) {
interactable.on('dropactivate', options.ondropactivate);
}
if (is.func(options.ondropdeactivate)) {
interactable.on('dropdeactivate', options.ondropdeactivate);
}
if (is.func(options.ondragenter)) {
interactable.on('dragenter', options.ondragenter);
}
if (is.func(options.ondragleave)) {
interactable.on('dragleave', options.ondragleave);
}
if (is.func(options.ondropmove)) {
interactable.on('dropmove', options.ondropmove);
}
if (/^(pointer|center)$/.test(options.overlap)) {
interactable.options.drop.overlap = options.overlap;
} else if (is.number(options.overlap)) {
interactable.options.drop.overlap = Math.max(Math.min(1, options.overlap), 0);
}
if ('accept' in options) {
interactable.options.drop.accept = options.accept;
}
if ('checker' in options) {
interactable.options.drop.checker = options.checker;
}
return interactable;
}
if (is.bool(options)) {
interactable.options.drop.enabled = options;
return interactable;
}
return interactable.options.drop;
}
function dropCheckMethod(interactable, dragEvent, event, draggable, draggableElement, dropElement, rect) {
var dropped = false;
// if the dropzone has no rect (eg. display: none)
// call the custom dropChecker or just return false
if (!(rect = rect || interactable.getRect(dropElement))) {
return interactable.options.drop.checker ? interactable.options.drop.checker(dragEvent, event, dropped, interactable, dropElement, draggable, draggableElement) : false;
}
var dropOverlap = interactable.options.drop.overlap;
if (dropOverlap === 'pointer') {
var origin = getOriginXY(draggable, draggableElement, 'drag');
var page = getPageXY(dragEvent);
page.x += origin.x;
page.y += origin.y;
var horizontal = page.x > rect.left && page.x < rect.right;
var vertical = page.y > rect.top && page.y < rect.bottom;
dropped = horizontal && vertical;
}
var dragRect = draggable.getRect(draggableElement);
if (dragRect && dropOverlap === 'center') {
var cx = dragRect.left + dragRect.width / 2;
var cy = dragRect.top + dragRect.height / 2;
dropped = cx >= rect.left && cx <= rect.right && cy >= rect.top && cy <= rect.bottom;
}
if (dragRect && is.number(dropOverlap)) {
var overlapArea = Math.max(0, Math.min(rect.right, dragRect.right) - Math.max(rect.left, dragRect.left)) * Math.max(0, Math.min(rect.bottom, dragRect.bottom) - Math.max(rect.top, dragRect.top));
var overlapRatio = overlapArea / (dragRect.width * dragRect.height);
dropped = overlapRatio >= dropOverlap;
}
if (