UNPKG

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
/** * 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 (