kitchen-simulator
Version:
It is a kitchen simulator (self-contained micro-frontend).
1,173 lines (1,172 loc) • 112 kB
JavaScript
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _get from "@babel/runtime/helpers/esm/get";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _superPropGet(t, o, e, r) { var p = _get(_getPrototypeOf(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
/*!
* camera-controls
* https://github.com/yomotsu/camera-controls
* (c) 2017 @yomotsu
* Released under the MIT License.
*/
// see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons#value
var MOUSE_BUTTON = {
LEFT: 1,
RIGHT: 2,
MIDDLE: 4
};
var ACTION = Object.freeze({
NONE: 0,
ROTATE: 1,
TRUCK: 2,
OFFSET: 4,
DOLLY: 8,
ZOOM: 16,
TOUCH_ROTATE: 32,
TOUCH_TRUCK: 64,
TOUCH_OFFSET: 128,
TOUCH_DOLLY: 256,
TOUCH_ZOOM: 512,
TOUCH_DOLLY_TRUCK: 1024,
TOUCH_DOLLY_OFFSET: 2048,
TOUCH_DOLLY_ROTATE: 4096,
TOUCH_ZOOM_TRUCK: 8192,
TOUCH_ZOOM_OFFSET: 16384,
TOUCH_ZOOM_ROTATE: 32768
});
var DOLLY_DIRECTION = {
NONE: 0,
IN: 1,
OUT: -1
};
function isPerspectiveCamera(camera) {
return camera.isPerspectiveCamera;
}
function isOrthographicCamera(camera) {
return camera.isOrthographicCamera;
}
var PI_2 = Math.PI * 2;
var PI_HALF = Math.PI / 2;
var EPSILON = 1e-5;
var DEG2RAD = Math.PI / 180;
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
function approxZero(number) {
var error = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : EPSILON;
return Math.abs(number) < error;
}
function approxEquals(a, b) {
var error = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : EPSILON;
return approxZero(a - b, error);
}
function roundToStep(value, step) {
return Math.round(value / step) * step;
}
function infinityToMaxNumber(value) {
if (isFinite(value)) return value;
if (value < 0) return -Number.MAX_VALUE;
return Number.MAX_VALUE;
}
function maxNumberToInfinity(value) {
if (Math.abs(value) < Number.MAX_VALUE) return value;
return value * Infinity;
}
// https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html
// https://github.com/Unity-Technologies/UnityCsReference/blob/a2bdfe9b3c4cd4476f44bf52f848063bfaf7b6b9/Runtime/Export/Math/Mathf.cs#L308
function smoothDamp(current, target, currentVelocityRef, smoothTime) {
var maxSpeed = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : Infinity;
var deltaTime = arguments.length > 5 ? arguments[5] : undefined;
// Based on Game Programming Gems 4 Chapter 1.10
smoothTime = Math.max(0.0001, smoothTime);
var omega = 2 / smoothTime;
var x = omega * deltaTime;
var exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x);
var change = current - target;
var originalTo = target;
// Clamp maximum speed
var maxChange = maxSpeed * smoothTime;
change = clamp(change, -maxChange, maxChange);
target = current - change;
var temp = (currentVelocityRef.value + omega * change) * deltaTime;
currentVelocityRef.value = (currentVelocityRef.value - omega * temp) * exp;
var output = target + (change + temp) * exp;
// Prevent overshooting
if (originalTo - current > 0.0 === output > originalTo) {
output = originalTo;
currentVelocityRef.value = (output - originalTo) / deltaTime;
}
return output;
}
// https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html
// https://github.com/Unity-Technologies/UnityCsReference/blob/a2bdfe9b3c4cd4476f44bf52f848063bfaf7b6b9/Runtime/Export/Math/Vector3.cs#L97
function smoothDampVec3(current, target, currentVelocityRef, smoothTime) {
var maxSpeed = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : Infinity;
var deltaTime = arguments.length > 5 ? arguments[5] : undefined;
var out = arguments.length > 6 ? arguments[6] : undefined;
// Based on Game Programming Gems 4 Chapter 1.10
smoothTime = Math.max(0.0001, smoothTime);
var omega = 2 / smoothTime;
var x = omega * deltaTime;
var exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x);
var targetX = target.x;
var targetY = target.y;
var targetZ = target.z;
var changeX = current.x - targetX;
var changeY = current.y - targetY;
var changeZ = current.z - targetZ;
var originalToX = targetX;
var originalToY = targetY;
var originalToZ = targetZ;
// Clamp maximum speed
var maxChange = maxSpeed * smoothTime;
var maxChangeSq = maxChange * maxChange;
var magnitudeSq = changeX * changeX + changeY * changeY + changeZ * changeZ;
if (magnitudeSq > maxChangeSq) {
var magnitude = Math.sqrt(magnitudeSq);
changeX = changeX / magnitude * maxChange;
changeY = changeY / magnitude * maxChange;
changeZ = changeZ / magnitude * maxChange;
}
targetX = current.x - changeX;
targetY = current.y - changeY;
targetZ = current.z - changeZ;
var tempX = (currentVelocityRef.x + omega * changeX) * deltaTime;
var tempY = (currentVelocityRef.y + omega * changeY) * deltaTime;
var tempZ = (currentVelocityRef.z + omega * changeZ) * deltaTime;
currentVelocityRef.x = (currentVelocityRef.x - omega * tempX) * exp;
currentVelocityRef.y = (currentVelocityRef.y - omega * tempY) * exp;
currentVelocityRef.z = (currentVelocityRef.z - omega * tempZ) * exp;
out.x = targetX + (changeX + tempX) * exp;
out.y = targetY + (changeY + tempY) * exp;
out.z = targetZ + (changeZ + tempZ) * exp;
// Prevent overshooting
var origMinusCurrentX = originalToX - current.x;
var origMinusCurrentY = originalToY - current.y;
var origMinusCurrentZ = originalToZ - current.z;
var outMinusOrigX = out.x - originalToX;
var outMinusOrigY = out.y - originalToY;
var outMinusOrigZ = out.z - originalToZ;
if (origMinusCurrentX * outMinusOrigX + origMinusCurrentY * outMinusOrigY + origMinusCurrentZ * outMinusOrigZ > 0) {
out.x = originalToX;
out.y = originalToY;
out.z = originalToZ;
currentVelocityRef.x = (out.x - originalToX) / deltaTime;
currentVelocityRef.y = (out.y - originalToY) / deltaTime;
currentVelocityRef.z = (out.z - originalToZ) / deltaTime;
}
return out;
}
function extractClientCoordFromEvent(pointers, out) {
out.set(0, 0);
pointers.forEach(function (pointer) {
out.x += pointer.clientX;
out.y += pointer.clientY;
});
out.x /= pointers.length;
out.y /= pointers.length;
}
function notSupportedInOrthographicCamera(camera, message) {
if (isOrthographicCamera(camera)) {
console.warn("".concat(message, " is not supported in OrthographicCamera"));
return true;
}
return false;
}
var EventDispatcher = /*#__PURE__*/function () {
function EventDispatcher() {
_classCallCheck(this, EventDispatcher);
this._listeners = {};
}
/**
* Adds the specified event listener.
* @param type event name
* @param listener handler function
* @category Methods
*/
return _createClass(EventDispatcher, [{
key: "addEventListener",
value: function addEventListener(type, listener) {
var listeners = this._listeners;
if (listeners[type] === undefined) listeners[type] = [];
if (listeners[type].indexOf(listener) === -1) listeners[type].push(listener);
}
/**
* Presence of the specified event listener.
* @param type event name
* @param listener handler function
* @category Methods
*/
}, {
key: "hasEventListener",
value: function hasEventListener(type, listener) {
var listeners = this._listeners;
return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1;
}
/**
* Removes the specified event listener
* @param type event name
* @param listener handler function
* @category Methods
*/
}, {
key: "removeEventListener",
value: function removeEventListener(type, listener) {
var listeners = this._listeners;
var listenerArray = listeners[type];
if (listenerArray !== undefined) {
var index = listenerArray.indexOf(listener);
if (index !== -1) listenerArray.splice(index, 1);
}
}
/**
* Removes all event listeners
* @param type event name
* @category Methods
*/
}, {
key: "removeAllEventListeners",
value: function removeAllEventListeners(type) {
if (!type) {
this._listeners = {};
return;
}
if (Array.isArray(this._listeners[type])) this._listeners[type].length = 0;
}
/**
* Fire an event type.
* @param event DispatcherEvent
* @category Methods
*/
}, {
key: "dispatchEvent",
value: function dispatchEvent(event) {
var listeners = this._listeners;
var listenerArray = listeners[event.type];
if (listenerArray !== undefined) {
event.target = this;
var array = listenerArray.slice(0);
for (var i = 0, l = array.length; i < l; i++) {
array[i].call(this, event);
}
}
}
}]);
}();
var _a;
var VERSION = '2.8.4'; // will be replaced with `version` in package.json during the build process.
var TOUCH_DOLLY_FACTOR = 1 / 8;
var isMac = /Mac/.test((_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _a === void 0 ? void 0 : _a.platform);
var THREE;
var _ORIGIN;
var _AXIS_Y;
var _AXIS_Z;
var _v2;
var _v3A;
var _v3B;
var _v3C;
var _cameraDirection;
var _xColumn;
var _yColumn;
var _zColumn;
var _deltaTarget;
var _deltaOffset;
var _sphericalA;
var _sphericalB;
var _box3A;
var _box3B;
var _sphere;
var _quaternionA;
var _quaternionB;
var _rotationMatrix;
var _raycaster;
var CameraControls = /*#__PURE__*/function (_EventDispatcher) {
/**
* Creates a `CameraControls` instance.
*
* Note:
* You **must install** three.js before using camera-controls. see [#install](#install)
* Not doing so will lead to runtime errors (`undefined` references to THREE).
*
* e.g.
* ```
* CameraControls.install( { THREE } );
* const cameraControls = new CameraControls( camera, domElement );
* ```
*
* @param camera A `THREE.PerspectiveCamera` or `THREE.OrthographicCamera` to be controlled.
* @param domElement A `HTMLElement` for the draggable area, usually `renderer.domElement`.
* @category Constructor
*/
function CameraControls(camera, domElement) {
var _this;
_classCallCheck(this, CameraControls);
_this = _callSuper(this, CameraControls);
/**
* Minimum vertical angle in radians.
* The angle has to be between `0` and `.maxPolarAngle` inclusive.
* The default value is `0`.
*
* e.g.
* ```
* cameraControls.maxPolarAngle = 0;
* ```
* @category Properties
*/
_this.minPolarAngle = 0; // radians
/**
* Maximum vertical angle in radians.
* The angle has to be between `.maxPolarAngle` and `Math.PI` inclusive.
* The default value is `Math.PI`.
*
* e.g.
* ```
* cameraControls.maxPolarAngle = Math.PI;
* ```
* @category Properties
*/
_this.maxPolarAngle = Math.PI; // radians
/**
* Minimum horizontal angle in radians.
* The angle has to be less than `.maxAzimuthAngle`.
* The default value is `- Infinity`.
*
* e.g.
* ```
* cameraControls.minAzimuthAngle = - Infinity;
* ```
* @category Properties
*/
_this.minAzimuthAngle = -Infinity; // radians
/**
* Maximum horizontal angle in radians.
* The angle has to be greater than `.minAzimuthAngle`.
* The default value is `Infinity`.
*
* e.g.
* ```
* cameraControls.maxAzimuthAngle = Infinity;
* ```
* @category Properties
*/
_this.maxAzimuthAngle = Infinity; // radians
// How far you can dolly in and out ( PerspectiveCamera only )
/**
* Minimum distance for dolly. The value must be higher than `0`. Default is `Number.EPSILON`.
* PerspectiveCamera only.
* @category Properties
*/
_this.minDistance = Number.EPSILON;
/**
* Maximum distance for dolly. The value must be higher than `minDistance`. Default is `Infinity`.
* PerspectiveCamera only.
* @category Properties
*/
_this.maxDistance = Infinity;
/**
* `true` to enable Infinity Dolly for wheel and pinch. Use this with `minDistance` and `maxDistance`
* If the Dolly distance is less (or over) than the `minDistance` (or `maxDistance`), `infinityDolly` will keep the distance and pushes the target position instead.
* @category Properties
*/
_this.infinityDolly = false;
/**
* Minimum camera zoom.
* @category Properties
*/
_this.minZoom = 0.01;
/**
* Maximum camera zoom.
* @category Properties
*/
_this.maxZoom = Infinity;
/**
* Approximate time in seconds to reach the target. A smaller value will reach the target faster.
* @category Properties
*/
_this.smoothTime = 0.25;
/**
* the smoothTime while dragging
* @category Properties
*/
_this.draggingSmoothTime = 0.125;
/**
* Max transition speed in unit-per-seconds
* @category Properties
*/
_this.maxSpeed = Infinity;
/**
* Speed of azimuth (horizontal) rotation.
* @category Properties
*/
_this.azimuthRotateSpeed = 1.0;
/**
* Speed of polar (vertical) rotation.
* @category Properties
*/
_this.polarRotateSpeed = 1.0;
/**
* Speed of mouse-wheel dollying.
* @category Properties
*/
_this.dollySpeed = 1.0;
/**
* `true` to invert direction when dollying or zooming via drag
* @category Properties
*/
_this.dollyDragInverted = false;
/**
* Speed of drag for truck and pedestal.
* @category Properties
*/
_this.truckSpeed = 2.0;
/**
* `true` to enable Dolly-in to the mouse cursor coords.
* @category Properties
*/
_this.dollyToCursor = false;
/**
* @category Properties
*/
_this.dragToOffset = false;
/**
* The same as `.screenSpacePanning` in three.js's OrbitControls.
* @category Properties
*/
_this.verticalDragToForward = false;
/**
* Friction ratio of the boundary.
* @category Properties
*/
_this.boundaryFriction = 0.0;
/**
* Controls how soon the `rest` event fires as the camera slows.
* @category Properties
*/
_this.restThreshold = 0.01;
/**
* An array of Meshes to collide with camera.
* Be aware colliderMeshes may decrease performance. The collision test uses 4 raycasters from the camera since the near plane has 4 corners.
* @category Properties
*/
_this.colliderMeshes = [];
/**
* Force cancel user dragging.
* @category Methods
*/
// cancel will be overwritten in the constructor.
_this.cancel = function () {};
_this._enabled = true;
_this._state = ACTION.NONE;
_this._viewport = null;
_this._changedDolly = 0;
_this._changedZoom = 0;
_this._hasRested = true;
_this._boundaryEnclosesCamera = false;
_this._needsUpdate = true;
_this._updatedLastTime = false;
_this._elementRect = new DOMRect();
_this._isDragging = false;
_this._dragNeedsUpdate = true;
_this._activePointers = [];
_this._lockedPointer = null;
_this._interactiveArea = new DOMRect(0, 0, 1, 1);
// Use draggingSmoothTime over smoothTime while true.
// set automatically true on user-dragging start.
// set automatically false on programmable methods call.
_this._isUserControllingRotate = false;
_this._isUserControllingDolly = false;
_this._isUserControllingTruck = false;
_this._isUserControllingOffset = false;
_this._isUserControllingZoom = false;
_this._lastDollyDirection = DOLLY_DIRECTION.NONE;
// velocities for smoothDamp
_this._thetaVelocity = {
value: 0
};
_this._phiVelocity = {
value: 0
};
_this._radiusVelocity = {
value: 0
};
_this._targetVelocity = new THREE.Vector3();
_this._focalOffsetVelocity = new THREE.Vector3();
_this._zoomVelocity = {
value: 0
};
_this._truckInternal = function (deltaX, deltaY, dragToOffset) {
var truckX;
var pedestalY;
if (isPerspectiveCamera(_this._camera)) {
var offset = _v3A.copy(_this._camera.position).sub(_this._target);
// half of the fov is center to top of screen
var fov = _this._camera.getEffectiveFOV() * DEG2RAD;
var targetDistance = offset.length() * Math.tan(fov * 0.5);
truckX = _this.truckSpeed * deltaX * targetDistance / _this._elementRect.height;
pedestalY = _this.truckSpeed * deltaY * targetDistance / _this._elementRect.height;
} else if (isOrthographicCamera(_this._camera)) {
var _camera = _this._camera;
truckX = deltaX * (_camera.right - _camera.left) / _camera.zoom / _this._elementRect.width;
pedestalY = deltaY * (_camera.top - _camera.bottom) / _camera.zoom / _this._elementRect.height;
} else {
return;
}
if (_this.verticalDragToForward) {
dragToOffset ? _this.setFocalOffset(_this._focalOffsetEnd.x + truckX, _this._focalOffsetEnd.y, _this._focalOffsetEnd.z, true) : _this.truck(truckX, 0, true);
_this.forward(-pedestalY, true);
} else {
dragToOffset ? _this.setFocalOffset(_this._focalOffsetEnd.x + truckX, _this._focalOffsetEnd.y + pedestalY, _this._focalOffsetEnd.z, true) : _this.truck(truckX, pedestalY, true);
}
};
_this._rotateInternal = function (deltaX, deltaY) {
var theta = PI_2 * _this.azimuthRotateSpeed * deltaX / _this._elementRect.height; // divide by *height* to refer the resolution
var phi = PI_2 * _this.polarRotateSpeed * deltaY / _this._elementRect.height;
_this.rotate(theta, phi, true);
};
_this._dollyInternal = function (delta, x, y) {
var dollyScale = Math.pow(0.95, -delta * _this.dollySpeed);
var lastDistance = _this._sphericalEnd.radius;
var distance = _this._sphericalEnd.radius * dollyScale;
var clampedDistance = clamp(distance, _this.minDistance, _this.maxDistance);
var overflowedDistance = clampedDistance - distance;
if (_this.infinityDolly && _this.dollyToCursor) {
_this._dollyToNoClamp(distance, true);
} else if (_this.infinityDolly && !_this.dollyToCursor) {
_this.dollyInFixed(overflowedDistance, true);
_this._dollyToNoClamp(clampedDistance, true);
} else {
_this._dollyToNoClamp(clampedDistance, true);
}
if (_this.dollyToCursor) {
_this._changedDolly += (_this.infinityDolly ? distance : clampedDistance) - lastDistance;
_this._dollyControlCoord.set(x, y);
}
_this._lastDollyDirection = Math.sign(-delta);
};
_this._zoomInternal = function (delta, x, y) {
var zoomScale = Math.pow(0.95, delta * _this.dollySpeed);
var lastZoom = _this._zoom;
var zoom = _this._zoom * zoomScale;
// for both PerspectiveCamera and OrthographicCamera
_this.zoomTo(zoom, true);
if (_this.dollyToCursor) {
_this._changedZoom += zoom - lastZoom;
_this._dollyControlCoord.set(x, y);
}
};
// Check if the user has installed THREE
if (typeof THREE === 'undefined') {
console.error('camera-controls: `THREE` is undefined. You must first run `CameraControls.install( { THREE: THREE } )`. Check the docs for further information.');
}
_this._camera = camera;
_this._yAxisUpSpace = new THREE.Quaternion().setFromUnitVectors(_this._camera.up, _AXIS_Y);
// this._yAxisUpSpaceInverse = this._yAxisUpSpace.clone().invert();
_this._yAxisUpSpaceInverse = _this._yAxisUpSpace.clone();
_this._state = ACTION.NONE;
// the location
_this._target = new THREE.Vector3();
_this._targetEnd = _this._target.clone();
_this._focalOffset = new THREE.Vector3();
_this._focalOffsetEnd = _this._focalOffset.clone();
// rotation
_this._spherical = new THREE.Spherical().setFromVector3(_v3A.copy(_this._camera.position).applyQuaternion(_this._yAxisUpSpace));
_this._sphericalEnd = _this._spherical.clone();
_this._lastDistance = _this._spherical.radius;
_this._zoom = _this._camera.zoom;
_this._zoomEnd = _this._zoom;
_this._lastZoom = _this._zoom;
// collisionTest uses nearPlane.s
_this._nearPlaneCorners = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
_this._updateNearPlaneCorners();
// Target cannot move outside of this box
_this._boundary = new THREE.Box3(new THREE.Vector3(-Infinity, -Infinity, -Infinity), new THREE.Vector3(Infinity, Infinity, Infinity));
// reset
_this._cameraUp0 = _this._camera.up.clone();
_this._target0 = _this._target.clone();
_this._position0 = _this._camera.position.clone();
_this._zoom0 = _this._zoom;
_this._focalOffset0 = _this._focalOffset.clone();
_this._dollyControlCoord = new THREE.Vector2();
// configs
_this.mouseButtons = {
left: ACTION.ROTATE,
middle: ACTION.DOLLY,
right: ACTION.TRUCK,
wheel: isPerspectiveCamera(_this._camera) ? ACTION.DOLLY : isOrthographicCamera(_this._camera) ? ACTION.ZOOM : ACTION.NONE
};
_this.touches = {
one: ACTION.TOUCH_ROTATE,
two: isPerspectiveCamera(_this._camera) ? ACTION.TOUCH_DOLLY_TRUCK : isOrthographicCamera(_this._camera) ? ACTION.TOUCH_ZOOM_TRUCK : ACTION.NONE,
three: ACTION.TOUCH_TRUCK
};
var dragStartPosition = new THREE.Vector2();
var lastDragPosition = new THREE.Vector2();
var dollyStart = new THREE.Vector2();
var onPointerDown = function onPointerDown(event) {
if (!_this._enabled || !_this._domElement) return;
if (_this._interactiveArea.left !== 0 || _this._interactiveArea.top !== 0 || _this._interactiveArea.width !== 1 || _this._interactiveArea.height !== 1) {
var elRect = _this._domElement.getBoundingClientRect();
var left = event.clientX / elRect.width;
var top = event.clientY / elRect.height;
// check if the interactiveArea contains the drag start position.
if (left < _this._interactiveArea.left || left > _this._interactiveArea.right || top < _this._interactiveArea.top || top > _this._interactiveArea.bottom) return;
}
// Don't call `event.preventDefault()` on the pointerdown event
// to keep receiving pointermove evens outside dragging iframe
// https://taye.me/blog/tips/2015/11/16/mouse-drag-outside-iframe/
var mouseButton = event.pointerType !== 'mouse' ? null : (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT ? MOUSE_BUTTON.LEFT : (event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE ? MOUSE_BUTTON.MIDDLE : (event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT ? MOUSE_BUTTON.RIGHT : null;
if (mouseButton !== null) {
var zombiePointer = _this._findPointerByMouseButton(mouseButton);
zombiePointer && _this._disposePointer(zombiePointer);
}
if ((event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT && _this._lockedPointer) return;
var pointer = {
pointerId: event.pointerId,
clientX: event.clientX,
clientY: event.clientY,
deltaX: 0,
deltaY: 0,
mouseButton: mouseButton
};
_this._activePointers.push(pointer);
// eslint-disable-next-line no-undef
_this._domElement.ownerDocument.removeEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.removeEventListener('pointerup', onPointerUp);
_this._domElement.ownerDocument.addEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.addEventListener('pointerup', onPointerUp);
_this._isDragging = true;
startDragging(event);
};
var onPointerMove = function onPointerMove(event) {
if (event.cancelable) event.preventDefault();
var pointerId = event.pointerId;
var pointer = _this._lockedPointer || _this._findPointerById(pointerId);
if (!pointer) return;
pointer.clientX = event.clientX;
pointer.clientY = event.clientY;
pointer.deltaX = event.movementX;
pointer.deltaY = event.movementY;
_this._state = 0;
if (event.pointerType === 'touch') {
switch (_this._activePointers.length) {
case 1:
_this._state = _this.touches.one;
break;
case 2:
_this._state = _this.touches.two;
break;
case 3:
_this._state = _this.touches.three;
break;
}
} else {
if (!_this._isDragging && _this._lockedPointer || _this._isDragging && (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT) {
_this._state = _this._state | _this.mouseButtons.left;
}
if (_this._isDragging && (event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE) {
_this._state = _this._state | _this.mouseButtons.middle;
}
if (_this._isDragging && (event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT) {
_this._state = _this._state | _this.mouseButtons.right;
}
}
dragging();
};
var onPointerUp = function onPointerUp(event) {
var pointer = _this._findPointerById(event.pointerId);
if (pointer && pointer === _this._lockedPointer) return;
pointer && _this._disposePointer(pointer);
if (event.pointerType === 'touch') {
switch (_this._activePointers.length) {
case 0:
_this._state = ACTION.NONE;
break;
case 1:
_this._state = _this.touches.one;
break;
case 2:
_this._state = _this.touches.two;
break;
case 3:
_this._state = _this.touches.three;
break;
}
} else {
_this._state = ACTION.NONE;
}
endDragging();
};
var lastScrollTimeStamp = -1;
var onMouseWheel = function onMouseWheel(event) {
if (!_this._domElement) return;
if (!_this._enabled || _this.mouseButtons.wheel === ACTION.NONE) return;
if (_this._interactiveArea.left !== 0 || _this._interactiveArea.top !== 0 || _this._interactiveArea.width !== 1 || _this._interactiveArea.height !== 1) {
var elRect = _this._domElement.getBoundingClientRect();
var left = event.clientX / elRect.width;
var top = event.clientY / elRect.height;
// check if the interactiveArea contains the drag start position.
if (left < _this._interactiveArea.left || left > _this._interactiveArea.right || top < _this._interactiveArea.top || top > _this._interactiveArea.bottom) return;
}
event.preventDefault();
if (_this.dollyToCursor || _this.mouseButtons.wheel === ACTION.ROTATE || _this.mouseButtons.wheel === ACTION.TRUCK) {
var now = performance.now();
// only need to fire this at scroll start.
if (lastScrollTimeStamp - now < 1000) _this._getClientRect(_this._elementRect);
lastScrollTimeStamp = now;
}
// Ref: https://github.com/cedricpinson/osgjs/blob/00e5a7e9d9206c06fdde0436e1d62ab7cb5ce853/sources/osgViewer/input/source/InputSourceMouse.js#L89-L103
var deltaYFactor = isMac ? -1 : -3;
var delta = event.deltaMode === 1 ? event.deltaY / deltaYFactor : event.deltaY / (deltaYFactor * 10);
var x = _this.dollyToCursor ? (event.clientX - _this._elementRect.x) / _this._elementRect.width * 2 - 1 : 0;
var y = _this.dollyToCursor ? (event.clientY - _this._elementRect.y) / _this._elementRect.height * -2 + 1 : 0;
switch (_this.mouseButtons.wheel) {
case ACTION.ROTATE:
{
_this._rotateInternal(event.deltaX, event.deltaY);
_this._isUserControllingRotate = true;
break;
}
case ACTION.TRUCK:
{
_this._truckInternal(event.deltaX, event.deltaY, false);
_this._isUserControllingTruck = true;
break;
}
case ACTION.OFFSET:
{
_this._truckInternal(event.deltaX, event.deltaY, true);
_this._isUserControllingOffset = true;
break;
}
case ACTION.DOLLY:
{
_this._dollyInternal(-delta, x, y);
_this._isUserControllingDolly = true;
break;
}
case ACTION.ZOOM:
{
_this._zoomInternal(-delta, x, y);
_this._isUserControllingZoom = true;
break;
}
}
_this.dispatchEvent({
type: 'control'
});
};
var onContextMenu = function onContextMenu(event) {
if (!_this._domElement || !_this._enabled) return;
// contextmenu event is fired right after pointerdown
// remove attached handlers and active pointer, if interrupted by contextmenu.
if (_this.mouseButtons.right === CameraControls.ACTION.NONE) {
var pointerId = event instanceof PointerEvent ? event.pointerId : 0;
var pointer = _this._findPointerById(pointerId);
pointer && _this._disposePointer(pointer);
// eslint-disable-next-line no-undef
_this._domElement.ownerDocument.removeEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.removeEventListener('pointerup', onPointerUp);
return;
}
event.preventDefault();
};
var startDragging = function startDragging(event) {
if (!_this._enabled) return;
extractClientCoordFromEvent(_this._activePointers, _v2);
_this._getClientRect(_this._elementRect);
dragStartPosition.copy(_v2);
lastDragPosition.copy(_v2);
var isMultiTouch = _this._activePointers.length >= 2;
if (isMultiTouch) {
// 2 finger pinch
var dx = _v2.x - _this._activePointers[1].clientX;
var dy = _v2.y - _this._activePointers[1].clientY;
var distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
// center coords of 2 finger truck
var x = (_this._activePointers[0].clientX + _this._activePointers[1].clientX) * 0.5;
var y = (_this._activePointers[0].clientY + _this._activePointers[1].clientY) * 0.5;
lastDragPosition.set(x, y);
}
_this._state = 0;
if (!event) {
if (_this._lockedPointer) _this._state = _this._state | _this.mouseButtons.left;
} else if ('pointerType' in event && event.pointerType === 'touch') {
switch (_this._activePointers.length) {
case 1:
_this._state = _this.touches.one;
break;
case 2:
_this._state = _this.touches.two;
break;
case 3:
_this._state = _this.touches.three;
break;
}
} else {
if (!_this._lockedPointer && (event.buttons & MOUSE_BUTTON.LEFT) === MOUSE_BUTTON.LEFT) {
_this._state = _this._state | _this.mouseButtons.left;
}
if ((event.buttons & MOUSE_BUTTON.MIDDLE) === MOUSE_BUTTON.MIDDLE) {
_this._state = _this._state | _this.mouseButtons.middle;
}
if ((event.buttons & MOUSE_BUTTON.RIGHT) === MOUSE_BUTTON.RIGHT) {
_this._state = _this._state | _this.mouseButtons.right;
}
}
// stop current movement on drag start
if ((_this._state & ACTION.ROTATE) === ACTION.ROTATE || (_this._state & ACTION.TOUCH_ROTATE) === ACTION.TOUCH_ROTATE || (_this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (_this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) {
_this._sphericalEnd.theta = _this._spherical.theta;
_this._sphericalEnd.phi = _this._spherical.phi;
_this._thetaVelocity.value = 0;
_this._phiVelocity.value = 0;
}
if ((_this._state & ACTION.TRUCK) === ACTION.TRUCK || (_this._state & ACTION.TOUCH_TRUCK) === ACTION.TOUCH_TRUCK || (_this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (_this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK) {
_this._targetEnd.copy(_this._target);
_this._targetVelocity.set(0, 0, 0);
}
if ((_this._state & ACTION.DOLLY) === ACTION.DOLLY || (_this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (_this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (_this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (_this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE) {
_this._sphericalEnd.radius = _this._spherical.radius;
_this._radiusVelocity.value = 0;
}
if ((_this._state & ACTION.ZOOM) === ACTION.ZOOM || (_this._state & ACTION.TOUCH_ZOOM) === ACTION.TOUCH_ZOOM || (_this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK || (_this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET || (_this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) {
_this._zoomEnd = _this._zoom;
_this._zoomVelocity.value = 0;
}
if ((_this._state & ACTION.OFFSET) === ACTION.OFFSET || (_this._state & ACTION.TOUCH_OFFSET) === ACTION.TOUCH_OFFSET || (_this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (_this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET) {
_this._focalOffsetEnd.copy(_this._focalOffset);
_this._focalOffsetVelocity.set(0, 0, 0);
}
_this.dispatchEvent({
type: 'controlstart'
});
};
var dragging = function dragging() {
if (!_this._enabled || !_this._dragNeedsUpdate) return;
_this._dragNeedsUpdate = false;
extractClientCoordFromEvent(_this._activePointers, _v2);
// When pointer lock is enabled clientX, clientY, screenX, and screenY remain 0.
// If pointer lock is enabled, use the Delta directory, and assume active-pointer is not multiple.
var isPointerLockActive = _this._domElement && _this._domElement.ownerDocument.pointerLockElement === _this._domElement;
var lockedPointer = isPointerLockActive ? _this._lockedPointer || _this._activePointers[0] : null;
var deltaX = lockedPointer ? -lockedPointer.deltaX : lastDragPosition.x - _v2.x;
var deltaY = lockedPointer ? -lockedPointer.deltaY : lastDragPosition.y - _v2.y;
lastDragPosition.copy(_v2);
if ((_this._state & ACTION.ROTATE) === ACTION.ROTATE || (_this._state & ACTION.TOUCH_ROTATE) === ACTION.TOUCH_ROTATE || (_this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (_this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) {
_this._rotateInternal(deltaX, deltaY);
_this._isUserControllingRotate = true;
}
if ((_this._state & ACTION.DOLLY) === ACTION.DOLLY || (_this._state & ACTION.ZOOM) === ACTION.ZOOM) {
var dollyX = _this.dollyToCursor ? (dragStartPosition.x - _this._elementRect.x) / _this._elementRect.width * 2 - 1 : 0;
var dollyY = _this.dollyToCursor ? (dragStartPosition.y - _this._elementRect.y) / _this._elementRect.height * -2 + 1 : 0;
var dollyDirection = _this.dollyDragInverted ? -1 : 1;
if ((_this._state & ACTION.DOLLY) === ACTION.DOLLY) {
_this._dollyInternal(dollyDirection * deltaY * TOUCH_DOLLY_FACTOR, dollyX, dollyY);
_this._isUserControllingDolly = true;
} else {
_this._zoomInternal(dollyDirection * deltaY * TOUCH_DOLLY_FACTOR, dollyX, dollyY);
_this._isUserControllingZoom = true;
}
}
if ((_this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (_this._state & ACTION.TOUCH_ZOOM) === ACTION.TOUCH_ZOOM || (_this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (_this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK || (_this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (_this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET || (_this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (_this._state & ACTION.TOUCH_ZOOM_ROTATE) === ACTION.TOUCH_ZOOM_ROTATE) {
var dx = _v2.x - _this._activePointers[1].clientX;
var dy = _v2.y - _this._activePointers[1].clientY;
var distance = Math.sqrt(dx * dx + dy * dy);
var dollyDelta = dollyStart.y - distance;
dollyStart.set(0, distance);
var _dollyX = _this.dollyToCursor ? (lastDragPosition.x - _this._elementRect.x) / _this._elementRect.width * 2 - 1 : 0;
var _dollyY = _this.dollyToCursor ? (lastDragPosition.y - _this._elementRect.y) / _this._elementRect.height * -2 + 1 : 0;
if ((_this._state & ACTION.TOUCH_DOLLY) === ACTION.TOUCH_DOLLY || (_this._state & ACTION.TOUCH_DOLLY_ROTATE) === ACTION.TOUCH_DOLLY_ROTATE || (_this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (_this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET) {
_this._dollyInternal(dollyDelta * TOUCH_DOLLY_FACTOR, _dollyX, _dollyY);
_this._isUserControllingDolly = true;
} else {
_this._zoomInternal(dollyDelta * TOUCH_DOLLY_FACTOR, _dollyX, _dollyY);
_this._isUserControllingZoom = true;
}
}
if ((_this._state & ACTION.TRUCK) === ACTION.TRUCK || (_this._state & ACTION.TOUCH_TRUCK) === ACTION.TOUCH_TRUCK || (_this._state & ACTION.TOUCH_DOLLY_TRUCK) === ACTION.TOUCH_DOLLY_TRUCK || (_this._state & ACTION.TOUCH_ZOOM_TRUCK) === ACTION.TOUCH_ZOOM_TRUCK) {
_this._truckInternal(deltaX, deltaY, false);
_this._isUserControllingTruck = true;
}
if ((_this._state & ACTION.OFFSET) === ACTION.OFFSET || (_this._state & ACTION.TOUCH_OFFSET) === ACTION.TOUCH_OFFSET || (_this._state & ACTION.TOUCH_DOLLY_OFFSET) === ACTION.TOUCH_DOLLY_OFFSET || (_this._state & ACTION.TOUCH_ZOOM_OFFSET) === ACTION.TOUCH_ZOOM_OFFSET) {
_this._truckInternal(deltaX, deltaY, true);
_this._isUserControllingOffset = true;
}
_this.dispatchEvent({
type: 'control'
});
};
var endDragging = function endDragging() {
extractClientCoordFromEvent(_this._activePointers, _v2);
lastDragPosition.copy(_v2);
_this._dragNeedsUpdate = false;
if (_this._activePointers.length === 0 || _this._activePointers.length === 1 && _this._activePointers[0] === _this._lockedPointer) {
_this._isDragging = false;
}
if (_this._activePointers.length === 0 && _this._domElement) {
// eslint-disable-next-line no-undef
_this._domElement.ownerDocument.removeEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.removeEventListener('pointerup', onPointerUp);
_this.dispatchEvent({
type: 'controlend'
});
}
};
_this.lockPointer = function () {
if (!_this._enabled || !_this._domElement) return;
_this.cancel();
// Element.requestPointerLock is allowed to happen without any pointer active - create a faux one for compatibility with controls
_this._lockedPointer = {
pointerId: -1,
clientX: 0,
clientY: 0,
deltaX: 0,
deltaY: 0,
mouseButton: null
};
_this._activePointers.push(_this._lockedPointer);
// eslint-disable-next-line no-undef
_this._domElement.ownerDocument.removeEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.removeEventListener('pointerup', onPointerUp);
_this._domElement.requestPointerLock();
_this._domElement.ownerDocument.addEventListener('pointerlockchange', onPointerLockChange);
_this._domElement.ownerDocument.addEventListener('pointerlockerror', onPointerLockError);
_this._domElement.ownerDocument.addEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.addEventListener('pointerup', onPointerUp);
startDragging();
};
_this.unlockPointer = function () {
var _a, _b, _c;
if (_this._lockedPointer !== null) {
_this._disposePointer(_this._lockedPointer);
_this._lockedPointer = null;
}
(_a = _this._domElement) === null || _a === void 0 ? void 0 : _a.ownerDocument.exitPointerLock();
(_b = _this._domElement) === null || _b === void 0 ? void 0 : _b.ownerDocument.removeEventListener('pointerlockchange', onPointerLockChange);
(_c = _this._domElement) === null || _c === void 0 ? void 0 : _c.ownerDocument.removeEventListener('pointerlockerror', onPointerLockError);
_this.cancel();
};
var onPointerLockChange = function onPointerLockChange() {
var isPointerLockActive = _this._domElement && _this._domElement.ownerDocument.pointerLockElement === _this._domElement;
if (!isPointerLockActive) _this.unlockPointer();
};
var onPointerLockError = function onPointerLockError() {
_this.unlockPointer();
};
_this._addAllEventListeners = function (domElement) {
_this._domElement = domElement;
_this._domElement.style.touchAction = 'none';
_this._domElement.style.userSelect = 'none';
_this._domElement.style.webkitUserSelect = 'none';
_this._domElement.addEventListener('pointerdown', onPointerDown);
_this._domElement.addEventListener('pointercancel', onPointerUp);
_this._domElement.addEventListener('wheel', onMouseWheel, {
passive: false
});
_this._domElement.addEventListener('contextmenu', onContextMenu);
};
_this._removeAllEventListeners = function () {
if (!_this._domElement) return;
_this._domElement.style.touchAction = '';
_this._domElement.style.userSelect = '';
_this._domElement.style.webkitUserSelect = '';
_this._domElement.removeEventListener('pointerdown', onPointerDown);
_this._domElement.removeEventListener('pointercancel', onPointerUp);
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener#matching_event_listeners_for_removal
// > it's probably wise to use the same values used for the call to `addEventListener()` when calling `removeEventListener()`
// see https://github.com/microsoft/TypeScript/issues/32912#issuecomment-522142969
// eslint-disable-next-line no-undef
_this._domElement.removeEventListener('wheel', onMouseWheel, {
passive: false
});
_this._domElement.removeEventListener('contextmenu', onContextMenu);
// eslint-disable-next-line no-undef
_this._domElement.ownerDocument.removeEventListener('pointermove', onPointerMove, {
passive: false
});
_this._domElement.ownerDocument.removeEventListener('pointerup', onPointerUp);
_this._domElement.ownerDocument.removeEventListener('pointerlockchange', onPointerLockChange);
_this._domElement.ownerDocument.removeEventListener('pointerlockerror', onPointerLockError);
};
_this.cancel = function () {
if (_this._state === ACTION.NONE) return;
_this._state = ACTION.NONE;
_this._activePointers.length = 0;
endDragging();
};
if (domElement) _this.connect(domElement);
_this.update(0);
return _this;
}
/**
* The camera to be controlled
* @category Properties
*/
_inherits(CameraControls, _EventDispatcher);
return _createClass(CameraControls, [{
key: "camera",
get: function get() {
return this._camera;
},
set: function set(camera) {
this._camera = camera;
this.updateCameraUp();
this._camera.updateProjectionMatrix();
this._updateNearPlaneCorners();
this._needsUpdate = true;
}
/**
* Whether or not the controls are enabled.
* `false` to disable user dragging/touch-move, but all methods works.
* @category Properties
*/
}, {
key: "enabled",
get: function get() {
return this._enabled;
},
set: function set(enabled) {
this._enabled = enabled;
if (!this._domElement) return;
if (enabled) {
this._domElement.style.touchAction = 'none';
this._domElement.style.userSelect = 'none';
this._domElement.style.webkitUserSelect = 'none';
} else {
this.cancel();
this._domElement.style.touchAction = '';
this._domElement.style.userSelect = '';
this._domElement.style.webkitUserSelect = '';
}
}
/**
* Returns `true` if the controls are active updating.
* readonly value.
* @category Properties
*/
}, {
key: "active",
get: function get() {
return !this._hasRested;
}
/**
* Getter for the current `ACTION`.
* readonly value.
* @category Properties
*/
}, {
key: "currentAction",
get: function get() {
return this._state;
}
/**
* get/set Current distance.
* @category Properties
*/
}, {
key: "distance",
get: function get() {
return this._spherical.radius;
},
set: function set(distance) {
if (this._spherical.radius === distance && this._sphericalEnd.radius === distance) return;
this._spherical.radius = distance;
this._sphericalEnd.radius = distance;
this._needsUpdate = true;
}
// horizontal angle
/**
* get/set the azimuth angle (horizontal) in radians.
* Every 360 degrees turn is added to `.azimuthAngle` value, which is accumulative.
* @category Properties
*/
}, {
key: "azimuthAngle",
get: function get() {
return this._spherical.theta;
},
set: function set(azimuthAngle) {
if (this._spherical.theta === azimuthAngle && this._sphericalEnd.theta === azimuthAngle) return;
this._spherical.theta = azimuthAngle;
this._sphericalEnd.theta = azimuthAngle;
this._needsUpdate = true;
}
// vertical angle
/**
* get/set the polar angle (vertical) in radians.
* @category Properties
*/
}, {
key: "polarAngle",
get: function get() {
return this._spherical.phi;
},
set: function set(polarAngle) {
if (this._spherical.phi === polarAngle && this._sphericalEnd.phi === polarAngle) return;
this._spherical.phi = polarAngle;
this._sphericalEnd.phi = polarAngle;
this._needsUpdate = true;
}
/**
* Whether camera position should be enclosed in the boundary or not.
* @category Properties
*/
}, {
key: "boundaryEnclosesCamera",
get: function get() {
return this._boundaryEnclosesCamera;
},
set: function set(boundaryEnclosesCamera) {
this._boundaryEnclosesCamera = boundaryEnclosesCamera;
this._needsUpdate = true;
}
/**
* Set drag-start, touches and wheel enable area in the domElement.
* each values are between `0` and `1` inclusive, where `0` is left/top and `1` is right/bottom of the screen.
* e.g. `{ x: 0, y: 0, width: 1, height: 1 }` for entire area.
* @category Properties
*/
}, {
key: "interactiveArea",
set: function set(interactiveArea) {
this._interactiveArea.width = clamp(interactiveArea.width, 0, 1);
this._interactiveArea.height = clamp(interactiveArea.height, 0, 1);
this._interactiveArea.x = clamp(interactiveArea.x, 0, 1 - this._interactiveArea.width);
this._interactiveArea.y = clamp(interactiveArea.y, 0, 1 - this._interactiveArea.height);
}
/**
* Adds the specified event listener.
* Applicable event types (which is `K`) are:
* | Event name | Timing |
* | ------------------- | ------ |
* | `'controlstart'` | When the user starts to control the camera via mouse / touches. ¹ |
* | `'control'` | When the user controls the camera (dragging). |
* | `'controlend'` | When the user ends to control the camera. ¹ |
* | `'transitionstart'` | When any kind of transition starts, either user control or using a method with `enableTransition = true` |
* | `'update'` | When the camera position is updated. |
* | `'wake'` | When the camera starts moving. |
* | `'rest'` | When the camera movement is below `.restThreshold` ². |
* | `'sleep'` | When the camera end moving. |
*
* 1. `mouseButtons.wheel` (Mouse wheel control) does not emit `'controlstart'` and `'controlend'`. `mouseButtons.wheel` uses scroll-event internally, and scroll-event happens intermittently. That means "start" and "end" cannot be detected.
* 2. Due to damping, `sleep` will usually fire a few seconds after the camera _appears_ to have stopped moving. If you want to do something (e.g. enable UI, perform another transition) at the point when the camera has stopped, you probably want the `rest` event. This can be fine tuned using the `.restThreshold` parameter. See the [Rest and Sleep Example](https://yomotsu.github.io/camera-controls/examples/rest-and-sleep.html).
*
* e.g.
* ```
* cameraControl.addEventListener( 'controlstart', myCallbackFunction );