{“ast”:null,“code”:“function _typeof2(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof2(obj); }nnimport { EventDispatcher, Object3D, Raycaster, Vector2 } from 'three';n/**n * get variable typen * @param {*} val a variable which you want to get the typen * @return {String} variable-typen */nnfunction _rt(val) {n return Object.prototype.toString.call(val);n}n/**n * Utils tool boxn *n * @namespace Utilsn */nnnvar Utils = {n /**n * determine whether it is a `Function`n *n * @staticn * @methodn * @memberof Utilsn * @param {*} variable a variable which you want to determinen * @return {Boolean} type resultn */n isFunction: function () {n var ks = _rt(function () {});nn return function (variable) {n return _rt(variable) === ks;n };n }(),nn /**n * determine whether it is a `undefined`n *n * @staticn * @methodn * @memberof Utilsn * @param {*} variable a variable which you want to determinen * @return {Boolean} type resultn */n isUndefined: function isUndefined(variable) {n return typeof variable === 'undefined';n }n};n/**n * proxy `addEventListener` functionn *n * @param {String} type event type, evnet namen * @param {Function} fn callbackn * @return {this} thisn */nnEventDispatcher.prototype.on = function (type, fn) {n if (!Utils.isFunction(fn)) return;n if (this instanceof Object3D) this.interactive = true;n this.addEventListener(type, fn);n return this;n};n/**n * proxy `removeEventListener` functionn *n * @param {String} type event type, evnet namen * @param {Function} fn callback, which you had bind beforen * @return {this} thisn */nnnEventDispatcher.prototype.off = function (type, fn) {n this.removeEventListener(type, fn);n return this;n};n/**n * binding a once event, just emit once timen *n * @param {String} type event type, evnet namen * @param {Function} fn callbackn * @return {this} thisn */nnnEventDispatcher.prototype.once = function (type, fn) {n var _this = this;nn if (!Utils.isFunction(fn)) return;nn var cb = function cb(ev) {n fn(ev);nn _this.off(type, cb);n };nn this.on(type, cb);n return this;n};n/**n * emit a eventn *n * @param {String} type event type, evnet namen * @return {this} thisn */nnnEventDispatcher.prototype.emit = function (type) {n if (this._listeners === undefined || Utils.isUndefined(this._listeners)) return;n var cbs = this._listeners || [];n var cache = cbs.slice(0);nn for (var _len = arguments.length, argument = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {n argument[_key - 1] = arguments;n }nn for (var i = 0; i < cache.length; i++) {n cache.apply(this, argument);n }nn return this;n};n/**n * whether displayObject is interactivelyn */nnnObject3D.prototype.interactive = false;n/**n * whether displayObject's children is interactivelyn */nnObject3D.prototype.interactiveChildren = true;n/**n * whether displayObject had touchstartn * @privaten */nnObject3D.prototype.started = false;n/**n * tracked event cache, like: touchend、mouseout、pointerout which decided by primary-eventn */nnObject.defineProperty(Object3D.prototype, 'trackedPointers', {n get: function get() {n if (!this._trackedPointers) this._trackedPointers = {};n return this._trackedPointers;n }n});n/**n * dispatch a raycastn *n * @param {Raycaster} raycaster Raycaster object, get from THREE.Raycastern * @return {Object|Boolean} had pass hit-testn */nnObject3D.prototype.raycastTest = function (raycaster) {n var result = [];n this.raycast(raycaster, result);nn if (result.length > 0) {n return result;n }nn return false;n};nnvar _typeof = typeof Symbol === "function" && _typeof2(Symbol.iterator) === "symbol" ? function (obj) {n return _typeof2(obj);n} : function (obj) {n return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof2(obj);n};nnvar classCallCheck = function classCallCheck(instance, Constructor) {n if (!(instance instanceof Constructor)) {n throw new TypeError("Cannot call a class as a function");n }n};nnvar createClass = function () {n function defineProperties(target, props) {n for (var i = 0; i < props.length; i++) {n var descriptor = props;n descriptor.enumerable = descriptor.enumerable || false;n descriptor.configurable = true;n if ("value" in descriptor) descriptor.writable = true;n Object.defineProperty(target, descriptor.key, descriptor);n }n }nn return function (Constructor, protoProps, staticProps) {n if (protoProps) defineProperties(Constructor.prototype, protoProps);n if (staticProps) defineProperties(Constructor, staticProps);n return Constructor;n };n}();nnvar inherits = function inherits(subClass, superClass) {n if (typeof superClass !== "function" && superClass !== null) {n throw new TypeError("Super expression must either be null or a function, not " + _typeof2(superClass));n }nn subClass.prototype = Object.create(superClass && superClass.prototype, {n constructor: {n value: subClass,n enumerable: false,n writable: true,n configurable: truen }n });n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;n};nnvar possibleConstructorReturn = function possibleConstructorReturn(self, call) {n if (!self) {n throw new ReferenceError("this hasn't been initialised - super() hasn't been called");n }nn return call && (_typeof2(call) === "object" || typeof call === "function") ? call : self;n};n/**n * Holds all information related to an Interaction eventn *n * @classn */nnnvar InteractionData = function () {n /**n * InteractionData constructorn */n function InteractionData() {n classCallCheck(this, InteractionData);n /**n * This point stores the global coords of where the touch/mouse event happenedn *n * @member {Vector2}n */nn this.global = new Vector2();n /**n * The target DisplayObject that was interacted withn *n * @member {Object3D}n */nn this.target = null;n /**n * When passed to an event handler, this will be the original DOM Event that was capturedn *n * @see developer.mozilla.org/en-US/docs/Web/API/MouseEventn * @see developer.mozilla.org/en-US/docs/Web/API/TouchEventn * @see developer.mozilla.org/en-US/docs/Web/API/PointerEventn * @member {MouseEvent|TouchEvent|PointerEvent}n */nn this.originalEvent = null;n /**n * Unique identifier for this interactionn *n * @member {number}n */nn this.identifier = null;n /**n * Indicates whether or not the pointer device that created the event is the primary pointer.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/isPrimaryn * @type {Boolean}n */nn this.isPrimary = false;n /**n * Indicates which button was pressed on the mouse or pointer device to trigger the event.n * @see developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttonn * @type {number}n */nn this.button = 0;n /**n * Indicates which buttons are pressed on the mouse or pointer device when the event is triggered.n * @see developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttonsn * @type {number}n */nn this.buttons = 0;n /**n * The width of the pointer's contact along the x-axis, measured in CSS pixels.n * radiusX of TouchEvents will be represented by this value.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/widthn * @type {number}n */nn this.width = 0;n /**n * The height of the pointer's contact along the y-axis, measured in CSS pixels.n * radiusY of TouchEvents will be represented by this value.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/heightn * @type {number}n */nn this.height = 0;n /**n * The angle, in degrees, between the pointer device and the screen.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/tiltXn * @type {number}n */nn this.tiltX = 0;n /**n * The angle, in degrees, between the pointer device and the screen.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/tiltYn * @type {number}n */nn this.tiltY = 0;n /**n * The type of pointer that triggered the event.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerTypen * @type {string}n */nn this.pointerType = null;n /**n * Pressure applied by the pointing device during the event. A Touch's force propertyn * will be represented by this value.n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pressuren * @type {number}n */nn this.pressure = 0;n /**n * From TouchEvents (not PointerEvents triggered by touches), the rotationAngle of the Touch.n * @see developer.mozilla.org/en-US/docs/Web/API/Touch/rotationAnglen * @type {number}n */nn this.rotationAngle = 0;n /**n * Twist of a stylus pointer.n * @see w3c.github.io/pointerevents/#pointerevent-interfacen * @type {number}n */nn this.twist = 0;n /**n * Barrel pressure on a stylus pointer.n * @see w3c.github.io/pointerevents/#pointerevent-interfacen * @type {number}n */nn this.tangentialPressure = 0;n }n /**n * The unique identifier of the pointer. It will be the same as `identifier`.n * @readonlyn * @member {number}n * @see developer.mozilla.org/en-US/docs/Web/API/PointerEvent/pointerIdn */nnn createClass(InteractionData, [{n key: '_copyEvent',nn /**n * Copies properties from normalized event data.n *n * @param {Touch|MouseEvent|PointerEvent} event The normalized event datan * @privaten */n value: function _copyEvent(event) {n // isPrimary should only change on touchstart/pointerdown, so we don't want to overwriten // it with "false" on later events when our shim for it on touch events might not ben // accuraten if (event.isPrimary) {n this.isPrimary = true;n }nn this.button = event.button;n this.buttons = event.buttons;n this.width = event.width;n this.height = event.height;n this.tiltX = event.tiltX;n this.tiltY = event.tiltY;n this.pointerType = event.pointerType;n this.pressure = event.pressure;n this.rotationAngle = event.rotationAngle;n this.twist = event.twist || 0;n this.tangentialPressure = event.tangentialPressure || 0;n }n /**n * Resets the data for pooling.n *n * @privaten */nn }, {n key: '_reset',n value: function _reset() {n // isPrimary is the only property that we really need to reset - everything else isn // guaranteed to be overwrittenn this.isPrimary = false;n }n }, {n key: 'pointerId',n get: function get$$1() {n return this.identifier;n }n }]);n return InteractionData;n}();n/**n * Event class that mimics native DOM events.n *n * @classn */nnnvar InteractionEvent = function () {n /**n * InteractionEvent constructorn */n function InteractionEvent() {n classCallCheck(this, InteractionEvent);n /**n * Whether this event will continue propagating in the treen *n * @member {boolean}n */nn this.stopped = false;n /**n * The object which caused this event to be dispatched.n *n * @member {Object3D}n */nn this.target = null;n /**n * The object whose event listener’s callback is currently being invoked.n *n * @member {Object3D}n */nn this.currentTarget = null;n /**n * Type of the eventn *n * @member {string}n */nn this.type = null;n /**n * InteractionData related to this eventn *n * @member {InteractionData}n */nn this.data = null;n /**n * ray caster detial from 3d-meshn *n * @member {Intersects}n */nn this.intersects = [];n }n /**n * Prevents event from reaching any objects other than the current object.n *n */nnn createClass(InteractionEvent, [{n key: "stopPropagation",n value: function stopPropagation() {n this.stopped = true;n }n /**n * Resets the event.n *n * @privaten */nn }, {n key: "_reset",n value: function _reset() {n this.stopped = false;n this.currentTarget = null;n this.target = null;n this.intersects = [];n }n }]);n return InteractionEvent;n}();n/**n * DisplayObjects with the `trackedPointers` property use this class to track interactionsn *n * @classn * @privaten */nnnvar InteractionTrackingData = function () {n /**n * @param {number} pointerId - Unique pointer id of the eventn */n function InteractionTrackingData(pointerId) {n classCallCheck(this, InteractionTrackingData);n this._pointerId = pointerId;n this._flags = InteractionTrackingData.FLAGS.NONE;n }n /**n *n * @privaten * @param {number} flag - The interaction flag to setn * @param {boolean} yn - Should the flag be set or unsetn */nnn createClass(InteractionTrackingData, [{n key: "_doSet",n value: function _doSet(flag, yn) {n if (yn) {n this._flags = this._flags | flag;n } else {n this._flags = this._flags & ~flag;n }n }n /**n * Unique pointer id of the eventn *n * @readonlyn * @member {number}n */nn }, {n key: "pointerId",n get: function get$$1() {n return this._pointerId;n }n /**n * State of the tracking data, expressed as bit flagsn *n * @member {number}n */nn }, {n key: "flags",n get: function get$$1() {n return this._flags;n }n /**n * Set the flags for the tracking datan *n * @param {number} flags - Flags to setn */n ,n set: function set$$1(flags) {n this._flags = flags;n }n /**n * Is the tracked event inactive (not over or down)?n *n * @member {number}n */nn }, {n key: "none",n get: function get$$1() {n return this._flags === this.constructor.FLAGS.NONE;n }n /**n * Is the tracked event over the DisplayObject?n *n * @member {boolean}n */nn }, {n key: "over",n get: function get$$1() {n return (this._flags & this.constructor.FLAGS.OVER) !== 0;n }n /**n * Set the over flagn *n * @param {boolean} yn - Is the event over?n */n ,n set: function set$$1(yn) {n this._doSet(this.constructor.FLAGS.OVER, yn);n }n /**n * Did the right mouse button come down in the DisplayObject?n *n * @member {boolean}n */nn }, {n key: "rightDown",n get: function get$$1() {n return (this._flags & this.constructor.FLAGS.RIGHT_DOWN) !== 0;n }n /**n * Set the right down flagn *n * @param {boolean} yn - Is the right mouse button down?n */n ,n set: function set$$1(yn) {n this._doSet(this.constructor.FLAGS.RIGHT_DOWN, yn);n }n /**n * Did the left mouse button come down in the DisplayObject?n *n * @member {boolean}n */nn }, {n key: "leftDown",n get: function get$$1() {n return (this._flags & this.constructor.FLAGS.LEFT_DOWN) !== 0;n }n /**n * Set the left down flagn *n * @param {boolean} yn - Is the left mouse button down?n */n ,n set: function set$$1(yn) {n this._doSet(this.constructor.FLAGS.LEFT_DOWN, yn);n }n }]);n return InteractionTrackingData;n}();nnInteractionTrackingData.FLAGS = Object.freeze({n NONE: 0,n OVER: 1 << 0,n LEFT_DOWN: 1 << 1,n RIGHT_DOWN: 1 << 2n});nvar MOUSE_POINTER_ID = 'MOUSE'; // helpers for hitTest() - only used inside hitTest()nnvar hitTestEvent = {n target: null,n data: {n global: nulln }n};n/**n * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactiven * if its interactive parameter is set to truen * This manager also supports multitouch.n *n * reference to [pixi.js](www.pixijs.com/) impln *n * @privaten * @classn * @extends EventDispatchern */nnvar InteractionManager = function (_EventDispatcher) {n inherits(InteractionManager, _EventDispatcher);n /**n * @param {WebGLRenderer} renderer - A reference to the current renderern * @param {Scene} scene - A reference to the current scenen * @param {Camera} camera - A reference to the current cameran * @param {Object} [options] - The options for the manager.n * @param {Boolean} [options.autoPreventDefault=false] - Should the manager automatically prevent default browser actions.n * @param {Boolean} [options.autoAttach=true] - Should the manager automatically attach target element.n * @param {Number} [options.interactionFrequency=10] - Frequency increases the interaction events will be checked.n */nn function InteractionManager(renderer, scene, camera, options) {n classCallCheck(this, InteractionManager);nn var _this = possibleConstructorReturn(this, (InteractionManager.__proto__ || Object.getPrototypeOf(InteractionManager)).call(this));nn options = options || {};n /**n * The renderer this interaction manager works for.n *n * @member {WebGLRenderer}n */nn _this.renderer = renderer;n /**n * The renderer this interaction manager works for.n *n * @member {Scene}n */nn _this.scene = scene;n /**n * The renderer this interaction manager works for.n *n * @member {Camera}n */nn _this.camera = camera;n /**n * Should default browser actions automatically be prevented.n * Does not apply to pointer events for backwards compatibilityn * preventDefault on pointer events stops mouse events from firingn * Thus, for every pointer event, there will always be either a mouse of touch event alongside it.n *n * @member {boolean}n * @default falsen */nn _this.autoPreventDefault = options.autoPreventDefault || false;n /**n * Frequency in milliseconds that the mousemove, moveover & mouseout interaction events will be checked.n *n * @member {number}n * @default 10n */nn _this.interactionFrequency = options.interactionFrequency || 10;n /**n * The mouse datan *n * @member {InteractionData}n */nn _this.mouse = new InteractionData();n _this.mouse.identifier = MOUSE_POINTER_ID; // setting the mouse to start off far off screen will mean that mouse over doesn // not get called before we even move the mouse.nn _this.mouse.global.set(-999999);n /**n * Actively tracked InteractionDatan *n * @privaten * @member {Object.<number,InteractionData>}n */nnn _this.activeInteractionData = {};n _this.activeInteractionData = _this.mouse;n /**n * Pool of unused InteractionDatan *n * @privaten * @member {InteractionData[]}n */nn _this.interactionDataPool = [];n /**n * An event data object to handle all the event tracking/dispatchingn *n * @member {object}n */nn _this.eventData = new InteractionEvent();n /**n * The DOM element to bind to.n *n * @privaten * @member {HTMLElement}n */nn _this.interactionDOMElement = null;n /**n * This property determines if mousemove and touchmove events are fired only when the cursorn * is over the object.n * Setting to true will make things work more in line with how the DOM verison works.n * Setting to false can make things easier for things like draggingn * It is currently set to false as this is how three.js used to work.n *n * @member {boolean}n * @default truen */nn _this.moveWhenInside = true;n /**n * Have events been attached to the dom element?n *n * @privaten * @member {boolean}n */nn _this.eventsAdded = false;n /**n * Is the mouse hovering over the renderer?n *n * @privaten * @member {boolean}n */nn _this.mouseOverRenderer = false;n /**n * Does the device support touch eventsn * www.w3.org/TR/touch-events/n *n * @readonlyn * @member {boolean}n */nn _this.supportsTouchEvents = 'ontouchstart' in window;n /**n * Does the device support pointer eventsn * www.w3.org/Submission/pointer-events/n *n * @readonlyn * @member {boolean}n */nn _this.supportsPointerEvents = !!window.PointerEvent; // this will make it so that you don't have to call bind all the timenn /**n * @privaten * @member {Function}n */nn _this.onClick = _this.onClick.bind(_this);n _this.processClick = _this.processClick.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerUp = _this.onPointerUp.bind(_this);n _this.processPointerUp = _this.processPointerUp.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerCancel = _this.onPointerCancel.bind(_this);n _this.processPointerCancel = _this.processPointerCancel.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerDown = _this.onPointerDown.bind(_this);n _this.processPointerDown = _this.processPointerDown.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerMove = _this.onPointerMove.bind(_this);n _this.processPointerMove = _this.processPointerMove.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerOut = _this.onPointerOut.bind(_this);n _this.processPointerOverOut = _this.processPointerOverOut.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerOver = _this.onPointerOver.bind(_this);n /**n * Dictionary of how different cursor modes are handled. Strings are handled as CSS cursorn * values, objects are handled as dictionaries of CSS values for interactionDOMElement,n * and functions are called instead of changing the CSS.n * Default CSS cursor values are provided for 'default' and 'pointer' modes.n * @member {Object.<string, (string|Function|Object.<string, string>)>}n */nn _this.cursorStyles = {n "default": 'inherit',n pointer: 'pointer'n };n /**n * The mode of the cursor that is being used.n * The value of this is a key from the cursorStyles dictionary.n *n * @member {string}n */nn _this.currentCursorMode = null;n /**n * Internal cached let.n *n * @privaten * @member {string}n */nn _this.cursor = null;n /**n * ray caster, for survey intersects from 3d-scenen *n * @privaten * @member {Raycaster}n */nn _this.raycaster = new Raycaster();n /**n * snippet timen *n * @privaten * @member {Number}n */nn _this._deltaTime = 0;nn _this.setTargetElement(_this.renderer.domElement);n /**n * Fired when a pointer device button (usually a mouse left-button) is pressed on the displayn * object.n *n * @event InteractionManager#mousedownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * on the display object.n *n * @event InteractionManager#rightdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released over the displayn * object.n *n * @event InteractionManager#mouseupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * over the display object.n *n * @event InteractionManager#rightupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed and released onn * the display object.n *n * @event InteractionManager#clickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * and released on the display object.n *n * @event InteractionManager#rightclickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released outside then * display object that initially registered an * [mousedown]{@link InteractionManager#event:mousedown}.n *n * @event InteractionManager#mouseupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * outside the display object that initially registered an * [rightdown]{@link InteractionManager#event:rightdown}.n *n * @event InteractionManager#rightupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved while over the display objectn *n * @event InteractionManager#mousemoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved onto the display objectn *n * @event InteractionManager#mouseovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved off the display objectn *n * @event InteractionManager#mouseoutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed on the display object.n *n * @event InteractionManager#pointerdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released over the display object.n *n * @event InteractionManager#pointerupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a pointer eventn *n * @event InteractionManager#pointercanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed and released on the display object.n *n * @event InteractionManager#pointertapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released outside the display object that initiallyn * registered a [pointerdown]{@link InteractionManager#event:pointerdown}.n *n * @event InteractionManager#pointerupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved while over the display objectn *n * @event InteractionManager#pointermoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved onto the display objectn *n * @event InteractionManager#pointerovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved off the display objectn *n * @event InteractionManager#pointeroutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed on the display object.n *n * @event InteractionManager#touchstartn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed from the display object.n *n * @event InteractionManager#touchendn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a touchn *n * @event InteractionManager#touchcanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed and removed from the display object.n *n * @event InteractionManager#tapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed outside of the display object that initiallyn * registered a [touchstart]{@link InteractionManager#event:touchstart}.n *n * @event InteractionManager#touchendoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is moved along the display object.n *n * @event InteractionManager#touchmoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.n * object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mousedownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released over the displayn * object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed and released onn * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#clickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightclickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released outside then * display object that initially registered an * [mousedown]{@link Object3D#event:mousedown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * outside the display object that initially registered an * [rightdown]{@link Object3D#event:rightdown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved while over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mousemoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved onto the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved off the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseoutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a pointer event.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointercanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed and released on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointertapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released outside the display object that initiallyn * registered a [pointerdown]{@link Object3D#event:pointerdown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved while over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointermoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved onto the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved off the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointeroutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchstartn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed from the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchendn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a touch.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchcanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed and removed from the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#tapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed outside of the display object that initiallyn * registered a [touchstart]{@link Object3D#event:touchstart}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchendoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is moved along the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchmoven * @param {InteractionEvent} event - Interaction eventn */nnn return _this;n }n /**n * Hit tests a point against the display tree, returning the first interactive object that is hit.n *n * @param {Point} globalPoint - A point to hit test with, in global space.n * @param {Object3D} [root] - The root display object to start from. If omitted, defaultsn * to the last rendered root of the associated renderer.n * @return {Object3D} The hit display object, if any.n */nnn createClass(InteractionManager, [{n key: 'hitTest',n value: function hitTest(globalPoint, root) {n // clear the target for our hit testn hitTestEvent.target = null; // assign the global pointnn hitTestEvent.data.global = globalPoint; // ensure safety of the rootnn if (!root) {n root = this.scene;n } // run the hit testnnn this.processInteractive(hitTestEvent, root, null, true); // return our found object - it'll be null if we didn't hit anythingnn return hitTestEvent.target;n }n /**n * Sets the DOM element which will receive mouse/touch events. This is useful for when you haven * other DOM elements on top of the renderers Canvas element. With this you'll be bale to deletegaten * another DOM element to receive those events.n *n * @param {HTMLCanvasElement} element - the DOM element which will receive mouse and touch events.n */nn }, {n key: 'setTargetElement',n value: function setTargetElement(element) {n this.removeEvents();n this.interactionDOMElement = element;n this.addEvents();n }n /**n * Registers all the DOM eventsn *n * @privaten */nn }, {n key: 'addEvents',n value: function addEvents() {n if (!this.interactionDOMElement || this.eventsAdded) {n return;n }nn this.emit('addevents');n this.interactionDOMElement.addEventListener('click', this.onClick, true);nn if (window.navigator.msPointerEnabled) {n this.interactionDOMElement.style = 'none';n this.interactionDOMElement.style = 'none';n } else if (this.supportsPointerEvents) {n this.interactionDOMElement.style = 'none';n }n /**n * These events are added first, so that if pointer events are normalised, they are firedn * in the same order as non-normalised events. ie. pointer event 1st, mouse / touch 2ndn */nnn if (this.supportsPointerEvents) {n window.document.addEventListener('pointermove', this.onPointerMove, true);n this.interactionDOMElement.addEventListener('pointerdown', this.onPointerDown, true); // pointerout is fired in addition to pointerup (for touch events) and pointercanceln // we already handle those, so for the purposes of what we do in onPointerOut, we onlyn // care about the pointerleave eventnn this.interactionDOMElement.addEventListener('pointerleave', this.onPointerOut, true);n this.interactionDOMElement.addEventListener('pointerover', this.onPointerOver, true);n window.addEventListener('pointercancel', this.onPointerCancel, true);n window.addEventListener('pointerup', this.onPointerUp, true);n } else {n window.document.addEventListener('mousemove', this.onPointerMove, true);n this.interactionDOMElement.addEventListener('mousedown', this.onPointerDown, true);n this.interactionDOMElement.addEventListener('mouseout', this.onPointerOut, true);n this.interactionDOMElement.addEventListener('mouseover', this.onPointerOver, true);n window.addEventListener('mouseup', this.onPointerUp, true);n } // always look directly for touch events so that we can provide original datan // In a future version we should change this to being just a fallback and rely solely onn // PointerEvents whenever availablennn if (this.supportsTouchEvents) {n this.interactionDOMElement.addEventListener('touchstart', this.onPointerDown, true);n this.interactionDOMElement.addEventListener('touchcancel', this.onPointerCancel, true);n this.interactionDOMElement.addEventListener('touchend', this.onPointerUp, true);n this.interactionDOMElement.addEventListener('touchmove', this.onPointerMove, true);n }nn this.eventsAdded = true;n }n /**n * Removes all the DOM events that were previously registeredn *n * @privaten */nn }, {n key: 'removeEvents',n value: function removeEvents() {n if (!this.interactionDOMElement) {n return;n }nn this.emit('removeevents');n this.interactionDOMElement.removeEventListener('click', this.onClick, true);nn if (window.navigator.msPointerEnabled) {n this.interactionDOMElement.style = '';n this.interactionDOMElement.style = '';n } else if (this.supportsPointerEvents) {n this.interactionDOMElement.style = '';n }nn if (this.supportsPointerEvents) {n window.document.removeEventListener('pointermove', this.onPointerMove, true);n this.interactionDOMElement.removeEventListener('pointerdown', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('pointerleave', this.onPointerOut, true);n this.interactionDOMElement.removeEventListener('pointerover', this.onPointerOver, true);n window.removeEventListener('pointercancel', this.onPointerCancel, true);n window.removeEventListener('pointerup', this.onPointerUp, true);n } else {n window.document.removeEventListener('mousemove', this.onPointerMove, true);n this.interactionDOMElement.removeEventListener('mousedown', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('mouseout', this.onPointerOut, true);n this.interactionDOMElement.removeEventListener('mouseover', this.onPointerOver, true);n window.removeEventListener('mouseup', this.onPointerUp, true);n }nn if (this.supportsTouchEvents) {n this.interactionDOMElement.removeEventListener('touchstart', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('touchcancel', this.onPointerCancel, true);n this.interactionDOMElement.removeEventListener('touchend', this.onPointerUp, true);n this.interactionDOMElement.removeEventListener('touchmove', this.onPointerMove, true);n }nn this.interactionDOMElement = null;n this.eventsAdded = false;n }n /**n * Updates the state of interactive objects.n * Invoked by a throttled ticker.n *n * @param {number} deltaTime - time delta since last tickn */nn }, {n key: 'update',n value: function update(_ref) {n var snippet = _ref.snippet;n this._deltaTime += snippet;nn if (this._deltaTime < this.interactionFrequency) {n return;n }nn this._deltaTime = 0;nn if (!this.interactionDOMElement) {n return;n } // if the user move the mouse this check has already been done using the mouse move!nnn if (this.didMove) {n this.didMove = false;n return;n }nn this.cursor = null; // Resets the flag as set by a stopPropagation call. This flag is usually reset by a user interaction of any kind,n // but there was a scenario of a display object moving under a static mouse cursor.n // In this case, mouseover and mouseevents would not pass the flag test in triggerEvent functionnn for (var k in this.activeInteractionData) {n // eslint-disable-next-line no-prototype-builtinsn if (this.activeInteractionData.hasOwnProperty(k)) {n var interactionData = this.activeInteractionData;nn if (interactionData.originalEvent && interactionData.pointerType !== 'touch') {n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, interactionData.originalEvent, interactionData);n this.processInteractive(interactionEvent, this.scene, this.processPointerOverOut, true);n }n }n }nn this.setCursorMode(this.cursor); // TODOn }n /**n * Sets the current cursor mode, handling any callbacks or CSS style changes.n *n * @param {string} mode - cursor mode, a key from the cursorStyles dictionaryn */nn }, {n key: 'setCursorMode',n value: function setCursorMode(mode) {n mode = mode || 'default'; // if the mode didn't actually change, bail earlynn if (this.currentCursorMode === mode) {n return;n }nn this.currentCursorMode = mode;n var style = this.cursorStyles; // only do things if there is a cursor style for itnn if (style) {n switch (typeof style === 'undefined' ? 'undefined' : _typeof(style)) {n case 'string':n // string styles are handled as cursor CSSn this.interactionDOMElement.style.cursor = style;n break;nn case 'function':n // functions are just called, and passed the cursor moden style(mode);n break;nn case 'object':n // if it is an object, assume that it is a dictionary of CSS styles,n // apply it to the interactionDOMElementn Object.assign(this.interactionDOMElement.style, style);n break;nn default:n break;n }n } else if (typeof mode === 'string' && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) {n // if it mode is a string (not a Symbol) and cursorStyles doesn't have any entryn // for the mode, then assume that the dev wants it to be CSS for the cursor.n this.interactionDOMElement.style.cursor = mode;n }n }n /**n * Dispatches an event on the display object that was interacted withn *n * @param {Object3D} displayObject - the display object in questionn * @param {string} eventString - the name of the event (e.g, mousedown)n * @param {object} eventData - the event data objectn * @privaten */nn }, {n key: 'triggerEvent',n value: function triggerEvent(displayObject, eventString, eventData) {n if (!eventData.stopped) {n eventData.currentTarget = displayObject;n eventData.type = eventString;n displayObject.emit(eventString, eventData);nn if (displayObject) {n displayObject(eventData);n }n }n }n /**n * This function is provides a neat way of crawling through the scene graph and running an * specified function on all interactive objects it finds. It will also take care of hitn * testing the interactive objects and passes the hit across in the function.n *n * @privaten * @param {InteractionEvent} interactionEvent - event containing the point thatn * is tested for collisionn * @param {Object3D} displayObject - the displayObjectn * that will be hit test (recursively crawls its children)n * @param {Function} [func] - the function that will be called on each interactive object. Then * interactionEvent, displayObject and hit will be passed to the functionn * @param {boolean} [hitTest] - this indicates if the objects inside should be hit test against the pointn * @param {boolean} [interactive] - Whether the displayObject is interactiven * @return {boolean} returns true if the displayObject hit the pointn */nn }, {n key: 'processInteractive',n value: function processInteractive(interactionEvent, displayObject, func, hitTest, interactive) {n if (!displayObject || !displayObject.visible) {n return false;n } // Took a little while to rework this function correctly! But now it is done and nice and optimised. ^_^n //n // This function will now loop through all objects and then only hit test the objects it HASn // to, not all of them. MUCH faster..n // An object will be hit test if the following is true:n //n // 1: It is interactive.n // 2: It belongs to a parent that is interactive AND one of the parents children have not already been hit.n //n // As another little optimisation once an interactive object has been hit we can carry onn // through the scenegraph, but we know that there will be no more hits! So we can avoid extra hit testsn // A final optimisation is that an object is not hit test directly if a child has already been hit.nnn interactive = displayObject.interactive || interactive;n var hit = false;n var interactiveParent = interactive;nn if (displayObject.interactiveChildren && displayObject.children) {n var children = displayObject.children;nn for (var i = children.length - 1; i >= 0; i–) {n var child = children; // time to get recursive.. if this function will return if something is hit..nn var childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);nn if (childHit) {n // its a good idea to check if a child has lost its parent.n // this means it has been removed whilst looping so its bestn if (!child.parent) {n continue;n } // we no longer need to hit test any more objects in this container as we wen // now know the parent has been hitnnn interactiveParent = false; // If the child is interactive , that means that the object hit was actuallyn // interactive and not just the child of an interactive object.n // This means we no longer need to hit test anything else. We still need to runn // through all objects, but we don't need to perform any hit tests.nn if (childHit) {n if (interactionEvent.target) {n hitTest = false;n }nn hit = true;n }n }n }n } // no point running this if the item is not interactive or does not have an interactive parent.nnn if (interactive) {n // if we are hit testing (as in we have no hit any objects yet)n // We also don't need to worry about hit testing if once of the displayObjects childrenn // has already been hit - but only if it was interactive, otherwise we need to keepn // looking for an interactive child, just in case we hit onen if (hitTest && !interactionEvent.target) {n if (interactionEvent.intersects && interactionEvent.intersects.object === displayObject) {n hit = true;n }n }nn if (displayObject.interactive) {n if (hit && !interactionEvent.target) {n interactionEvent.data.target = interactionEvent.target = displayObject;n }nn if (func) {n func(interactionEvent, displayObject, !!hit);n }n }n }nn return hit;n }n /**n * Is called when the click is pressed down on the renderer elementn *n * @privaten * @param {MouseEvent} originalEvent - The DOM event of a click being pressed downn */nn }, {n key: 'onClick',n value: function onClick(originalEvent) {n if (originalEvent.type !== 'click') return;n var events = this.normalizeToPointerData(originalEvent);nn if (this.autoPreventDefault && events.isNormalized) {n originalEvent.preventDefault();n }nn var interactionData = this.getInteractionDataForPointerId(events);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, events, interactionData);n interactionEvent.data.originalEvent = originalEvent;n this.processInteractive(interactionEvent, this.scene, this.processClick, true);n this.emit('click', interactionEvent);n }n /**n * Processes the result of the click check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processClick',n value: function processClick(interactionEvent, displayObject, hit) {n if (hit) {n this.triggerEvent(displayObject, 'click', interactionEvent);n }n }n /**n * Is called when the pointer button is pressed down on the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being pressed downn */nn }, {n key: 'onPointerDown',n value: function onPointerDown(originalEvent) {n // if we support touch events, then only use those for touch events, not pointer eventsn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent);n /**n * No need to prevent default on natural pointer events, as there are no side effectsn * Normalized events, however, may have the double mousedown/touchstart issue on the native android browser,n * so still need to be prevented.n */n // Guaranteed that there will be at least one event in events, and all events must have the same pointer typenn if (this.autoPreventDefault && events.isNormalized) {n originalEvent.preventDefault();n }nn var eventLen = events.length;nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent;n this.processInteractive(interactionEvent, this.scene, this.processPointerDown, true);n this.emit('pointerdown', interactionEvent);nn if (event.pointerType === 'touch') {n this.emit('touchstart', interactionEvent);n } else if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n var isRightButton = event.button === 2;n this.emit(isRightButton ? 'rightdown' : 'mousedown', this.eventData);n }n }n }n /**n * Processes the result of the pointer down check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerDown',n value: function processPointerDown(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;nn if (hit) {n if (!displayObject.trackedPointers) {n displayObject.trackedPointers = new InteractionTrackingData(id);n }nn this.triggerEvent(displayObject, 'pointerdown', interactionEvent);nn if (data.pointerType === 'touch') {n displayObject.started = true;n this.triggerEvent(displayObject, 'touchstart', interactionEvent);n } else if (data.pointerType === 'mouse' || data.pointerType === 'pen') {n var isRightButton = data.button === 2;nn if (isRightButton) {n displayObject.trackedPointers.rightDown = true;n } else {n displayObject.trackedPointers.leftDown = true;n }nn this.triggerEvent(displayObject, isRightButton ? 'rightdown' : 'mousedown', interactionEvent);n }n }n }n /**n * Is called when the pointer button is released on the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being releasedn * @param {boolean} cancelled - true if the pointer is cancelledn * @param {Function} func - Function passed to {@link processInteractive}n */nn }, {n key: 'onPointerComplete',n value: function onPointerComplete(originalEvent, cancelled, func) {n var events = this.normalizeToPointerData(originalEvent);n var eventLen = events.length; // if the event wasn't targeting our canvas, then consider it to be pointerupoutsiden // in all cases (unless it was a pointercancel)nn var eventAppend = originalEvent.target !== this.interactionDOMElement ? 'outside' : '';nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent; // perform hit testing for events targeting our canvas or cancel eventsnn this.processInteractive(interactionEvent, this.scene, func, cancelled || !eventAppend);n this.emit(cancelled ? 'pointercancel' : 'pointerup' + eventAppend, interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n var isRightButton = event.button === 2;n this.emit(isRightButton ? 'rightup' + eventAppend : 'mouseup' + eventAppend, interactionEvent);n } else if (event.pointerType === 'touch') {n this.emit(cancelled ? 'touchcancel' : 'touchend' + eventAppend, interactionEvent);n this.releaseInteractionDataForPointerId(event.pointerId, interactionData);n }n }n }n /**n * Is called when the pointer button is cancelledn *n * @privaten * @param {PointerEvent} event - The DOM event of a pointer button being releasedn */nn }, {n key: 'onPointerCancel',n value: function onPointerCancel(event) {n // if we support touch events, then only use those for touch events, not pointer eventsn if (this.supportsTouchEvents && event.pointerType === 'touch') return;n this.onPointerComplete(event, true, this.processPointerCancel);n }n /**n * Processes the result of the pointer cancel check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn */nn }, {n key: 'processPointerCancel',n value: function processPointerCancel(interactionEvent, displayObject) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;nn if (displayObject.trackedPointers !== undefined) {n delete displayObject.trackedPointers;n this.triggerEvent(displayObject, 'pointercancel', interactionEvent);nn if (data.pointerType === 'touch') {n this.triggerEvent(displayObject, 'touchcancel', interactionEvent);n }n }n }n /**n * Is called when the pointer button is released on the renderer elementn *n * @privaten * @param {PointerEvent} event - The DOM event of a pointer button being releasedn */nn }, {n key: 'onPointerUp',n value: function onPointerUp(event) {n // if we support touch events, then only use those for touch events, not pointer eventsn if (this.supportsTouchEvents && event.pointerType === 'touch') return;n this.onPointerComplete(event, false, this.processPointerUp);n }n /**n * Processes the result of the pointer up check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerUp',n value: function processPointerUp(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;n var trackingData = displayObject.trackedPointers;n var isTouch = data.pointerType === 'touch';n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen'; // Mouse onlynn if (isMouse) {n var isRightButton = data.button === 2;n var flags = InteractionTrackingData.FLAGS;n var test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;n var isDown = trackingData !== undefined && trackingData.flags & test;nn if (hit) {n this.triggerEvent(displayObject, isRightButton ? 'rightup' : 'mouseup', interactionEvent);nn if (isDown) {n this.triggerEvent(displayObject, isRightButton ? 'rightclick' : 'leftclick', interactionEvent);n }n } else if (isDown) {n this.triggerEvent(displayObject, isRightButton ? 'rightupoutside' : 'mouseupoutside', interactionEvent);n } // update the down state of the tracking datannn if (trackingData) {n if (isRightButton) {n trackingData.rightDown = false;n } else {n trackingData.leftDown = false;n }n }n } // Pointers and Touches, and Mousennn if (isTouch && displayObject.started) {n displayObject.started = false;n this.triggerEvent(displayObject, 'touchend', interactionEvent);n }nn if (hit) {n this.triggerEvent(displayObject, 'pointerup', interactionEvent);nn if (trackingData) {n this.triggerEvent(displayObject, 'pointertap', interactionEvent);nn if (isTouch) {n this.triggerEvent(displayObject, 'tap', interactionEvent); // touches are no longer over (if they ever were) when we get the touchendn // so we should ensure that we don't keep pretending that they arenn trackingData.over = false;n }n }n } else if (trackingData) {n this.triggerEvent(displayObject, 'pointerupoutside', interactionEvent);n if (isTouch) this.triggerEvent(displayObject, 'touchendoutside', interactionEvent);n } // Only remove the tracking data if there is no over/down state still associated with itnnn if (trackingData && trackingData.none) {n delete displayObject.trackedPointers;n }n }n /**n * Is called when the pointer moves across the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer movingn */nn }, {n key: 'onPointerMove',n value: function onPointerMove(originalEvent) {n // if we support touch events, then only use those for touch events, not pointer eventsn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent);nn if (events.pointerType === 'mouse') {n this.didMove = true;n this.cursor = null;n }nn var eventLen = events.length;nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent;n var interactive = event.pointerType === 'touch' ? this.moveWhenInside : true;n this.processInteractive(interactionEvent, this.scene, this.processPointerMove, interactive);n this.emit('pointermove', interactionEvent);n if (event.pointerType === 'touch') this.emit('touchmove', interactionEvent);n if (event.pointerType === 'mouse' || event.pointerType === 'pen') this.emit('mousemove', interactionEvent);n }nn if (events.pointerType === 'mouse') {n this.setCursorMode(this.cursor); // TODO BUG for parents interactive object (border order issue)n }n }n /**n * Processes the result of the pointer move check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerMove',n value: function processPointerMove(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var isTouch = data.pointerType === 'touch';n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen';nn if (isMouse) {n this.processPointerOverOut(interactionEvent, displayObject, hit);n }nn if (isTouch && displayObject.started) this.triggerEvent(displayObject, 'touchmove', interactionEvent);nn if (!this.moveWhenInside || hit) {n this.triggerEvent(displayObject, 'pointermove', interactionEvent);n if (isMouse) this.triggerEvent(displayObject, 'mousemove', interactionEvent);n }n }n /**n * Is called when the pointer is moved out of the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer being moved outn */nn }, {n key: 'onPointerOut',n value: function onPointerOut(originalEvent) {n // if we support touch events, then only use those for touch events, not pointer eventsn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent); // Only mouse and pointer can call onPointerOut, so events will always be length 1nn var event = events;nn if (event.pointerType === 'mouse') {n this.mouseOverRenderer = false;n this.setCursorMode(null);n }nn var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = event;n this.processInteractive(interactionEvent, this.scene, this.processPointerOverOut, false);n this.emit('pointerout', interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n this.emit('mouseout', interactionEvent);n } else {n // we can get touchleave events after touchend, so we want to make sure we don'tn // introduce memory leaksn this.releaseInteractionDataForPointerId(interactionData.identifier);n }n }n /**n * Processes the result of the pointer over/out check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerOverOut',n value: function processPointerOverOut(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen';n var trackingData = displayObject.trackedPointers; // if we just moused over the display object, then we need to track that statenn if (hit && !trackingData) {n trackingData = displayObject.trackedPointers = new InteractionTrackingData(id);n }nn if (trackingData === undefined) return;nn if (hit && this.mouseOverRenderer) {n if (!trackingData.over) {n trackingData.over = true;n this.triggerEvent(displayObject, 'pointerover', interactionEvent);nn if (isMouse) {n this.triggerEvent(displayObject, 'mouseover', interactionEvent);n }n } // only change the cursor if it has not already been changed (by something deeper in then // display tree)nnn if (isMouse && this.cursor === null) {n this.cursor = displayObject.cursor;n }n } else if (trackingData.over) {n trackingData.over = false;n this.triggerEvent(displayObject, 'pointerout', this.eventData);nn if (isMouse) {n this.triggerEvent(displayObject, 'mouseout', interactionEvent);n } // if there is no mouse down information for the pointer, then it is safe to deletennn if (trackingData.none) {n delete displayObject.trackedPointers;n }n }n }n /**n * Is called when the pointer is moved into the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being moved into the renderer viewn */nn }, {n key: 'onPointerOver',n value: function onPointerOver(originalEvent) {n var events = this.normalizeToPointerData(originalEvent); // Only mouse and pointer can call onPointerOver, so events will always be length 1nn var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = event;nn if (event.pointerType === 'mouse') {n this.mouseOverRenderer = true;n }nn this.emit('pointerover', interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n this.emit('mouseover', interactionEvent);n }n }n /**n * Get InteractionData for a given pointerId. Store that data as welln *n * @privaten * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerDatan * @return {InteractionData} - Interaction data for the given pointer identifiern */nn }, {n key: 'getInteractionDataForPointerId',n value: function getInteractionDataForPointerId(event) {n var pointerId = event.pointerId;n var interactionData = void 0;nn if (pointerId === MOUSE_POINTER_ID || event.pointerType === 'mouse') {n interactionData = this.mouse;n } else if (this.activeInteractionData) {n interactionData = this.activeInteractionData;n } else {n interactionData = this.interactionDataPool.pop() || new InteractionData();n interactionData.identifier = pointerId;n this.activeInteractionData = interactionData;n } // copy properties from the event, so that we can make sure that touch/pointer specificn // data is availablennn interactionData._copyEvent(event);nn return interactionData;n }n /**n * Return unused InteractionData to the pool, for a given pointerIdn *n * @privaten * @param {number} pointerId - Identifier from a pointer eventn */nn }, {n key: 'releaseInteractionDataForPointerId',n value: function releaseInteractionDataForPointerId(pointerId) {n var interactionData = this.activeInteractionData;nn if (interactionData) {n delete this.activeInteractionData;nn interactionData._reset();nn this.interactionDataPool.push(interactionData);n }n }n /**n * Maps x and y coords from a DOM object and maps them correctly to the three.js view. Then * resulting value is stored in the point. This takes into account the fact that the DOMn * element could be scaled and positioned anywhere on the screen.n *n * @param {Vector2} point - the point that the result will be stored inn * @param {number} x - the x coord of the position to mapn * @param {number} y - the y coord of the position to mapn */nn }, {n key: 'mapPositionToPoint',n value: function mapPositionToPoint(point, x, y) {n var rect = void 0; // IE 11 fixnn if (!this.interactionDOMElement.parentElement) {n rect = {n x: 0,n y: 0,n left: 0,n top: 0,n width: 0,n height: 0n };n } else {n rect = this.interactionDOMElement.getBoundingClientRect();n }nn point.x = (x - rect.left) / rect.width * 2 - 1;n point.y = -((y - rect.top) / rect.height) * 2 + 1;n }n /**n * Configure an InteractionEvent to wrap a DOM PointerEvent and InteractionDatan *n * @privaten * @param {InteractionEvent} interactionEvent - The event to be configuredn * @param {PointerEvent} pointerEvent - The DOM event that will be paired with the InteractionEventn * @param {InteractionData} interactionData - The InteractionData that will be pairedn * with the InteractionEventn * @return {InteractionEvent} the interaction event that was passed inn */nn }, {n key: 'configureInteractionEventForDOMEvent',n value: function configureInteractionEventForDOMEvent(interactionEvent, pointerEvent, interactionData) {n interactionEvent.data = interactionData;n this.mapPositionToPoint(interactionData.global, pointerEvent.clientX, pointerEvent.clientY);n this.raycaster.setFromCamera(interactionData.global, this.camera); // Not really sure why this is happening, but it's how a previous version handled things TODO: there should be removenn if (pointerEvent.pointerType === 'touch') {n pointerEvent.globalX = interactionData.global.x;n pointerEvent.globalY = interactionData.global.y;n }nn interactionData.originalEvent = pointerEvent;nn interactionEvent._reset();nn interactionEvent.intersects = this.raycaster.intersectObjects(this.scene.children, true);n return interactionEvent;n }n /**n * Ensures that the original event object contains all data that a regular pointer event would haven *n * @privaten * @param {TouchEvent|MouseEvent|PointerEvent} event - The original event data from a touch or mouse eventn * @return {PointerEvent[]} An array containing a single normalized pointer event, in the case of a pointern * or mouse event, or a multiple normalized pointer events if there are multiple changed touchesn */nn }, {n key: 'normalizeToPointerData',n value: function normalizeToPointerData(event) {n var normalizedEvents = [];nn if (this.supportsTouchEvents && event instanceof TouchEvent) {n for (var i = 0, li = event.changedTouches.length; i < li; i++) {n var touch = event.changedTouches;n if (typeof touch.button === 'undefined') touch.button = event.touches.length ? 1 : 0;n if (typeof touch.buttons === 'undefined') touch.buttons = event.touches.length ? 1 : 0;nn if (typeof touch.isPrimary === 'undefined') {n touch.isPrimary = event.touches.length === 1 && event.type === 'touchstart';n }nn if (typeof touch.width === 'undefined') touch.width = touch.radiusX || 1;n if (typeof touch.height === 'undefined') touch.height = touch.radiusY || 1;n if (typeof touch.tiltX === 'undefined') touch.tiltX = 0;n if (typeof touch.tiltY === 'undefined') touch.tiltY = 0;n if (typeof touch.pointerType === 'undefined') touch.pointerType = 'touch';n if (typeof touch.pointerId === 'undefined') touch.pointerId = touch.identifier || 0;n if (typeof touch.pressure === 'undefined') touch.pressure = touch.force || 0.5;n touch.twist = 0;n touch.tangentialPressure = 0; // TODO: Remove these, as layerX/Y is not a standard, is deprecated, has unevenn // support, and the fill ins are not quite the samen // offsetX/Y might be okay, but is not the same as clientX/Y when the canvas's topn // left is not 0,0 on the pagenn if (typeof touch.layerX === 'undefined') touch.layerX = touch.offsetX = touch.clientX;n if (typeof touch.layerY === 'undefined') touch.layerY = touch.offsetY = touch.clientY; // mark the touch as normalized, just so that we know we did itnn touch.isNormalized = true;n normalizedEvents.push(touch);n }n } else if (event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof window.PointerEvent))) {n if (typeof event.isPrimary === 'undefined') event.isPrimary = true;n if (typeof event.width === 'undefined') event.width = 1;n if (typeof event.height === 'undefined') event.height = 1;n if (typeof event.tiltX === 'undefined') event.tiltX = 0;n if (typeof event.tiltY === 'undefined') event.tiltY = 0;n if (typeof event.pointerType === 'undefined') event.pointerType = 'mouse';n if (typeof event.pointerId === 'undefined') event.pointerId = MOUSE_POINTER_ID;n if (typeof event.pressure === 'undefined') event.pressure = 0.5;n event.twist = 0;n event.tangentialPressure = 0; // mark the mouse event as normalized, just so that we know we did itnn event.isNormalized = true;n normalizedEvents.push(event);n } else {n normalizedEvents.push(event);n }nn return normalizedEvents;n }n /**n * Destroys the interaction managern *n */nn }, {n key: 'destroy',n value: function destroy() {n this.removeEvents();n this.removeAllListeners();n this.renderer = null;n this.mouse = null;n this.eventData = null;n this.interactionDOMElement = null;n this.onPointerDown = null;n this.processPointerDown = null;n this.onPointerUp = null;n this.processPointerUp = null;n this.onPointerCancel = null;n this.processPointerCancel = null;n this.onPointerMove = null;n this.processPointerMove = null;n this.onPointerOut = null;n this.processPointerOverOut = null;n this.onPointerOver = null;n this._tempPoint = null;n }n }]);n return InteractionManager;n}(EventDispatcher);nnvar MOUSE_POINTER_ID$1 = 'MOUSE'; // helpers for hitTest() - only used inside hitTest()nnvar hitTestEvent$1 = {n target: null,n data: {n global: nulln }n};n/**n * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactiven * if its interactive parameter is set to truen * This manager also supports multitouch.n *n * reference to [pixi.js](www.pixijs.com/) impln *n * @privaten * @classn * @extends EventDispatchern */nnvar InteractionLayer = function (_EventDispatcher) {n inherits(InteractionLayer, _EventDispatcher);n /**n * @param {WebGLRenderer} renderer - A reference to the current renderern * @param {Object} [options] - The options for the manager.n * @param {Boolean} [options.autoPreventDefault=false] - Should the manager automatically prevent default browser actions.n * @param {Boolean} [options.autoAttach=true] - Should the manager automatically attach target element.n * @param {Number} [options.interactionFrequency=10] - Frequency increases the interaction events will be checked.n */nn function InteractionLayer(renderer, options) {n classCallCheck(this, InteractionLayer);nn var _this = possibleConstructorReturn(this, (InteractionLayer.__proto__ || Object.getPrototypeOf(InteractionLayer)).call(this));nn options = options || {};n /**n * The renderer this interaction manager works for.n *n * @member {WebGLRenderer}n */nn _this.renderer = renderer;n /**n * The renderer this interaction manager works for.n *n * @member {Layer}n */nn _this.layer = null;n /**n * The renderer this interaction manager works for.n *n * @member {Scene}n */n // this.scene = scene;nn /**n * The renderer this interaction manager works for.n *n * @member {Camera}n */n // this.camera = camera;nn /**n * Should default browser actions automatically be prevented.n * Does not apply to pointer events for backwards compatibilityn * preventDefault on pointer events stops mouse events from firingn * Thus, for every pointer event, there will always be either a mouse of touch event alongside it.n *n * @member {boolean}n * @default falsen */nn _this.autoPreventDefault = options.autoPreventDefault || false;n /**n * Frequency in milliseconds that the mousemove, moveover & mouseout interaction events will be checked.n *n * @member {number}n * @default 10n */nn _this.interactionFrequency = options.interactionFrequency || 10;n /**n * The mouse datan *n * @member {InteractionData}n */nn _this.mouse = new InteractionData();n _this.mouse.identifier = MOUSE_POINTER_ID$1; // setting the mouse to start off far off screen will mean that mouse over doesn // not get called before we even move the mouse.nn _this.mouse.global.set(-999999);n /**n * Actively tracked InteractionDatan *n * @privaten * @member {Object.<number,InteractionData>}n */nnn _this.activeInteractionData = {};n _this.activeInteractionData = _this.mouse;n /**n * Pool of unused InteractionDatan *n * @privaten * @member {InteractionData[]}n */nn _this.interactionDataPool = [];n /**n * An event data object to handle all the event tracking/dispatchingn *n * @member {object}n */nn _this.eventData = new InteractionEvent();n /**n * The DOM element to bind to.n *n * @privaten * @member {HTMLElement}n */nn _this.interactionDOMElement = null;n /**n * This property determines if mousemove and touchmove events are fired only when the cursorn * is over the object.n * Setting to true will make things work more in line with how the DOM verison works.n * Setting to false can make things easier for things like draggingn * It is currently set to false as this is how three.js used to work.n *n * @member {boolean}n * @default truen */nn _this.moveWhenInside = true;n /**n * Have events been attached to the dom element?n *n * @privaten * @member {boolean}n */nn _this.eventsAdded = false;n /**n * Is the mouse hovering over the renderer?n *n * @privaten * @member {boolean}n */nn _this.mouseOverRenderer = false;n /**n * Does the device support touch eventsn * www.w3.org/TR/touch-events/n *n * @readonlyn * @member {boolean}n */nn _this.supportsTouchEvents = 'ontouchstart' in window;n /**n * Does the device support pointer eventsn * www.w3.org/Submission/pointer-events/n *n * @readonlyn * @member {boolean}n */nn _this.supportsPointerEvents = !!window.PointerEvent; // this will make it so that you don't have to call bind all the timenn /**n * @privaten * @member {Function}n */nn _this.onClick = _this.onClick.bind(_this);n _this.processClick = _this.processClick.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerUp = _this.onPointerUp.bind(_this);n _this.processPointerUp = _this.processPointerUp.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerCancel = _this.onPointerCancel.bind(_this);n _this.processPointerCancel = _this.processPointerCancel.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerDown = _this.onPointerDown.bind(_this);n _this.processPointerDown = _this.processPointerDown.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerMove = _this.onPointerMove.bind(_this);n _this.processPointerMove = _this.processPointerMove.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerOut = _this.onPointerOut.bind(_this);n _this.processPointerOverOut = _this.processPointerOverOut.bind(_this);n /**n * @privaten * @member {Function}n */nn _this.onPointerOver = _this.onPointerOver.bind(_this);n /**n * Dictionary of how different cursor modes are handled. Strings are handled as CSS cursorn * values, objects are handled as dictionaries of CSS values for interactionDOMElement,n * and functions are called instead of changing the CSS.n * Default CSS cursor values are provided for 'default' and 'pointer' modes.n * @member {Object.<string, (string|Function|Object.<string, string>)>}n */nn _this.cursorStyles = {n "default": 'inherit',n pointer: 'pointer'n };n /**n * The mode of the cursor that is being used.n * The value of this is a key from the cursorStyles dictionary.n *n * @member {string}n */nn _this.currentCursorMode = null;n /**n * Internal cached let.n *n * @privaten * @member {string}n */nn _this.cursor = null;n /**n * ray caster, for survey intersects from 3d-scenen *n * @privaten * @member {Raycaster}n */nn _this.raycaster = new Raycaster();n /**n * snippet timen *n * @privaten * @member {Number}n */nn _this._deltaTime = 0;nn _this.setTargetElement(_this.renderer.domElement);n /**n * Fired when a pointer device button (usually a mouse left-button) is pressed on the displayn * object.n *n * @event InteractionLayer#mousedownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * on the display object.n *n * @event InteractionLayer#rightdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released over the displayn * object.n *n * @event InteractionLayer#mouseupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * over the display object.n *n * @event InteractionLayer#rightupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed and released onn * the display object.n *n * @event InteractionLayer#clickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * and released on the display object.n *n * @event InteractionLayer#rightclickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released outside then * display object that initially registered an * [mousedown]{@link InteractionLayer#event:mousedown}.n *n * @event InteractionLayer#mouseupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * outside the display object that initially registered an * [rightdown]{@link InteractionLayer#event:rightdown}.n *n * @event InteractionLayer#rightupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved while over the display objectn *n * @event InteractionLayer#mousemoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved onto the display objectn *n * @event InteractionLayer#mouseovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved off the display objectn *n * @event InteractionLayer#mouseoutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed on the display object.n *n * @event InteractionLayer#pointerdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released over the display object.n *n * @event InteractionLayer#pointerupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a pointer eventn *n * @event InteractionLayer#pointercanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed and released on the display object.n *n * @event InteractionLayer#pointertapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released outside the display object that initiallyn * registered a [pointerdown]{@link InteractionLayer#event:pointerdown}.n *n * @event InteractionLayer#pointerupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved while over the display objectn *n * @event InteractionLayer#pointermoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved onto the display objectn *n * @event InteractionLayer#pointerovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved off the display objectn *n * @event InteractionLayer#pointeroutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed on the display object.n *n * @event InteractionLayer#touchstartn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed from the display object.n *n * @event InteractionLayer#touchendn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a touchn *n * @event InteractionLayer#touchcanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed and removed from the display object.n *n * @event InteractionLayer#tapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed outside of the display object that initiallyn * registered a [touchstart]{@link InteractionLayer#event:touchstart}.n *n * @event InteractionLayer#touchendoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is moved along the display object.n *n * @event InteractionLayer#touchmoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed on the display.n * object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mousedownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released over the displayn * object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * over the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is pressed and released onn * the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#clickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is pressedn * and released on the display object. DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightclickn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button (usually a mouse left-button) is released outside then * display object that initially registered an * [mousedown]{@link Object3D#event:mousedown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device secondary button (usually a mouse right-button) is releasedn * outside the display object that initially registered an * [rightdown]{@link Object3D#event:rightdown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#rightupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved while over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mousemoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved onto the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device (usually a mouse) is moved off the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#mouseoutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerdownn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerupn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a pointer event.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointercanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is pressed and released on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointertapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device button is released outside the display object that initiallyn * registered a [pointerdown]{@link Object3D#event:pointerdown}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerupoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved while over the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointermoven * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved onto the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointerovern * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a pointer device is moved off the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#pointeroutn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed on the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchstartn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed from the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchendn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when the operating system cancels a touch.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchcanceln * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is placed and removed from the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#tapn * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is removed outside of the display object that initiallyn * registered a [touchstart]{@link Object3D#event:touchstart}.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchendoutsiden * @param {InteractionEvent} event - Interaction eventn */nn /**n * Fired when a touch point is moved along the display object.n * DisplayObject's `interactive` property must be set to `true` to fire event.n *n * @event Object3D#touchmoven * @param {InteractionEvent} event - Interaction eventn */nnn return _this;n }n /**n * @return {boolean}n */nnn createClass(InteractionLayer, [{n key: 'isAble',n value: function isAble() {n return this.layer && this.layer.interactive;n }n /**n * set layern * @param {Layer} layer layern */nn }, {n key: 'setLayer',n value: function setLayer(layer) {n this.layer = layer;n }n /**n * Hit tests a point against the display tree, returning the first interactive object that is hit.n *n * @param {Point} globalPoint - A point to hit test with, in global space.n * @param {Object3D} [root] - The root display object to start from. If omitted, defaultsn * to the last rendered root of the associated renderer.n * @return {Object3D} The hit display object, if any.n */nn }, {n key: 'hitTest',n value: function hitTest(globalPoint, root) {n if (!this.isAble()) return null; // clear the target for our hit testnn hitTestEvent$1.target = null; // assign the global pointnn hitTestEvent$1.data.global = globalPoint; // ensure safety of the rootnn if (!root) {n root = this.layer.scene;n } // run the hit testnnn this.processInteractive(hitTestEvent$1, root, null, true); // return our found object - it'll be null if we didn't hit anythingnn return hitTestEvent$1.target;n }n /**n * Sets the DOM element which will receive mouse/touch events. This is useful for when you haven * other DOM elements on top of the renderers Canvas element. With this you'll be bale to deletegaten * another DOM element to receive those events.n *n * @param {HTMLCanvasElement} element - the DOM element which will receive mouse and touch events.n */nn }, {n key: 'setTargetElement',n value: function setTargetElement(element) {n this.removeEvents();n this.interactionDOMElement = element;n this.addEvents();n }n /**n * Registers all the DOM eventsn *n * @privaten */nn }, {n key: 'addEvents',n value: function addEvents() {n if (!this.interactionDOMElement || this.eventsAdded) {n return;n }nn this.emit('addevents');n this.interactionDOMElement.addEventListener('click', this.onClick, true);nn if (window.navigator.msPointerEnabled) {n this.interactionDOMElement.style = 'none';n this.interactionDOMElement.style = 'none';n } else if (this.supportsPointerEvents) {n this.interactionDOMElement.style = 'none';n }n /**n * These events are added first, so that if pointer events are normalised, they are firedn * in the same order as non-normalised events. ie. pointer event 1st, mouse / touch 2ndn */nnn if (this.supportsPointerEvents) {n window.document.addEventListener('pointermove', this.onPointerMove, true);n this.interactionDOMElement.addEventListener('pointerdown', this.onPointerDown, true); // pointerout is fired in addition to pointerup (for touch events) and pointercanceln // we already handle those, so for the purposes of what we do in onPointerOut, we onlyn // care about the pointerleave eventnn this.interactionDOMElement.addEventListener('pointerleave', this.onPointerOut, true);n this.interactionDOMElement.addEventListener('pointerover', this.onPointerOver, true);n window.addEventListener('pointercancel', this.onPointerCancel, true);n window.addEventListener('pointerup', this.onPointerUp, true);n } else {n window.document.addEventListener('mousemove', this.onPointerMove, true);n this.interactionDOMElement.addEventListener('mousedown', this.onPointerDown, true);n this.interactionDOMElement.addEventListener('mouseout', this.onPointerOut, true);n this.interactionDOMElement.addEventListener('mouseover', this.onPointerOver, true);n window.addEventListener('mouseup', this.onPointerUp, true);n } // always look directly for touch events so that we can provide original datan // In a future version we should change this to being just a fallback and rely solely onn // PointerEvents whenever availablennn if (this.supportsTouchEvents) {n this.interactionDOMElement.addEventListener('touchstart', this.onPointerDown, true);n this.interactionDOMElement.addEventListener('touchcancel', this.onPointerCancel, true);n this.interactionDOMElement.addEventListener('touchend', this.onPointerUp, true);n this.interactionDOMElement.addEventListener('touchmove', this.onPointerMove, true);n }nn this.eventsAdded = true;n }n /**n * Removes all the DOM events that were previously registeredn *n * @privaten */nn }, {n key: 'removeEvents',n value: function removeEvents() {n if (!this.interactionDOMElement) {n return;n }nn this.emit('removeevents');n this.interactionDOMElement.removeEventListener('click', this.onClick, true);nn if (window.navigator.msPointerEnabled) {n this.interactionDOMElement.style = '';n this.interactionDOMElement.style = '';n } else if (this.supportsPointerEvents) {n this.interactionDOMElement.style = '';n }nn if (this.supportsPointerEvents) {n window.document.removeEventListener('pointermove', this.onPointerMove, true);n this.interactionDOMElement.removeEventListener('pointerdown', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('pointerleave', this.onPointerOut, true);n this.interactionDOMElement.removeEventListener('pointerover', this.onPointerOver, true);n window.removeEventListener('pointercancel', this.onPointerCancel, true);n window.removeEventListener('pointerup', this.onPointerUp, true);n } else {n window.document.removeEventListener('mousemove', this.onPointerMove, true);n this.interactionDOMElement.removeEventListener('mousedown', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('mouseout', this.onPointerOut, true);n this.interactionDOMElement.removeEventListener('mouseover', this.onPointerOver, true);n window.removeEventListener('mouseup', this.onPointerUp, true);n }nn if (this.supportsTouchEvents) {n this.interactionDOMElement.removeEventListener('touchstart', this.onPointerDown, true);n this.interactionDOMElement.removeEventListener('touchcancel', this.onPointerCancel, true);n this.interactionDOMElement.removeEventListener('touchend', this.onPointerUp, true);n this.interactionDOMElement.removeEventListener('touchmove', this.onPointerMove, true);n }nn this.interactionDOMElement = null;n this.eventsAdded = false;n }n /**n * Updates the state of interactive objects.n * Invoked by a throttled ticker.n *n * @param {number} deltaTime - time delta since last tickn */nn }, {n key: 'update',n value: function update(_ref) {n var snippet = _ref.snippet;n if (!this.isAble()) return;n this._deltaTime += snippet;nn if (this._deltaTime < this.interactionFrequency) {n return;n }nn this._deltaTime = 0;nn if (!this.interactionDOMElement) {n return;n } // if the user move the mouse this check has already been done using the mouse move!nnn if (this.didMove) {n this.didMove = false;n return;n }nn this.cursor = null; // Resets the flag as set by a stopPropagation call. This flag is usually reset by a user interaction of any kind,n // but there was a scenario of a display object moving under a static mouse cursor.n // In this case, mouseover and mouseevents would not pass the flag test in triggerEvent functionnn for (var k in this.activeInteractionData) {n // eslint-disable-next-line no-prototype-builtinsn if (this.activeInteractionData.hasOwnProperty(k)) {n var interactionData = this.activeInteractionData;nn if (interactionData.originalEvent && interactionData.pointerType !== 'touch') {n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, interactionData.originalEvent, interactionData);n this.processInteractive(interactionEvent, this.layer.scene, this.processPointerOverOut, true);n }n }n }nn this.setCursorMode(this.cursor); // TODOn }n /**n * Sets the current cursor mode, handling any callbacks or CSS style changes.n *n * @param {string} mode - cursor mode, a key from the cursorStyles dictionaryn */nn }, {n key: 'setCursorMode',n value: function setCursorMode(mode) {n mode = mode || 'default'; // if the mode didn't actually change, bail earlynn if (this.currentCursorMode === mode) {n return;n }nn this.currentCursorMode = mode;n var style = this.cursorStyles; // only do things if there is a cursor style for itnn if (style) {n switch (typeof style === 'undefined' ? 'undefined' : _typeof(style)) {n case 'string':n // string styles are handled as cursor CSSn this.interactionDOMElement.style.cursor = style;n break;nn case 'function':n // functions are just called, and passed the cursor moden style(mode);n break;nn case 'object':n // if it is an object, assume that it is a dictionary of CSS styles,n // apply it to the interactionDOMElementn Object.assign(this.interactionDOMElement.style, style);n break;nn default:n break;n }n } else if (typeof mode === 'string' && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) {n // if it mode is a string (not a Symbol) and cursorStyles doesn't have any entryn // for the mode, then assume that the dev wants it to be CSS for the cursor.n this.interactionDOMElement.style.cursor = mode;n }n }n /**n * Dispatches an event on the display object that was interacted withn *n * @param {Object3D} displayObject - the display object in questionn * @param {string} eventString - the name of the event (e.g, mousedown)n * @param {object} eventData - the event data objectn * @privaten */nn }, {n key: 'triggerEvent',n value: function triggerEvent(displayObject, eventString, eventData) {n if (!eventData.stopped) {n eventData.currentTarget = displayObject;n eventData.type = eventString;n displayObject.emit(eventString, eventData);nn if (displayObject) {n displayObject(eventData);n }n }n }n /**n * This function is provides a neat way of crawling through the scene graph and running an * specified function on all interactive objects it finds. It will also take care of hitn * testing the interactive objects and passes the hit across in the function.n *n * @privaten * @param {InteractionEvent} interactionEvent - event containing the point thatn * is tested for collisionn * @param {Object3D} displayObject - the displayObjectn * that will be hit test (recursively crawls its children)n * @param {Function} [func] - the function that will be called on each interactive object. Then * interactionEvent, displayObject and hit will be passed to the functionn * @param {boolean} [hitTest] - this indicates if the objects inside should be hit test against the pointn * @param {boolean} [interactive] - Whether the displayObject is interactiven * @return {boolean} returns true if the displayObject hit the pointn */nn }, {n key: 'processInteractive',n value: function processInteractive(interactionEvent, displayObject, func, hitTest, interactive) {n if (!displayObject || !displayObject.visible) {n return false;n } // Took a little while to rework this function correctly! But now it is done and nice and optimised. ^_^n //n // This function will now loop through all objects and then only hit test the objects it HASn // to, not all of them. MUCH faster..n // An object will be hit test if the following is true:n //n // 1: It is interactive.n // 2: It belongs to a parent that is interactive AND one of the parents children have not already been hit.n //n // As another little optimisation once an interactive object has been hit we can carry onn // through the scenegraph, but we know that there will be no more hits! So we can avoid extra hit testsn // A final optimisation is that an object is not hit test directly if a child has already been hit.nnn interactive = displayObject.interactive || interactive;n var hit = false;n var interactiveParent = interactive;nn if (displayObject.interactiveChildren && displayObject.children) {n var children = displayObject.children;nn for (var i = children.length - 1; i >= 0; i–) {n var child = children; // time to get recursive.. if this function will return if something is hit..nn var childHit = this.processInteractive(interactionEvent, child, func, hitTest, interactiveParent);nn if (childHit) {n // its a good idea to check if a child has lost its parent.n // this means it has been removed whilst looping so its bestn if (!child.parent) {n continue;n } // we no longer need to hit test any more objects in this container as we wen // now know the parent has been hitnnn interactiveParent = false; // If the child is interactive , that means that the object hit was actuallyn // interactive and not just the child of an interactive object.n // This means we no longer need to hit test anything else. We still need to runn // through all objects, but we don't need to perform any hit tests.nn if (childHit) {n if (interactionEvent.target) {n hitTest = false;n }nn hit = true;n }n }n }n } // no point running this if the item is not interactive or does not have an interactive parent.nnn if (interactive) {n // if we are hit testing (as in we have no hit any objects yet)n // We also don't need to worry about hit testing if once of the displayObjects childrenn // has already been hit - but only if it was interactive, otherwise we need to keepn // looking for an interactive child, just in case we hit onen if (hitTest && !interactionEvent.target) {n if (interactionEvent.intersects && interactionEvent.intersects.object === displayObject) {n hit = true;n }n }nn if (displayObject.interactive) {n if (hit && !interactionEvent.target) {n interactionEvent.data.target = interactionEvent.target = displayObject;n }nn if (func) {n func(interactionEvent, displayObject, !!hit);n }n }n }nn return hit;n }n /**n * Is called when the click is pressed down on the renderer elementn *n * @privaten * @param {MouseEvent} originalEvent - The DOM event of a click being pressed downn */nn }, {n key: 'onClick',n value: function onClick(originalEvent) {n if (!this.isAble()) return;n if (originalEvent.type !== 'click') return;n var events = this.normalizeToPointerData(originalEvent);nn if (this.autoPreventDefault && events.isNormalized) {n originalEvent.preventDefault();n }nn var interactionData = this.getInteractionDataForPointerId(events);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, events, interactionData);n interactionEvent.data.originalEvent = originalEvent;n this.processInteractive(interactionEvent, this.layer.scene, this.processClick, true);n this.emit('click', interactionEvent);n }n /**n * Processes the result of the click check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processClick',n value: function processClick(interactionEvent, displayObject, hit) {n if (hit) {n this.triggerEvent(displayObject, 'click', interactionEvent);n }n }n /**n * Is called when the pointer button is pressed down on the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being pressed downn */nn }, {n key: 'onPointerDown',n value: function onPointerDown(originalEvent) {n if (!this.isAble()) return; // if we support touch events, then only use those for touch events, not pointer eventsnn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent);n /**n * No need to prevent default on natural pointer events, as there are no side effectsn * Normalized events, however, may have the double mousedown/touchstart issue on the native android browser,n * so still need to be prevented.n */n // Guaranteed that there will be at least one event in events, and all events must have the same pointer typenn if (this.autoPreventDefault && events.isNormalized) {n originalEvent.preventDefault();n }nn var eventLen = events.length;nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent;n this.processInteractive(interactionEvent, this.layer.scene, this.processPointerDown, true);n this.emit('pointerdown', interactionEvent);nn if (event.pointerType === 'touch') {n this.emit('touchstart', interactionEvent);n } else if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n var isRightButton = event.button === 2;n this.emit(isRightButton ? 'rightdown' : 'mousedown', this.eventData);n }n }n }n /**n * Processes the result of the pointer down check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerDown',n value: function processPointerDown(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;nn if (hit) {n if (!displayObject.trackedPointers) {n displayObject.trackedPointers = new InteractionTrackingData(id);n }nn this.triggerEvent(displayObject, 'pointerdown', interactionEvent);nn if (data.pointerType === 'touch') {n displayObject.started = true;n this.triggerEvent(displayObject, 'touchstart', interactionEvent);n } else if (data.pointerType === 'mouse' || data.pointerType === 'pen') {n var isRightButton = data.button === 2;nn if (isRightButton) {n displayObject.trackedPointers.rightDown = true;n } else {n displayObject.trackedPointers.leftDown = true;n }nn this.triggerEvent(displayObject, isRightButton ? 'rightdown' : 'mousedown', interactionEvent);n }n }n }n /**n * Is called when the pointer button is released on the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being releasedn * @param {boolean} cancelled - true if the pointer is cancelledn * @param {Function} func - Function passed to {@link processInteractive}n */nn }, {n key: 'onPointerComplete',n value: function onPointerComplete(originalEvent, cancelled, func) {n var events = this.normalizeToPointerData(originalEvent);n var eventLen = events.length; // if the event wasn't targeting our canvas, then consider it to be pointerupoutsiden // in all cases (unless it was a pointercancel)nn var eventAppend = originalEvent.target !== this.interactionDOMElement ? 'outside' : '';nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent; // perform hit testing for events targeting our canvas or cancel eventsnn this.processInteractive(interactionEvent, this.layer.scene, func, cancelled || !eventAppend);n this.emit(cancelled ? 'pointercancel' : 'pointerup' + eventAppend, interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n var isRightButton = event.button === 2;n this.emit(isRightButton ? 'rightup' + eventAppend : 'mouseup' + eventAppend, interactionEvent);n } else if (event.pointerType === 'touch') {n this.emit(cancelled ? 'touchcancel' : 'touchend' + eventAppend, interactionEvent);n this.releaseInteractionDataForPointerId(event.pointerId, interactionData);n }n }n }n /**n * Is called when the pointer button is cancelledn *n * @privaten * @param {PointerEvent} event - The DOM event of a pointer button being releasedn */nn }, {n key: 'onPointerCancel',n value: function onPointerCancel(event) {n if (!this.isAble()) return; // if we support touch events, then only use those for touch events, not pointer eventsnn if (this.supportsTouchEvents && event.pointerType === 'touch') return;n this.onPointerComplete(event, true, this.processPointerCancel);n }n /**n * Processes the result of the pointer cancel check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn */nn }, {n key: 'processPointerCancel',n value: function processPointerCancel(interactionEvent, displayObject) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;nn if (displayObject.trackedPointers !== undefined) {n delete displayObject.trackedPointers;n this.triggerEvent(displayObject, 'pointercancel', interactionEvent);nn if (data.pointerType === 'touch') {n this.triggerEvent(displayObject, 'touchcancel', interactionEvent);n }n }n }n /**n * Is called when the pointer button is released on the renderer elementn *n * @privaten * @param {PointerEvent} event - The DOM event of a pointer button being releasedn */nn }, {n key: 'onPointerUp',n value: function onPointerUp(event) {n if (!this.isAble()) return; // if we support touch events, then only use those for touch events, not pointer eventsnn if (this.supportsTouchEvents && event.pointerType === 'touch') return;n this.onPointerComplete(event, false, this.processPointerUp);n }n /**n * Processes the result of the pointer up check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerUp',n value: function processPointerUp(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;n var trackingData = displayObject.trackedPointers;n var isTouch = data.pointerType === 'touch';n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen'; // Mouse onlynn if (isMouse) {n var isRightButton = data.button === 2;n var flags = InteractionTrackingData.FLAGS;n var test = isRightButton ? flags.RIGHT_DOWN : flags.LEFT_DOWN;n var isDown = trackingData !== undefined && trackingData.flags & test;nn if (hit) {n this.triggerEvent(displayObject, isRightButton ? 'rightup' : 'mouseup', interactionEvent);nn if (isDown) {n this.triggerEvent(displayObject, isRightButton ? 'rightclick' : 'leftclick', interactionEvent);n }n } else if (isDown) {n this.triggerEvent(displayObject, isRightButton ? 'rightupoutside' : 'mouseupoutside', interactionEvent);n } // update the down state of the tracking datannn if (trackingData) {n if (isRightButton) {n trackingData.rightDown = false;n } else {n trackingData.leftDown = false;n }n }n } // Pointers and Touches, and Mousennn if (isTouch && displayObject.started) {n displayObject.started = false;n this.triggerEvent(displayObject, 'touchend', interactionEvent);n }nn if (hit) {n this.triggerEvent(displayObject, 'pointerup', interactionEvent);nn if (trackingData) {n this.triggerEvent(displayObject, 'pointertap', interactionEvent);nn if (isTouch) {n this.triggerEvent(displayObject, 'tap', interactionEvent); // touches are no longer over (if they ever were) when we get the touchendn // so we should ensure that we don't keep pretending that they arenn trackingData.over = false;n }n }n } else if (trackingData) {n this.triggerEvent(displayObject, 'pointerupoutside', interactionEvent);n if (isTouch) this.triggerEvent(displayObject, 'touchendoutside', interactionEvent);n } // Only remove the tracking data if there is no over/down state still associated with itnnn if (trackingData && trackingData.none) {n delete displayObject.trackedPointers;n }n }n /**n * Is called when the pointer moves across the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer movingn */nn }, {n key: 'onPointerMove',n value: function onPointerMove(originalEvent) {n if (!this.isAble()) return; // if we support touch events, then only use those for touch events, not pointer eventsnn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent);nn if (events.pointerType === 'mouse') {n this.didMove = true;n this.cursor = null;n }nn var eventLen = events.length;nn for (var i = 0; i < eventLen; i++) {n var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = originalEvent;n var interactive = event.pointerType === 'touch' ? this.moveWhenInside : true;n this.processInteractive(interactionEvent, this.layer.scene, this.processPointerMove, interactive);n this.emit('pointermove', interactionEvent);n if (event.pointerType === 'touch') this.emit('touchmove', interactionEvent);n if (event.pointerType === 'mouse' || event.pointerType === 'pen') this.emit('mousemove', interactionEvent);n }nn if (events.pointerType === 'mouse') {n this.setCursorMode(this.cursor); // TODO BUG for parents interactive object (border order issue)n }n }n /**n * Processes the result of the pointer move check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerMove',n value: function processPointerMove(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var isTouch = data.pointerType === 'touch';n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen';nn if (isMouse) {n this.processPointerOverOut(interactionEvent, displayObject, hit);n }nn if (isTouch && displayObject.started) this.triggerEvent(displayObject, 'touchmove', interactionEvent);nn if (!this.moveWhenInside || hit) {n this.triggerEvent(displayObject, 'pointermove', interactionEvent);n if (isMouse) this.triggerEvent(displayObject, 'mousemove', interactionEvent);n }n }n /**n * Is called when the pointer is moved out of the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer being moved outn */nn }, {n key: 'onPointerOut',n value: function onPointerOut(originalEvent) {n if (!this.isAble()) return; // if we support touch events, then only use those for touch events, not pointer eventsnn if (this.supportsTouchEvents && originalEvent.pointerType === 'touch') return;n var events = this.normalizeToPointerData(originalEvent); // Only mouse and pointer can call onPointerOut, so events will always be length 1nn var event = events;nn if (event.pointerType === 'mouse') {n this.mouseOverRenderer = false;n this.setCursorMode(null);n }nn var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = event;n this.processInteractive(interactionEvent, this.layer.scene, this.processPointerOverOut, false);n this.emit('pointerout', interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n this.emit('mouseout', interactionEvent);n } else {n // we can get touchleave events after touchend, so we want to make sure we don'tn // introduce memory leaksn this.releaseInteractionDataForPointerId(interactionData.identifier);n }n }n /**n * Processes the result of the pointer over/out check and dispatches the event if need ben *n * @privaten * @param {InteractionEvent} interactionEvent - The interaction event wrapping the DOM eventn * @param {Object3D} displayObject - The display object that was testedn * @param {boolean} hit - the result of the hit test on the display objectn */nn }, {n key: 'processPointerOverOut',n value: function processPointerOverOut(interactionEvent, displayObject, hit) {n var data = interactionEvent.data;n var id = interactionEvent.data.identifier;n var isMouse = data.pointerType === 'mouse' || data.pointerType === 'pen';n var trackingData = displayObject.trackedPointers; // if we just moused over the display object, then we need to track that statenn if (hit && !trackingData) {n trackingData = displayObject.trackedPointers = new InteractionTrackingData(id);n }nn if (trackingData === undefined) return;nn if (hit && this.mouseOverRenderer) {n if (!trackingData.over) {n trackingData.over = true;n this.triggerEvent(displayObject, 'pointerover', interactionEvent);nn if (isMouse) {n this.triggerEvent(displayObject, 'mouseover', interactionEvent);n }n } // only change the cursor if it has not already been changed (by something deeper in then // display tree)nnn if (isMouse && this.cursor === null) {n this.cursor = displayObject.cursor;n }n } else if (trackingData.over) {n trackingData.over = false;n this.triggerEvent(displayObject, 'pointerout', this.eventData);nn if (isMouse) {n this.triggerEvent(displayObject, 'mouseout', interactionEvent);n } // if there is no mouse down information for the pointer, then it is safe to deletennn if (trackingData.none) {n delete displayObject.trackedPointers;n }n }n }n /**n * Is called when the pointer is moved into the renderer elementn *n * @privaten * @param {PointerEvent} originalEvent - The DOM event of a pointer button being moved into the renderer viewn */nn }, {n key: 'onPointerOver',n value: function onPointerOver(originalEvent) {n if (!this.isAble()) return;n var events = this.normalizeToPointerData(originalEvent); // Only mouse and pointer can call onPointerOver, so events will always be length 1nn var event = events;n var interactionData = this.getInteractionDataForPointerId(event);n var interactionEvent = this.configureInteractionEventForDOMEvent(this.eventData, event, interactionData);n interactionEvent.data.originalEvent = event;nn if (event.pointerType === 'mouse') {n this.mouseOverRenderer = true;n }nn this.emit('pointerover', interactionEvent);nn if (event.pointerType === 'mouse' || event.pointerType === 'pen') {n this.emit('mouseover', interactionEvent);n }n }n /**n * Get InteractionData for a given pointerId. Store that data as welln *n * @privaten * @param {PointerEvent} event - Normalized pointer event, output from normalizeToPointerDatan * @return {InteractionData} - Interaction data for the given pointer identifiern */nn }, {n key: 'getInteractionDataForPointerId',n value: function getInteractionDataForPointerId(event) {n var pointerId = event.pointerId;n var interactionData = void 0;nn if (pointerId === MOUSE_POINTER_ID$1 || event.pointerType === 'mouse') {n interactionData = this.mouse;n } else if (this.activeInteractionData) {n interactionData = this.activeInteractionData;n } else {n interactionData = this.interactionDataPool.pop() || new InteractionData();n interactionData.identifier = pointerId;n this.activeInteractionData = interactionData;n } // copy properties from the event, so that we can make sure that touch/pointer specificn // data is availablennn interactionData._copyEvent(event);nn return interactionData;n }n /**n * Return unused InteractionData to the pool, for a given pointerIdn *n * @privaten * @param {number} pointerId - Identifier from a pointer eventn */nn }, {n key: 'releaseInteractionDataForPointerId',n value: function releaseInteractionDataForPointerId(pointerId) {n var interactionData = this.activeInteractionData;nn if (interactionData) {n delete this.activeInteractionData;nn interactionData._reset();nn this.interactionDataPool.push(interactionData);n }n }n /**n * Maps x and y coords from a DOM object and maps them correctly to the three.js view. Then * resulting value is stored in the point. This takes into account the fact that the DOMn * element could be scaled and positioned anywhere on the screen.n *n * @param {Vector2} point - the point that the result will be stored inn * @param {number} x - the x coord of the position to mapn * @param {number} y - the y coord of the position to mapn */nn }, {n key: 'mapPositionToPoint',n value: function mapPositionToPoint(point, x, y) {n var rect = void 0; // IE 11 fixnn if (!this.interactionDOMElement.parentElement) {n rect = {n x: 0,n y: 0,n left: 0,n top: 0,n width: 0,n height: 0n };n } else {n rect = this.interactionDOMElement.getBoundingClientRect();n }nn point.x = (x - rect.left) / rect.width * 2 - 1;n point.y = -((y - rect.top) / rect.height) * 2 + 1;n }n /**n * Configure an InteractionEvent to wrap a DOM PointerEvent and InteractionDatan *n * @privaten * @param {InteractionEvent} interactionEvent - The event to be configuredn * @param {PointerEvent} pointerEvent - The DOM event that will be paired with the InteractionEventn * @param {InteractionData} interactionData - The InteractionData that will be pairedn * with the InteractionEventn * @return {InteractionEvent} the interaction event that was passed inn */nn }, {n key: 'configureInteractionEventForDOMEvent',n value: function configureInteractionEventForDOMEvent(interactionEvent, pointerEvent, interactionData) {n interactionEvent.data = interactionData;n this.mapPositionToPoint(interactionData.global, pointerEvent.clientX, pointerEvent.clientY);n if (this.layer && this.layer.interactive) this.raycaster.setFromCamera(interactionData.global, this.layer.camera); // Not really sure why this is happening, but it's how a previous version handled things TODO: there should be removenn if (pointerEvent.pointerType === 'touch') {n pointerEvent.globalX = interactionData.global.x;n pointerEvent.globalY = interactionData.global.y;n }nn interactionData.originalEvent = pointerEvent;nn interactionEvent._reset();nn interactionEvent.intersects = this.raycaster.intersectObjects(this.scene.children, true);n return interactionEvent;n }n /**n * Ensures that the original event object contains all data that a regular pointer event would haven *n * @privaten * @param {TouchEvent|MouseEvent|PointerEvent} event - The original event data from a touch or mouse eventn * @return {PointerEvent[]} An array containing a single normalized pointer event, in the case of a pointern * or mouse event, or a multiple normalized pointer events if there are multiple changed touchesn */nn }, {n key: 'normalizeToPointerData',n value: function normalizeToPointerData(event) {n var normalizedEvents = [];nn if (this.supportsTouchEvents && event instanceof TouchEvent) {n for (var i = 0, li = event.changedTouches.length; i < li; i++) {n var touch = event.changedTouches;n if (typeof touch.button === 'undefined') touch.button = event.touches.length ? 1 : 0;n if (typeof touch.buttons === 'undefined') touch.buttons = event.touches.length ? 1 : 0;nn if (typeof touch.isPrimary === 'undefined') {n touch.isPrimary = event.touches.length === 1 && event.type === 'touchstart';n }nn if (typeof touch.width === 'undefined') touch.width = touch.radiusX || 1;n if (typeof touch.height === 'undefined') touch.height = touch.radiusY || 1;n if (typeof touch.tiltX === 'undefined') touch.tiltX = 0;n if (typeof touch.tiltY === 'undefined') touch.tiltY = 0;n if (typeof touch.pointerType === 'undefined') touch.pointerType = 'touch';n if (typeof touch.pointerId === 'undefined') touch.pointerId = touch.identifier || 0;n if (typeof touch.pressure === 'undefined') touch.pressure = touch.force || 0.5;n touch.twist = 0;n touch.tangentialPressure = 0; // TODO: Remove these, as layerX/Y is not a standard, is deprecated, has unevenn // support, and the fill ins are not quite the samen // offsetX/Y might be okay, but is not the same as clientX/Y when the canvas's topn // left is not 0,0 on the pagenn if (typeof touch.layerX === 'undefined') touch.layerX = touch.offsetX = touch.clientX;n if (typeof touch.layerY === 'undefined') touch.layerY = touch.offsetY = touch.clientY; // mark the touch as normalized, just so that we know we did itnn touch.isNormalized = true;n normalizedEvents.push(touch);n }n } else if (event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof window.PointerEvent))) {n if (typeof event.isPrimary === 'undefined') event.isPrimary = true;n if (typeof event.width === 'undefined') event.width = 1;n if (typeof event.height === 'undefined') event.height = 1;n if (typeof event.tiltX === 'undefined') event.tiltX = 0;n if (typeof event.tiltY === 'undefined') event.tiltY = 0;n if (typeof event.pointerType === 'undefined') event.pointerType = 'mouse';n if (typeof event.pointerId === 'undefined') event.pointerId = MOUSE_POINTER_ID$1;n if (typeof event.pressure === 'undefined') event.pressure = 0.5;n event.twist = 0;n event.tangentialPressure = 0; // mark the mouse event as normalized, just so that we know we did itnn event.isNormalized = true;n normalizedEvents.push(event);n } else {n normalizedEvents.push(event);n }nn return normalizedEvents;n }n /**n * Destroys the interaction managern *n */nn }, {n key: 'destroy',n value: function destroy() {n this.removeEvents();n this.removeAllListeners();n this.renderer = null;n this.mouse = null;n this.eventData = null;n this.interactionDOMElement = null;n this.onPointerDown = null;n this.processPointerDown = null;n this.onPointerUp = null;n this.processPointerUp = null;n this.onPointerCancel = null;n this.processPointerCancel = null;n this.onPointerMove = null;n this.processPointerMove = null;n this.onPointerOut = null;n this.processPointerOverOut = null;n this.onPointerOver = null;n this._tempPoint = null;n }n }]);n return InteractionLayer;n}(EventDispatcher);nn(function () {n var lastTime = 0;n var vendors = ['ms', 'moz', 'webkit', 'o'];nn for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {n window.requestAnimationFrame = window[vendors + 'RequestAnimationFrame'];n window.cancelAnimationFrame = window[vendors + 'CancelAnimationFrame'] || window[vendors + 'CancelRequestAnimationFrame'];n }nn if (!window.requestAnimationFrame) {n window.requestAnimationFrame = function (callback) {n var currTime = new Date().getTime();n var timeToCall = Math.max(0, 16 - (currTime - lastTime));n var id = window.setTimeout(function () {n callback(currTime + timeToCall);n }, timeToCall);n lastTime = currTime + timeToCall;n return id;n };n }nn if (!window.cancelAnimationFrame) {n window.cancelAnimationFrame = function (id) {n clearTimeout(id);n };n }nn window.RAF = window.requestAnimationFrame;n window.CAF = window.cancelAnimationFrame;n})();n/**n * @extends EventDispatchern */nnnvar Ticker = function (_EventDispatcher) {n inherits(Ticker, _EventDispatcher);n /**n *n */nn function Ticker() {n classCallCheck(this, Ticker);nn var _this = possibleConstructorReturn(this, (Ticker.__proto__ || Object.getPrototypeOf(Ticker)).call(this));nn _this.timer = null;n _this.started = false;n /**n * pre-time cachen *n * @member {Number}n * @privaten */nn _this.pt = 0;n /**n * how long the time through, at this tickn *n * @member {Number}n * @privaten */nn _this.snippet = 0;nn _this.start();nn return _this;n }n /**n * start tick loopn */nnn createClass(Ticker, [{n key: 'start',n value: function start() {n var _this2 = this;nn if (this.started) return;nn var loop = function loop() {n _this2.timeline();nn _this2.emit('tick', {n snippet: _this2.snippetn });nn _this2.timer = RAF(loop);n };nn loop();n }n /**n * stop tick loopn */nn }, {n key: 'stop',n value: function stop() {n CAF(this.timer);n this.started = false;n }n /**n * get timeline snippetn *n * @privaten */nn }, {n key: 'timeline',n value: function timeline() {n this.snippet = Date.now() - this.pt;nn if (this.pt === 0 || this.snippet > 200) {n this.pt = Date.now();n this.snippet = Date.now() - this.pt;n }nn this.pt += this.snippet;n }n }]);n return Ticker;n}(EventDispatcher);n/**n * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactiven * if its interactive parameter is set to truen * This manager also supports multitouch.n *n * reference to [pixi.js](www.pixijs.com/) impln *n * @examplen * import { Scene, PerspectiveCamera, WebGLRenderer, Mesh, BoxGeometry, MeshBasicMaterial } from 'three';n * import { Interaction } from 'three.interaction';n * const renderer = new WebGLRenderer({ canvas: canvasElement });n * const scene = new Scene();n * const camera = new PerspectiveCamera(60, width / height, 0.1, 100);n *n * const interaction = new Interaction(renderer, scene, camera);n * // then you can bind every interaction event with any mesh which you had `add` into `scene` beforen * const cube = new Mesh(n * new BoxGeometry(1, 1, 1),n * new MeshBasicMaterial({ color: 0xffffff }),n * );n * scene.add(cube);n * cube.on('touchstart', ev => {n * console.log(ev);n * });n *n * cube.on('mousedown', ev => {n * console.log(ev);n * });n *n * cube.on('pointerdown', ev => {n * console.log(ev);n * });n * // and so on …n *n * // you can also listen on parent-node or any display-tree node,n * // source event will bubble up along with display-tree.n * // you can stop the bubble-up by invoke ev.stopPropagation function.n * scene.on('touchstart', ev => {n * console.log(ev);n * })n *n * @classn * @extends InteractionManagern */nnnvar Interaction = function (_InteractionManager) {n inherits(Interaction, _InteractionManager);n /**n * @param {WebGLRenderer} renderer - A reference to the current renderern * @param {Scene} scene - A reference to the current scenen * @param {Camera} camera - A reference to the current cameran * @param {Object} [options] - The options for the manager.n * @param {Boolean} [options.autoPreventDefault=false] - Should the manager automatically prevent default browser actions.n * @param {Boolean} [options.autoAttach=false] - Should the manager automatically attach target element.n * @param {Number} [options.interactionFrequency=10] - Frequency increases the interaction events will be checked.n */nn function Interaction(renderer, scene, camera, options) {n classCallCheck(this, Interaction);n options = Object.assign({n autoAttach: falsen }, options);n /**n * a tickern *n * @privaten * @member {Ticker}n */nn var _this = possibleConstructorReturn(this, (Interaction.__proto__ || Object.getPrototypeOf(Interaction)).call(this, renderer, scene, camera, options));nn _this.ticker = new Ticker();n /**n * update for some over eventn *n * @privaten */nn _this.update = _this.update.bind(_this);nn _this.on('addevents', function () {n _this.ticker.on('tick', _this.update);n });nn _this.on('removeevents', function () {n _this.ticker.off('tick', _this.update);n });nn _this.setTargetElement(_this.renderer.domElement);nn return _this;n }nn return Interaction;n}(InteractionManager);nnexport { InteractionManager, InteractionLayer, Interaction };”,“map”:null,“metadata”:{},“sourceType”:“module”}