UNPKG

react-force-graph-ar

Version:
992 lines (981 loc) 815 kB
// Version 1.9.0 react-force-graph-ar - https://github.com/vasturiano/react-force-graph (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) : typeof define === 'function' && define.amd ? define(['react'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ForceGraphAR = factory(global.React)); })(this, (function (React) { 'use strict'; function _iterableToArrayLimit$5(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = true, _d = false; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = true, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } } function _defineProperty$2(obj, key, value) { key = _toPropertyKey$3(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray$5(arr, i) { return _arrayWithHoles$5(arr) || _iterableToArrayLimit$5(arr, i) || _unsupportedIterableToArray$5(arr, i) || _nonIterableRest$5(); } function _toConsumableArray$4(arr) { return _arrayWithoutHoles$4(arr) || _iterableToArray$4(arr) || _unsupportedIterableToArray$5(arr) || _nonIterableSpread$4(); } function _arrayWithoutHoles$4(arr) { if (Array.isArray(arr)) return _arrayLikeToArray$5(arr); } function _arrayWithHoles$5(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray$4(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _unsupportedIterableToArray$5(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray$5(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$5(o, minLen); } function _arrayLikeToArray$5(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread$4() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest$5() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _toPrimitive$3(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey$3(arg) { var key = _toPrimitive$3(arg, "string"); return typeof key === "symbol" ? key : String(key); } var omit = function omit(obj, keys) { var keySet = new Set(keys); return Object.assign.apply(Object, [{}].concat(_toConsumableArray$4(Object.entries(obj).filter(function (_ref2) { var _ref3 = _slicedToArray$5(_ref2, 1), key = _ref3[0]; return !keySet.has(key); }).map(function (_ref4) { var _ref5 = _slicedToArray$5(_ref4, 2), key = _ref5[0], val = _ref5[1]; return _defineProperty$2({}, key, val); })))); }; function _arrayLikeToArray$4(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles$4(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles$3(r) { if (Array.isArray(r)) return _arrayLikeToArray$4(r); } function _iterableToArray$3(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit$4(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = true, o = false; try { if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = true, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest$4() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableSpread$3() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _slicedToArray$4(r, e) { return _arrayWithHoles$4(r) || _iterableToArrayLimit$4(r, e) || _unsupportedIterableToArray$4(r, e) || _nonIterableRest$4(); } function _toConsumableArray$3(r) { return _arrayWithoutHoles$3(r) || _iterableToArray$3(r) || _unsupportedIterableToArray$4(r) || _nonIterableSpread$3(); } function _unsupportedIterableToArray$4(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$4(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$4(r, a) : void 0; } } function index$3 (kapsuleComponent) { var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, _ref$wrapperElementTy = _ref.wrapperElementType, wrapperElementType = _ref$wrapperElementTy === void 0 ? 'div' : _ref$wrapperElementTy, _ref$nodeMapper = _ref.nodeMapper, nodeMapper = _ref$nodeMapper === void 0 ? function (node) { return node; } : _ref$nodeMapper, _ref$methodNames = _ref.methodNames, methodNames = _ref$methodNames === void 0 ? [] : _ref$methodNames, _ref$initPropNames = _ref.initPropNames, initPropNames = _ref$initPropNames === void 0 ? [] : _ref$initPropNames; return /*#__PURE__*/React.forwardRef(function (props, ref) { var domEl = React.useRef(); // instantiate the inner kapsule component with the defined initPropNames var comp = React.useMemo(function () { var configOptions = Object.fromEntries(initPropNames.filter(function (p) { return props.hasOwnProperty(p); }).map(function (prop) { return [prop, props[prop]]; })); return kapsuleComponent(configOptions); }, []); useEffectOnce(function () { comp(nodeMapper(domEl.current)); // mount kapsule synchronously on this element ref, optionally mapped into an object that the kapsule understands }, React.useLayoutEffect); useEffectOnce(function () { // invoke destructor on unmount, if it exists return comp._destructor instanceof Function ? comp._destructor : undefined; }); // Call a component method var _call = React.useCallback(function (method) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } return comp[method] instanceof Function ? comp[method].apply(comp, args) : undefined; } // method not found , [comp]); // propagate component props that have changed var prevPropsRef = React.useRef({}); Object.keys(omit(props, [].concat(_toConsumableArray$3(methodNames), _toConsumableArray$3(initPropNames)))) // initPropNames or methodNames should not be called .filter(function (p) { return prevPropsRef.current[p] !== props[p]; }).forEach(function (p) { return _call(p, props[p]); }); prevPropsRef.current = props; // bind external methods to parent ref React.useImperativeHandle(ref, function () { return Object.fromEntries(methodNames.map(function (method) { return [method, function () { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return _call.apply(void 0, [method].concat(args)); }]; })); }, [_call]); return /*#__PURE__*/React.createElement(wrapperElementType, { ref: domEl }); }); } // // Handle R18 strict mode double mount at init function useEffectOnce(effect) { var useEffectFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : React.useEffect; var destroyFunc = React.useRef(); var effectCalled = React.useRef(false); var renderAfterCalled = React.useRef(false); var _useState = React.useState(0), _useState2 = _slicedToArray$4(_useState, 2); _useState2[0]; var setVal = _useState2[1]; if (effectCalled.current) { renderAfterCalled.current = true; } useEffectFn(function () { // only execute the effect first time around if (!effectCalled.current) { destroyFunc.current = effect(); effectCalled.current = true; } // this forces one render after the effect is run setVal(function (val) { return val + 1; }); return function () { // if the comp didn't render since the useEffect was called, // we know it's the dummy React cycle if (!renderAfterCalled.current) return; if (destroyFunc.current) destroyFunc.current(); }; }, []); } /** * @license * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */const REVISION='178';/** * Only front faces are rendered. * * @type {number} * @constant */const FrontSide=0;/** * Only back faces are rendered. * * @type {number} * @constant */const BackSide=1;/** * The default blending. * * @type {number} * @constant */const NormalBlending=1;/** * A `source + destination` blending equation. * * @type {number} * @constant */const AddEquation=100;/** * Multiplies all colors by the source alpha value. * * @type {number} * @constant */const SrcAlphaFactor=204;/** * Multiplies all colors by 1 minus the source alpha value. * * @type {number} * @constant */const OneMinusSrcAlphaFactor=205;/** * Pass if the incoming value is less than or equal to the depth buffer value. * * @type {number} * @constant */const LessEqualDepth=3;/** * Multiplies the environment map color with the surface color. * * @type {number} * @constant */const MultiplyOperation=0;/** * Maps textures using the geometry's UV coordinates. * * @type {number} * @constant */const UVMapping=300;/** * The texture will simply repeat to infinity. * * @type {number} * @constant */const RepeatWrapping=1000;/** * The last pixel of the texture stretches to the edge of the mesh. * * @type {number} * @constant */const ClampToEdgeWrapping=1001;/** * The texture will repeats to infinity, mirroring on each repeat. * * @type {number} * @constant */const MirroredRepeatWrapping=1002;/** * Returns the weighted average of the four texture elements that are closest to the specified * texture coordinates, and can include items wrapped or repeated from other parts of a texture, * depending on the values of `wrapS` and `wrapT`, and on the exact mapping. * * @type {number} * @constant */const LinearFilter=1006;/** * Chooses the two mipmaps that most closely match the size of the pixel being textured and uses * the `LinearFilter` criterion to produce a texture value from each mipmap. The final texture value * is a weighted average of those two values. * * @type {number} * @constant */const LinearMipmapLinearFilter=1008;/** * An unsigned byte data type for textures. * * @type {number} * @constant */const UnsignedByteType=1009;/** * A float data type for textures. * * @type {number} * @constant */const FloatType=1015;/** * Reads the red, green, blue and alpha components. * * @type {number} * @constant */const RGBAFormat=1023;/** * Normal information is relative to the underlying surface. * * @type {number} * @constant */const TangentSpaceNormalMap=0;/** * No color space. * * @type {string} * @constant */const NoColorSpace='';/** * sRGB color space. * * @type {string} * @constant */const SRGBColorSpace='srgb';/** * sRGB-linear color space. * * @type {string} * @constant */const LinearSRGBColorSpace='srgb-linear';/** * Linear transfer function. * * @type {string} * @constant */const LinearTransfer='linear';/** * sRGB transfer function. * * @type {string} * @constant */const SRGBTransfer='srgb';/** * Keeps the current value. * * @type {number} * @constant */const KeepStencilOp=7680;/** * Will always return true. * * @type {number} * @constant */const AlwaysStencilFunc=519;/** * The contents are intended to be specified once by the application, and used many * times as the source for drawing and image specification commands. * * @type {number} * @constant */const StaticDrawUsage=35044;/** * WebGL coordinate system. * * @type {number} * @constant */const WebGLCoordinateSystem=2000;/** * WebGPU coordinate system. * * @type {number} * @constant */const WebGPUCoordinateSystem=2001;/** * This type represents mouse buttons and interaction types in context of controls. * * @typedef {Object} ConstantsMouse * @property {number} MIDDLE - The left mouse button. * @property {number} LEFT - The middle mouse button. * @property {number} RIGHT - The right mouse button. * @property {number} ROTATE - A rotate interaction. * @property {number} DOLLY - A dolly interaction. * @property {number} PAN - A pan interaction. **//** * This type represents touch interaction types in context of controls. * * @typedef {Object} ConstantsTouch * @property {number} ROTATE - A rotate interaction. * @property {number} PAN - A pan interaction. * @property {number} DOLLY_PAN - The dolly-pan interaction. * @property {number} DOLLY_ROTATE - A dolly-rotate interaction. **//** * This type represents the different timestamp query types. * * @typedef {Object} ConstantsTimestampQuery * @property {string} COMPUTE - A `compute` timestamp query. * @property {string} RENDER - A `render` timestamp query. **//** * Represents the different interpolation sampling types. * * @typedef {Object} ConstantsInterpolationSamplingType * @property {string} PERSPECTIVE - Perspective-correct interpolation. * @property {string} LINEAR - Linear interpolation. * @property {string} FLAT - Flat interpolation. *//** * Represents the different interpolation sampling modes. * * @typedef {Object} ConstantsInterpolationSamplingMode * @property {string} NORMAL - Normal sampling mode. * @property {string} CENTROID - Centroid sampling mode. * @property {string} SAMPLE - Sample-specific sampling mode. * @property {string} FLAT_FIRST - Flat interpolation using the first vertex. * @property {string} FLAT_EITHER - Flat interpolation using either vertex. *//** * This modules allows to dispatch event objects on custom JavaScript objects. * * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/} * * Code Example: * ```js * class Car extends EventDispatcher { * start() { * this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } ); * } *}; * * // Using events with the custom object * const car = new Car(); * car.addEventListener( 'start', function ( event ) { * alert( event.message ); * } ); * * car.start(); * ``` */class EventDispatcher{/** * Adds the given event listener to the given event type. * * @param {string} type - The type of event to listen to. * @param {Function} listener - The function that gets called when the event is fired. */addEventListener(type,listener){if(this._listeners===undefined)this._listeners={};const listeners=this._listeners;if(listeners[type]===undefined){listeners[type]=[];}if(listeners[type].indexOf(listener)===-1){listeners[type].push(listener);}}/** * Returns `true` if the given event listener has been added to the given event type. * * @param {string} type - The type of event. * @param {Function} listener - The listener to check. * @return {boolean} Whether the given event listener has been added to the given event type. */hasEventListener(type,listener){const listeners=this._listeners;if(listeners===undefined)return false;return listeners[type]!==undefined&&listeners[type].indexOf(listener)!==-1;}/** * Removes the given event listener from the given event type. * * @param {string} type - The type of event. * @param {Function} listener - The listener to remove. */removeEventListener(type,listener){const listeners=this._listeners;if(listeners===undefined)return;const listenerArray=listeners[type];if(listenerArray!==undefined){const index=listenerArray.indexOf(listener);if(index!==-1){listenerArray.splice(index,1);}}}/** * Dispatches an event object. * * @param {Object} event - The event that gets fired. */dispatchEvent(event){const listeners=this._listeners;if(listeners===undefined)return;const listenerArray=listeners[event.type];if(listenerArray!==undefined){event.target=this;// Make a copy, in case listeners are removed while iterating. const array=listenerArray.slice(0);for(let i=0,l=array.length;i<l;i++){array[i].call(this,event);}event.target=null;}}}const _lut=['00','01','02','03','04','05','06','07','08','09','0a','0b','0c','0d','0e','0f','10','11','12','13','14','15','16','17','18','19','1a','1b','1c','1d','1e','1f','20','21','22','23','24','25','26','27','28','29','2a','2b','2c','2d','2e','2f','30','31','32','33','34','35','36','37','38','39','3a','3b','3c','3d','3e','3f','40','41','42','43','44','45','46','47','48','49','4a','4b','4c','4d','4e','4f','50','51','52','53','54','55','56','57','58','59','5a','5b','5c','5d','5e','5f','60','61','62','63','64','65','66','67','68','69','6a','6b','6c','6d','6e','6f','70','71','72','73','74','75','76','77','78','79','7a','7b','7c','7d','7e','7f','80','81','82','83','84','85','86','87','88','89','8a','8b','8c','8d','8e','8f','90','91','92','93','94','95','96','97','98','99','9a','9b','9c','9d','9e','9f','a0','a1','a2','a3','a4','a5','a6','a7','a8','a9','aa','ab','ac','ad','ae','af','b0','b1','b2','b3','b4','b5','b6','b7','b8','b9','ba','bb','bc','bd','be','bf','c0','c1','c2','c3','c4','c5','c6','c7','c8','c9','ca','cb','cc','cd','ce','cf','d0','d1','d2','d3','d4','d5','d6','d7','d8','d9','da','db','dc','dd','de','df','e0','e1','e2','e3','e4','e5','e6','e7','e8','e9','ea','eb','ec','ed','ee','ef','f0','f1','f2','f3','f4','f5','f6','f7','f8','f9','fa','fb','fc','fd','fe','ff'];/** * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} * (universally unique identifier). * * @return {string} The UUID. */function generateUUID(){// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 const d0=Math.random()*0xffffffff|0;const d1=Math.random()*0xffffffff|0;const d2=Math.random()*0xffffffff|0;const d3=Math.random()*0xffffffff|0;const uuid=_lut[d0&0xff]+_lut[d0>>8&0xff]+_lut[d0>>16&0xff]+_lut[d0>>24&0xff]+'-'+_lut[d1&0xff]+_lut[d1>>8&0xff]+'-'+_lut[d1>>16&0x0f|0x40]+_lut[d1>>24&0xff]+'-'+_lut[d2&0x3f|0x80]+_lut[d2>>8&0xff]+'-'+_lut[d2>>16&0xff]+_lut[d2>>24&0xff]+_lut[d3&0xff]+_lut[d3>>8&0xff]+_lut[d3>>16&0xff]+_lut[d3>>24&0xff];// .toLowerCase() here flattens concatenated strings to save heap memory space. return uuid.toLowerCase();}/** * Clamps the given value between min and max. * * @param {number} value - The value to clamp. * @param {number} min - The min value. * @param {number} max - The max value. * @return {number} The clamped value. */function clamp(value,min,max){return Math.max(min,Math.min(max,value));}/** * Computes the Euclidean modulo of the given parameters that * is `( ( n % m ) + m ) % m`. * * @param {number} n - The first parameter. * @param {number} m - The second parameter. * @return {number} The Euclidean modulo. */function euclideanModulo(n,m){// https://en.wikipedia.org/wiki/Modulo_operation return (n%m+m)%m;}/** * Returns a value linearly interpolated from two known points based on the given interval - * `t = 0` will return `x` and `t = 1` will return `y`. * * @param {number} x - The start point * @param {number} y - The end point. * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. * @return {number} The interpolated value. */function lerp(x,y,t){return (1-t)*x+t*y;}/** * Denormalizes the given value according to the given typed array. * * @param {number} value - The value to denormalize. * @param {TypedArray} array - The typed array that defines the data type of the value. * @return {number} The denormalize (float) value in the range `[0,1]`. */function denormalize(value,array){switch(array.constructor){case Float32Array:return value;case Uint32Array:return value/4294967295.0;case Uint16Array:return value/65535.0;case Uint8Array:return value/255.0;case Int32Array:return Math.max(value/2147483647.0,-1);case Int16Array:return Math.max(value/32767.0,-1);case Int8Array:return Math.max(value/127.0,-1);default:throw new Error('Invalid component type.');}}/** * Normalizes the given value according to the given typed array. * * @param {number} value - The float value in the range `[0,1]` to normalize. * @param {TypedArray} array - The typed array that defines the data type of the value. * @return {number} The normalize value. */function normalize(value,array){switch(array.constructor){case Float32Array:return value;case Uint32Array:return Math.round(value*4294967295.0);case Uint16Array:return Math.round(value*65535.0);case Uint8Array:return Math.round(value*255.0);case Int32Array:return Math.round(value*2147483647.0);case Int16Array:return Math.round(value*32767.0);case Int8Array:return Math.round(value*127.0);default:throw new Error('Invalid component type.');}}/** * Class representing a 2D vector. A 2D vector is an ordered pair of numbers * (labeled x and y), which can be used to represent a number of things, such as: * * - A point in 2D space (i.e. a position on a plane). * - A direction and length across a plane. In three.js the length will * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` * and the direction is also measured from `(0, 0)` towards `(x, y)`. * - Any arbitrary ordered pair of numbers. * * There are other things a 2D vector can be used to represent, such as * momentum vectors, complex numbers and so on, however these are the most * common uses in three.js. * * Iterating through a vector instance will yield its components `(x, y)` in * the corresponding order. * ```js * const a = new THREE.Vector2( 0, 1 ); * * //no arguments; will be initialised to (0, 0) * const b = new THREE.Vector2( ); * * const d = a.distanceTo( b ); * ``` */class Vector2{/** * Constructs a new 2D vector. * * @param {number} [x=0] - The x value of this vector. * @param {number} [y=0] - The y value of this vector. */constructor(x=0,y=0){/** * This flag can be used for type testing. * * @type {boolean} * @readonly * @default true */Vector2.prototype.isVector2=true;/** * The x value of this vector. * * @type {number} */this.x=x;/** * The y value of this vector. * * @type {number} */this.y=y;}/** * Alias for {@link Vector2#x}. * * @type {number} */get width(){return this.x;}set width(value){this.x=value;}/** * Alias for {@link Vector2#y}. * * @type {number} */get height(){return this.y;}set height(value){this.y=value;}/** * Sets the vector components. * * @param {number} x - The value of the x component. * @param {number} y - The value of the y component. * @return {Vector2} A reference to this vector. */set(x,y){this.x=x;this.y=y;return this;}/** * Sets the vector components to the same value. * * @param {number} scalar - The value to set for all vector components. * @return {Vector2} A reference to this vector. */setScalar(scalar){this.x=scalar;this.y=scalar;return this;}/** * Sets the vector's x component to the given value * * @param {number} x - The value to set. * @return {Vector2} A reference to this vector. */setX(x){this.x=x;return this;}/** * Sets the vector's y component to the given value * * @param {number} y - The value to set. * @return {Vector2} A reference to this vector. */setY(y){this.y=y;return this;}/** * Allows to set a vector component with an index. * * @param {number} index - The component index. `0` equals to x, `1` equals to y. * @param {number} value - The value to set. * @return {Vector2} A reference to this vector. */setComponent(index,value){switch(index){case 0:this.x=value;break;case 1:this.y=value;break;default:throw new Error('index is out of range: '+index);}return this;}/** * Returns the value of the vector component which matches the given index. * * @param {number} index - The component index. `0` equals to x, `1` equals to y. * @return {number} A vector component value. */getComponent(index){switch(index){case 0:return this.x;case 1:return this.y;default:throw new Error('index is out of range: '+index);}}/** * Returns a new vector with copied values from this instance. * * @return {Vector2} A clone of this instance. */clone(){return new this.constructor(this.x,this.y);}/** * Copies the values of the given vector to this instance. * * @param {Vector2} v - The vector to copy. * @return {Vector2} A reference to this vector. */copy(v){this.x=v.x;this.y=v.y;return this;}/** * Adds the given vector to this instance. * * @param {Vector2} v - The vector to add. * @return {Vector2} A reference to this vector. */add(v){this.x+=v.x;this.y+=v.y;return this;}/** * Adds the given scalar value to all components of this instance. * * @param {number} s - The scalar to add. * @return {Vector2} A reference to this vector. */addScalar(s){this.x+=s;this.y+=s;return this;}/** * Adds the given vectors and stores the result in this instance. * * @param {Vector2} a - The first vector. * @param {Vector2} b - The second vector. * @return {Vector2} A reference to this vector. */addVectors(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this;}/** * Adds the given vector scaled by the given factor to this instance. * * @param {Vector2} v - The vector. * @param {number} s - The factor that scales `v`. * @return {Vector2} A reference to this vector. */addScaledVector(v,s){this.x+=v.x*s;this.y+=v.y*s;return this;}/** * Subtracts the given vector from this instance. * * @param {Vector2} v - The vector to subtract. * @return {Vector2} A reference to this vector. */sub(v){this.x-=v.x;this.y-=v.y;return this;}/** * Subtracts the given scalar value from all components of this instance. * * @param {number} s - The scalar to subtract. * @return {Vector2} A reference to this vector. */subScalar(s){this.x-=s;this.y-=s;return this;}/** * Subtracts the given vectors and stores the result in this instance. * * @param {Vector2} a - The first vector. * @param {Vector2} b - The second vector. * @return {Vector2} A reference to this vector. */subVectors(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this;}/** * Multiplies the given vector with this instance. * * @param {Vector2} v - The vector to multiply. * @return {Vector2} A reference to this vector. */multiply(v){this.x*=v.x;this.y*=v.y;return this;}/** * Multiplies the given scalar value with all components of this instance. * * @param {number} scalar - The scalar to multiply. * @return {Vector2} A reference to this vector. */multiplyScalar(scalar){this.x*=scalar;this.y*=scalar;return this;}/** * Divides this instance by the given vector. * * @param {Vector2} v - The vector to divide. * @return {Vector2} A reference to this vector. */divide(v){this.x/=v.x;this.y/=v.y;return this;}/** * Divides this vector by the given scalar. * * @param {number} scalar - The scalar to divide. * @return {Vector2} A reference to this vector. */divideScalar(scalar){return this.multiplyScalar(1/scalar);}/** * Multiplies this vector (with an implicit 1 as the 3rd component) by * the given 3x3 matrix. * * @param {Matrix3} m - The matrix to apply. * @return {Vector2} A reference to this vector. */applyMatrix3(m){const x=this.x,y=this.y;const e=m.elements;this.x=e[0]*x+e[3]*y+e[6];this.y=e[1]*x+e[4]*y+e[7];return this;}/** * If this vector's x or y value is greater than the given vector's x or y * value, replace that value with the corresponding min value. * * @param {Vector2} v - The vector. * @return {Vector2} A reference to this vector. */min(v){this.x=Math.min(this.x,v.x);this.y=Math.min(this.y,v.y);return this;}/** * If this vector's x or y value is less than the given vector's x or y * value, replace that value with the corresponding max value. * * @param {Vector2} v - The vector. * @return {Vector2} A reference to this vector. */max(v){this.x=Math.max(this.x,v.x);this.y=Math.max(this.y,v.y);return this;}/** * If this vector's x or y value is greater than the max vector's x or y * value, it is replaced by the corresponding value. * If this vector's x or y value is less than the min vector's x or y value, * it is replaced by the corresponding value. * * @param {Vector2} min - The minimum x and y values. * @param {Vector2} max - The maximum x and y values in the desired range. * @return {Vector2} A reference to this vector. */clamp(min,max){// assumes min < max, componentwise this.x=clamp(this.x,min.x,max.x);this.y=clamp(this.y,min.y,max.y);return this;}/** * If this vector's x or y values are greater than the max value, they are * replaced by the max value. * If this vector's x or y values are less than the min value, they are * replaced by the min value. * * @param {number} minVal - The minimum value the components will be clamped to. * @param {number} maxVal - The maximum value the components will be clamped to. * @return {Vector2} A reference to this vector. */clampScalar(minVal,maxVal){this.x=clamp(this.x,minVal,maxVal);this.y=clamp(this.y,minVal,maxVal);return this;}/** * If this vector's length is greater than the max value, it is replaced by * the max value. * If this vector's length is less than the min value, it is replaced by the * min value. * * @param {number} min - The minimum value the vector length will be clamped to. * @param {number} max - The maximum value the vector length will be clamped to. * @return {Vector2} A reference to this vector. */clampLength(min,max){const length=this.length();return this.divideScalar(length||1).multiplyScalar(clamp(length,min,max));}/** * The components of this vector are rounded down to the nearest integer value. * * @return {Vector2} A reference to this vector. */floor(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);return this;}/** * The components of this vector are rounded up to the nearest integer value. * * @return {Vector2} A reference to this vector. */ceil(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this;}/** * The components of this vector are rounded to the nearest integer value * * @return {Vector2} A reference to this vector. */round(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this;}/** * The components of this vector are rounded towards zero (up if negative, * down if positive) to an integer value. * * @return {Vector2} A reference to this vector. */roundToZero(){this.x=Math.trunc(this.x);this.y=Math.trunc(this.y);return this;}/** * Inverts this vector - i.e. sets x = -x and y = -y. * * @return {Vector2} A reference to this vector. */negate(){this.x=-this.x;this.y=-this.y;return this;}/** * Calculates the dot product of the given vector with this instance. * * @param {Vector2} v - The vector to compute the dot product with. * @return {number} The result of the dot product. */dot(v){return this.x*v.x+this.y*v.y;}/** * Calculates the cross product of the given vector with this instance. * * @param {Vector2} v - The vector to compute the cross product with. * @return {number} The result of the cross product. */cross(v){return this.x*v.y-this.y*v.x;}/** * Computes the square of the Euclidean length (straight-line length) from * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should * compare the length squared instead as it is slightly more efficient to calculate. * * @return {number} The square length of this vector. */lengthSq(){return this.x*this.x+this.y*this.y;}/** * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). * * @return {number} The length of this vector. */length(){return Math.sqrt(this.x*this.x+this.y*this.y);}/** * Computes the Manhattan length of this vector. * * @return {number} The length of this vector. */manhattanLength(){return Math.abs(this.x)+Math.abs(this.y);}/** * Converts this vector to a unit vector - that is, sets it equal to a vector * with the same direction as this one, but with a vector length of `1`. * * @return {Vector2} A reference to this vector. */normalize(){return this.divideScalar(this.length()||1);}/** * Computes the angle in radians of this vector with respect to the positive x-axis. * * @return {number} The angle in radians. */angle(){const angle=Math.atan2(-this.y,-this.x)+Math.PI;return angle;}/** * Returns the angle between the given vector and this instance in radians. * * @param {Vector2} v - The vector to compute the angle with. * @return {number} The angle in radians. */angleTo(v){const denominator=Math.sqrt(this.lengthSq()*v.lengthSq());if(denominator===0)return Math.PI/2;const theta=this.dot(v)/denominator;// clamp, to handle numerical problems return Math.acos(clamp(theta,-1,1));}/** * Computes the distance from the given vector to this instance. * * @param {Vector2} v - The vector to compute the distance to. * @return {number} The distance. */distanceTo(v){return Math.sqrt(this.distanceToSquared(v));}/** * Computes the squared distance from the given vector to this instance. * If you are just comparing the distance with another distance, you should compare * the distance squared instead as it is slightly more efficient to calculate. * * @param {Vector2} v - The vector to compute the squared distance to. * @return {number} The squared distance. */distanceToSquared(v){const dx=this.x-v.x,dy=this.y-v.y;return dx*dx+dy*dy;}/** * Computes the Manhattan distance from the given vector to this instance. * * @param {Vector2} v - The vector to compute the Manhattan distance to. * @return {number} The Manhattan distance. */manhattanDistanceTo(v){return Math.abs(this.x-v.x)+Math.abs(this.y-v.y);}/** * Sets this vector to a vector with the same direction as this one, but * with the specified length. * * @param {number} length - The new length of this vector. * @return {Vector2} A reference to this vector. */setLength(length){return this.normalize().multiplyScalar(length);}/** * Linearly interpolates between the given vector and this instance, where * alpha is the percent distance along the line - alpha = 0 will be this * vector, and alpha = 1 will be the given one. * * @param {Vector2} v - The vector to interpolate towards. * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. * @return {Vector2} A reference to this vector. */lerp(v,alpha){this.x+=(v.x-this.x)*alpha;this.y+=(v.y-this.y)*alpha;return this;}/** * Linearly interpolates between the given vectors, where alpha is the percent * distance along the line - alpha = 0 will be first vector, and alpha = 1 will * be the second one. The result is stored in this instance. * * @param {Vector2} v1 - The first vector. * @param {Vector2} v2 - The second vector. * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. * @return {Vector2} A reference to this vector. */lerpVectors(v1,v2,alpha){this.x=v1.x+(v2.x-v1.x)*alpha;this.y=v1.y+(v2.y-v1.y)*alpha;return this;}/** * Returns `true` if this vector is equal with the given one. * * @param {Vector2} v - The vector to test for equality. * @return {boolean} Whether this vector is equal with the given one. */equals(v){return v.x===this.x&&v.y===this.y;}/** * Sets this vector's x value to be `array[ offset ]` and y * value to be `array[ offset + 1 ]`. * * @param {Array<number>} array - An array holding the vector component values. * @param {number} [offset=0] - The offset into the array. * @return {Vector2} A reference to this vector. */fromArray(array,offset=0){this.x=array[offset];this.y=array[offset+1];return this;}/** * Writes the components of this vector to the given array. If no array is provided, * the method returns a new instance. * * @param {Array<number>} [array=[]] - The target array holding the vector components. * @param {number} [offset=0] - Index of the first element in the array. * @return {Array<number>} The vector components. */toArray(array=[],offset=0){array[offset]=this.x;array[offset+1]=this.y;return array;}/** * Sets the components of this vector from the given buffer attribute. * * @param {BufferAttribute} attribute - The buffer attribute holding vector data. * @param {number} index - The index into the attribute. * @return {Vector2} A reference to this vector. */fromBufferAttribute(attribute,index){this.x=attribute.getX(index);this.y=attribute.getY(index);return this;}/** * Rotates this vector around the given center by the given angle. * * @param {Vector2} center - The point around which to rotate. * @param {number} angle - The angle to rotate, in radians. * @return {Vector2} A reference to this vector. */rotateAround(center,angle){const c=Math.cos(angle),s=Math.sin(angle);const x=this.x-center.x;const y=this.y-center.y;this.x=x*c-y*s+center.x;this.y=x*s+y*c+center.y;return this;}/** * Sets each component of this vector to a pseudo-random value between `0` and * `1`, excluding `1`. * * @return {Vector2} A reference to this vector. */random(){this.x=Math.random();this.y=Math.random();return this;}*[Symbol.iterator](){yield this.x;yield this.y;}}/** * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations. * * Iterating through a vector instance will yield its components `(x, y, z, w)` in * the corresponding order. * * Note that three.js expects Quaternions to be normalized. * ```js * const quaternion = new THREE.Quaternion(); * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); * * const vector = new THREE.Vector3( 1, 0, 0 ); * vector.applyQuaternion( quaternion ); * ``` */class Quaternion{/** * Constructs a new quaternion. * * @param {number} [x=0] - The x value of this quaternion. * @param {number} [y=0] - The y value of this quaternion. * @param {number} [z=0] - The z value of this quaternion. * @param {number} [w=1] - The w value of this quaternion. */constructor(x=0,y=0,z=0,w=1){/** * This flag can be used for type testing. * * @type {boolean} * @readonly * @default true */this.isQuaternion=true;this._x=x;this._y=y;this._z=z;this._w=w;}/** * Interpolates between two quaternions via SLERP. This implementation assumes the * quaternion data are managed in flat arrays. * * @param {Array<number>} dst - The destination array. * @param {number} dstOffset - An offset into the destination array. * @param {Array<number>} src0 - The source array of the first quaternion. * @param {number} srcOffset0 - An offset into the first source array. * @param {Array<number>} src1 - The source array of the second quaternion. * @param {number} srcOffset1 - An offset into the second source array. * @param {number} t - The interpolation factor in the range `[0,1]`. * @see {@link Quaternion#slerp} */static slerpFlat(dst,dstOffset,src0,srcOffset0,src1,srcOffset1,t){// fuzz-free, array-based Quaternion SLERP operation let x0=src0[srcOffset0+0],y0=src0[srcOffset0+1],z0=src0[srcOffset0+2],w0=src0[srcOffset0+3];const x1=src1[srcOffset1+0],y1=src1[srcOffset1+1],z1=src1[srcOffset1+2],w1=src1[srcOffset1+3];if(t===0){dst[dstOffset+0]=x0;dst[dstOffset+1]=y0;dst[dstOffset+2]=z0;dst[dstOffset+3]=w0;return;}if(t===1){dst[dstOffset+0]=x1;dst[dstOffset+1]=y1;dst[dstOffset+2]=z1;dst[dstOffset+3]=w1;return;}if(w0!==w1||x0!==x1||y0!==y1||z0!==z1){let s=1-t;const cos=x0*x1+y0*y1+z0*z1+w0*w1,dir=cos>=0?1:-1,sqrSin=1-cos*cos;// Skip the Slerp for tiny steps to avoid numeric problems: if(sqrSin>Number.EPSILON){const sin=Math.sqrt(sqrSin),len=Math.atan2(sin,cos*dir);s=Math.sin(s*len)/sin;t=Math.sin(t*len)/sin;}const tDir=t*dir;x0=x0*s+x1*tDir;y0=y0*s+y1*tDir;z0=z0*s+z1*tDir;w0=w0*s+w1*tDir;// Normalize in case we just did a lerp: if(s===1-t){const f=1/Math.sqrt(x0*x0+y0*y0+z0*z0+w0*w0);x0*=f;y0*=f;z0*=f;w0*=f;}}dst[dstOffset]=x0;dst[dstOffset+1]=y0;dst[dstOffset+2]=z0;dst[dstOffset+3]=w0;}/** * Multiplies two quaternions. This implementation assumes the quaternion data are managed * in flat arrays. * * @param {Array<number>} dst - The destination array. * @param {number} dstOffset - An offset into the destination array. * @param {Array<number>} src0 - The source array of the first quaternion. * @param {number} srcOffset0 - An offset into the first source array. * @param {Array<number>} src1 - The source array of the second quaternion. * @param {number} srcOffset1 - An offset into the second source array. * @return {Array<number>} The destination array. * @see {@link Quaternion#multiplyQuaternions}. */static multiplyQuaternionsFlat(dst,dstOffset,src0,srcOffset0,src1,srcOffset1){const x0=src0[srcOffset0];const y0=src0[srcOffset0+1];const z0=src0[srcOffset0+2];const w0=src0[srcOffset0+3];const x1=src1[srcOffset1];const y1=src1[srcOffset1+1];const z1=src1[srcOffset1+2];const w1=src1[srcOffset1+3];dst[dstOffset]=x0*w1+w0*x1+y0*z1-z0*y1;dst[dstOffset+1]=y0*w1+w0*y1+z0*x1-x0*z1;dst[dstOffset+2]=z0*w1+w0*z1+x0*y1-y0*x1;dst[dstOffset+3]=w0*w1-x0*x1-y0*y1-z0*z1;return dst;}/** * The x value of this quaternion. * * @type {number} * @default 0 */get x(){return this._x;}set x(value){this._x=value;this._onChangeCallback();}/** * The y value of this quaternion. * * @type {number} * @default 0 */get y(){return this._y;}set y(value){this._y=value;this._onChangeCallback();}/** * The z value of this quaternion. * * @type {number} * @default 0 */get z(){return this._z;}set z(value){this._z=value;this._onChangeCallback();}/** * The w value of this quaternion. * * @type {number} * @default 1 */get w(){return this._w;}set w(value){this._w=value;this._onChangeCallback();}/** * Sets the quaternion components. * * @param {number} x - The x value of this quaternion. * @param {number} y - The y value of this quaternion. * @param {number} z - The z value of this quaternion. * @param {number} w - The w value of this quaternion. * @return {Quaternion} A reference to this quaternion. */set(x,y,z,w){this._x=x;this._y=y;this._z=z;this._w=w;this._onChangeCallback();return this;}/** * Returns a new quaternion with copied values from this instance. * * @return {Quaternion} A clone of this instance. */clone(){return new this.constructor(this._x,this._y,this._z,this._w);}/** * Copies the values of the given quaternion to this instance. * * @param {Quaternion} quaternion - The quaternion to copy. * @return {Quaternion} A reference to this quaternion. */copy(quaternion){this._x=quaternion.x;this._y=quaternion.y;this._z=quaternion.z;this._w=quaternion.w;this._onChangeCallback();return this;}/** * Sets this quaternion from the rotation specified by the given * Euler angles. * * @param {Euler} euler - The Euler angles. * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. * @return {Quaternion} A reference to this quaternion. */setFromEuler(euler,update=true){const x=euler._x,y=euler._y,z=euler._z,order=euler._order;// http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ // content/SpinCalc.m const cos=Math.cos;const sin=Math.sin;const c1=cos(x/2);const c2=cos(y/2);const c3=cos(z/2);const s1=sin(x/2);const s2=sin(y/2);const s3=sin(z/2);switch(order){case 'XYZ':this._x=s1*c2*c3+c1*s2*s3;this._y=c1*s2*c3-s1*c2*s3;this._z=c1*c2*s3+s1*s2*c3;this._w=c1*c2*c3-s1*s2*s3;break;case 'YXZ':this._x=s1*c2*c3+c1*s2*s3;this._y=c1*s2*c3-s1*c2*s3;this._z=c1*c2*s3-s1*s2*c3;this._w=c1*c2*c3+s1*s2*s3;break;case 'ZXY':this._x=s1*c2*c3-c1*s2*s3;this._y=c1*s2*c3+s1*c2*s3;this._z=c1*c2*s3+s1*s2*c3;this._w=c1*c2*c3-s1*s2*s3;break;case 'ZYX':this._x=s1*c2*c3-c1*s2*s3;this._y=c1*s2*c3+s1*c2*s3;this._z=c1*c2*s3-s1*s2*c3;this._w=c1*c2*c3+s1*s2*s3;break;case 'YZX':this._x=s1*c2*c3+c1*s2*s3;this._y=c1*s2*c3+s1*c2*s3;this._z=c1*c2*s3-s1*s2*c3;this._w=c1*c2*c3-s1*s2*s3;break;case 'XZY':this._x=s1*c2*c3-c1*s2*s3;this._y=c1*s2*c3-s1*c2*s3;this._z=c1*c2*s3+s1*s2*c3;this._w=c1*c2*c3+s1*s2*s3;break;default:console.warn('THREE.Quaternion: .setFromEuler() encountered an unknown order: '+order);}if(update===true)this._onChangeCallback();return this;}/** * Sets this quaternion from the given axis and angle. * * @param {Vector3} axis - The normalized axis. * @param {number} angle - The angle in radians. * @return {Quaternion} A reference to this quaternion. */setFromAxisAngle(axis,angle){// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm const halfAngle=angle/2,s=Math.sin(halfAngle);this._x=axis.x*s;this._y=axis.y*s;this._z=axis.z*s;this._w=Math.cos(halfAngle);this._onChangeCallback();return this;}/** * Sets this quaternion from the given rotation matrix. * * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). * @return {Quaternion} A reference to this quaternion. */setFromRotationMatrix(m){// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) const te=m.elements,m11=te[0],m12=te[4],m13=te[8],m21=te[1],m22=te[5],m23=te[9],m31=te[2],m32=te[6],m33=te[10],trace=m11+m22+m33;if(trace>0){const s=0.5/Math.sqrt(trace+1.0);this._w=0.25/s;this._x=(m32-m23)*s;this._y=(m13-m31)*s;this._z=(m21-m12)*s;}else if(m11>m22&&m11>m33){const s=2.0*Math.sqrt(1.0+m11-m22-m33);this._w=(m32-m23)/s;this._x=0.25*s;this._y=(m12+m21)/s;this._z=(m13+m31)/s;}else if(m22>m33){const s=2.0*Math.sqrt(1.0+m22-m11-m33);this._w=(m13-m31)/s;this._x=(m12+m21)/s;this._y=0.25*s;this._z=(m23+m32)/s;}else {const s=2.0*Math.sqrt(1.0+m33-m11-m22);this._w=(m21-m12)/s;this._x=(m13+m31)/s;this._y=(m23+m32)/s;this._z=