UNPKG

panolens

Version:
1,877 lines (1,282 loc) 252 kB
import { Cache, Texture, RGBFormat, RGBAFormat, CubeTexture, EventDispatcher, VideoTexture, LinearFilter, SpriteMaterial, Sprite, Color, CanvasTexture, DoubleSide, Vector3, Mesh, BackSide, Object3D, SphereBufferGeometry, MeshBasicMaterial, BufferGeometry, BufferAttribute, ShaderLib, BoxBufferGeometry, ShaderMaterial, Matrix4, Vector2, Quaternion, PlaneBufferGeometry, Math as Math$1, MOUSE, PerspectiveCamera, OrthographicCamera, Euler, Scene, StereoCamera, WebGLRenderTarget, NearestFilter, WebGLRenderer, Raycaster, Frustum, REVISION as REVISION$1 } from 'three'; const version="0.12.1";const dependencies={three:"^0.105.2"}; /** * REVISION * @module REVISION * @example PANOLENS.REVISION * @type {string} revision */ const REVISION = version.split( '.' )[ 1 ]; /** * VERSION * @module VERSION * @example PANOLENS.VERSION * @type {string} version */ const VERSION = version; /** * THREEJS REVISION * @module THREE_REVISION * @example PANOLENS.THREE_REVISION * @type {string} threejs revision */ const THREE_REVISION = dependencies.three.split( '.' )[ 1 ]; /** * THREEJS VERSION * @module THREE_VERSION * @example PANOLENS.THREE_VERSION * @type {string} threejs version */ const THREE_VERSION = dependencies.three.replace( /[^0-9.]/g, '' ); /** * CONTROLS * @module CONTROLS * @example PANOLENS.CONTROLS.ORBIT * @property {number} ORBIT 0 * @property {number} DEVICEORIENTATION 1 */ const CONTROLS = { ORBIT: 0, DEVICEORIENTATION: 1 }; /** * MODES * @module MODES * @example PANOLENS.MODES.UNKNOWN * @property {number} UNKNOWN 0 * @property {number} NORMAL 1 * @property {number} CARDBOARD 2 * @property {number} STEREO 3 */ const MODES = { UNKNOWN: 0, NORMAL: 1, CARDBOARD: 2, STEREO: 3 }; /** * Data URI Images * @module DataImage * @example PANOLENS.DataImage.Info * @property {string} Info Information Icon * @property {string} Arrow Arrow Icon * @property {string} FullscreenEnter Fullscreen Enter Icon * @property {string} FullscreenLeave Fullscreen Leave Icon * @property {string} VideoPlay Video Play Icon * @property {string} VideoPause Video Pause Icon * @property {string} WhiteTile White Tile Icon * @property {string} Setting Settings Icon * @property {string} ChevronRight Chevron Right Icon * @property {string} Check Check Icon * @property {string} ViewIndicator View Indicator Icon */ const DataImage = { Info: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAABAAAAAQADq8/hgAAADBklEQVR42u2bP08UQRiHnzFaSYCI/xoksdBIqGwIiYWRUBISExpCQ0ej38FWOmlIKKhoMPEbaCxsrrHiYrQgOSlQEaICrT+LHSPZzNzt3s3c3Hn7lHvLzvv82L2dm30XKioqKgYY062BJF0HpoA7wARwBbhsPz4DjoEG8AnYNcZ8Sx1Op8IXJM1KWpdUV3nq9m9nJV1I7VNGfEzSM0mNNqR9NOwxx1L7NRMflbQm6SSgeJ4TO8Zoat+8/LKkg4jieQ4kLaf2RtKwpJ0uiufZkTScSn5S0l5C+b/sSZrstvyMpKPU5uc4kjTTjkvpeYCkaeA1/+7hvcIZMGuMqUULQNIU8Aa4ltrWwyHwyBizGzwASSPAe+B2assW7AH3jTE/i+xcZoa12Qfy2Bo3i+5cKABl99zF1GYlWFTBeULLS0DZrOsDcDNggTXgc27bLWA64BhfgHvGmB8dHUXZ1DM0S45xliKMs9bKr+klIOkqsBrwv9JtVq1DewEAT4Ch1BYdMGQdygeg7Df4SmqDAKyoyXpCszPgITCeuvoAjFuX0gE8jljUdv7bCtiOOJ7XpdUZ8L/gdXHOA5QtYH5NXXVgbrgWWn1nwFTqaiPgdPIFcDd1tRFwOl307DwRuZgXwLvctgfA04hjOp18AcReZ6sZY16e3yDpUuQxnU6+S2AkcjEpcDr1zxOXSPgCKLSa0mc4nXwB/EpdbQScTr4AGqmrjYDTyRfAx9TVRsDp5Aug8LJyH+F0cgZg58z11BUHpO5ruGh2G3ybuuqAeF2aBfAqddUB8bq0OgP2U1cegH3aOQOMMb+BrdTVB2DLupQLwLIOnKY26IBT6+ClaQDGmO/ARmqLDtiwDn7HVkcY+EdjNoTlCI+tYhO2iUppm6HKslPUq2qQKHpUe8AFsjaUXuUQWCgqXyoAG8IuME/WkNRrnAHzZfqDSgdgQ6gBc2Td3b3CMTBXtkOsIzTIjZLnQhjcVtlcEIPZLJ0LoVvt8s/Va+3yuSAG84UJRxB98cpM9dJURUVFxSDzBxKde4Lk3/h2AAAAAElFTkSuQmCC', Arrow: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAABAAAAAQADq8/hgAAADPklEQVR42u2bMUscQRiG30/SRaJEI1ZKUiRErNIELRUbQYSAnX8hpVUgkDYp0wgWVjYW+QcJaQzYpLojJIXhtDDEKBpj65ti58ixmdmb2ZvZ7+T2AUHudmfmeXf2bnb3O6CmpqZmgJGqOiI5AWAWwEMA0wDuArht3r4CcAagBeAbgIaI/NQOp1fhIZKLJN+SbDKcptl3keSQtk+I+BjJVyRbJaRdtEybY9p+ReKjJN+QvIwonufS9DGq7ZuXXyd5nFA8zzHJdW1vkLxDcrdC8Ty7JO9oyc+QPFCUb3NAcqZq+TmSp9rmHZySnCvjErwOIPkUwHv8+w7vF64ALIrIfrIASM4C+ADgnratgxMACyLSiB4AyREAnwE80LbswgGAJyJy4bNxyApr6wbIw4xxy3djrwCYfeeuaZsFsEbPdULXU4DZqusLgMkEA21P05EEbf8A8FhEzos28pkBLxLKL5s/r/M1kEkz9vKQHGeatf05yfmOfubNa7G5JDle5NhtBjwHMBz5yFwAWBaRT+0XzP8pZsKwcQiH2fX8Ycojb+kzxUw4ZJn7CSQXqpRPHMKCq7+iZJ71Mvdy/DftXSQ6HcJdSDaqPPKW/mPOBO+lcbvzCU35RCFM2PpwnQKzZQfdgfe0dxH5dLA6uQJ4pC2fIASrkyuA6X6QjxyC1ckVQNn7bNHlI4ZgdXIFUObiJJl8pBCsTjGfuIwA2Cv4FN7xbYjkjqsRAHuIePXoCiDF1Zk2VidXAL+1R5sAq5MrgJb2aBNgdXIF8FV7tAmwOrkCCFs73wysTtYATHFCU3vEEWm6Ci6KvgY/ao86Ik6XogDeaY86Ik6XbjPgSHvkEThCwQy45XpDRK5JbgN4GWkgUyR9H65MRQxgW0SunZ5FezK7pfwd8e8MV8UfAPdF5Jdrg8JrAbPjprZFD2wWyQP6j8ZSEufRmGlgQ9umBBvd5IOgbjFUKLu+XnWBhG+rpsFVZGUo/coJgFVf+aAATAgNACvICpL6jSsAKyH1QcEBmBD2ASwhq+7uF84ALIVWiPUEB7lQsiOEwS2VzQUxmMXSuRCqKpd/zX4rl88FMZg/mLAEcSN+MlP/aKqmpqZmkPkL0hSjwOpNKxwAAAAASUVORK5CYII=', FullscreenEnter: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik03IDE0SDV2NWg1di0ySDd2LTN6bS0yLTRoMlY3aDNWNUg1djV6bTEyIDdoLTN2Mmg1di01aC0ydjN6TTE0IDV2MmgzdjNoMlY1aC01eiIvPgo8L3N2Zz4=', FullscreenLeave: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggc3R5bGU9ImZpbGw6I2ZmZiIgZD0iTTE0LDE0SDE5VjE2SDE2VjE5SDE0VjE0TTUsMTRIMTBWMTlIOFYxNkg1VjE0TTgsNUgxMFYxMEg1VjhIOFY1TTE5LDhWMTBIMTRWNUgxNlY4SDE5WiIgLz48L3N2Zz4=', VideoPlay: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggc3R5bGU9ImZpbGw6I2ZmZiIgZD0iTTgsNS4xNFYxOS4xNEwxOSwxMi4xNEw4LDUuMTRaIiAvPjwvc3ZnPg==', VideoPause: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggc3R5bGU9ImZpbGw6I2ZmZiIgZD0iTTE0LDE5LjE0SDE4VjUuMTRIMTRNNiwxOS4xNEgxMFY1LjE0SDZWMTkuMTRaIiAvPjwvc3ZnPg==', WhiteTile: 'data:image/png;base64,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', Setting: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAABAAAAAQADq8/hgAAADn0lEQVR42u2bzUsVURjGnyO6CPzAMnTjppAo3LTwH1CqTfaxbeOiRS37A0wXtROFVi1aRBs3LWohSIGbQAQXViBGRhG0UIRKUCpK7q/FnOB2uc6cOXNmRnGe3eW+H8/7zLln3vNxpQoVKlQ4wjBFJAFOSRqX1O7osivpvjHmU1nChBZglvSYLYJbS0EanCvIJzWK+gnsyH34/8OuMaYjb265jwCgz6N4SWq3vodbAEmnS/KtBDgoAgyU5BteAOAkMAPcBroc7PskDWfgN+wyDwBdltMMcDI3tYBnde/pHeARMNTErgd4APzweP834oeN1dMkz5DlsFNn/yyv4kdiSK4At4AO4CqwGaDwRmza2B0210qM7YhrXU59ANAq6bWkwQTTn5KO5fIE0uVYlXTeGLOXFMx1DrjlULwKKN41x6DlnIjEEQCckPRe0okCiguJr5LOGGO+xhm5jICJQ1i8LOeJJKPYEQAMKvrtt5ZdjSf2FM0Fq/sZJI2A6UNcvCz36TiDfUcAcE1SPu/U6Mm8k/TFfu6XdFb5iX3dGPM8lQfwNod3+TowBnQ3yddtv1vPIe+b1JIBiwEJ1IAJ208k5W21trWA+V/5CHAcmAtU/A2P/DcCiTAHHE8tgCVhgLvAXgYCk17Jo/yTGfLuWe7Zd72AC8CWB4n3OAz7mLytNkZabAEXMhfeQKYfWEpJZCxA3rGUOZeA/qDF15FpAz47EvlNk9neI2e3jeWCz0BbmvipNkSMMX8kuSZYM8Z8zyqAjbHmaN5mOeYjgIXrU93MWrxHrNQjrqiDkQMLHwG+OdqF3NN3jeXKzU8AoF1SzdH8XKhJUO7HZDXLMbwAwICkJUULFxe0SbqSVQAbw3Xi7Ze0ZLmGAzAKbHs0JGU1QtvAaIjCW4B7ZOvJy2qFa5a730RPtBiaz0CgnkiZi6F5fBZDVMvho7EhcuS3xJJ2hV9IupgTqaLw0hhzab8vq23xOG/r+LDsKjLgYVzxUnU0ltwK2wDezUyJmEwqXgp/PL4rvxthaeCSI+zxuA10J8ZkWdJNSb2SLkvayKHwDRu71+ZajrG941J8agALDQ3GU/a/IvMkYCPzmCbtLNEVmacNtgs5iP9fYVNEV1Q6Hez7yNZSL+J2SarTcpqiyV2iUkG0IvPFvbz5FbEn+KEk3wMjwMeSfCsBXFBdly9CAPk9ydyffpECuB5tZfVJjaKWueOSfinln6YK4lahQoUKRxd/AcRPGTcQCAUQAAAAAElFTkSuQmCC', ChevronRight: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTguNTksMTYuNThMMTMuMTcsMTJMOC41OSw3LjQxTDEwLDZMMTYsMTJMMTAsMThMOC41OSwxNi41OFoiIC8+PC9zdmc+', Check: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTIxLDdMOSwxOUwzLjUsMTMuNUw0LjkxLDEyLjA5TDksMTYuMTdMMTkuNTksNS41OUwyMSw3WiIgLz48L3N2Zz4=', ViewIndicator: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBpZD0idmlldy1pbmRpY2F0b3IiIGhlaWdodD0iMzAiIHdpZHRoPSIzMCIgdmlld0JveD0iLTIuNSAtMSAzMCAzMCI+Cgk8c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7ZmlsbDpub25lO30uc3Qxe3N0cm9rZS13aWR0aDo2O3N0cm9rZS1taXRlcmxpbWl0OjEwO30KCTwvc3R5bGU+Cgk8Zz4KCQk8cGF0aCBjbGFzcz0ic3QwIiBkPSJNIDEyLjUgMCBBIDEyLjUgMTIuNSAwIDAgMCAtMTIuNSAwIEEgMTIuNSAxMi41IDAgMCAwIDEyLjUgMCIgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxMywxNS41KSI+PC9wYXRoPgoJCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0gMTMgMCBMIDEwIDIgTCAxNiAyIFoiPjwvcGF0aD4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJNIDIgMCBBIDIgMiAwIDAgMCAtMiAwIEEgMiAyIDAgMCAwIDIgMCIgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMSwxMywxNS41KSI+PC9wYXRoPgoJCTxwYXRoIGNsYXNzPSJzdDEiIGlkPSJpbmRpY2F0b3IiIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMTMsMTUuNSkiPjwvcGF0aD4KCTwvZz4KPC9zdmc+' }; /** * @module ImageLoader * @description Image loader with progress based on {@link https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js} */ const ImageLoader = { /** * Load image * @example PANOLENS.ImageLoader.load( IMAGE_URL ) * @method load * @param {string} url - An image url * @param {function} onLoad - On load callback * @param {function} onProgress - In progress callback * @param {function} onError - On error callback */ load: function ( url, onLoad = () => {}, onProgress = () => {}, onError = () => {} ) { // Enable cache Cache.enabled = true; let cached, request, arrayBufferView, blob, urlCreator, image, reference; // Reference key for (let iconName in DataImage) { if (DataImage.hasOwnProperty(iconName) && url === DataImage[iconName]) { reference = iconName; } } // Cached cached = Cache.get(reference ? reference : url); if (cached !== undefined) { if (onLoad) { setTimeout(function () { onProgress({loaded: 1, total: 1}); onLoad(cached); }, 0); } return cached; } // Construct a new XMLHttpRequest urlCreator = window.URL || window.webkitURL; image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img'); // Add to cache Cache.add(reference ? reference : url, image); const onImageLoaded = () => { urlCreator.revokeObjectURL(image.src); onLoad(image); }; if (url.indexOf('data:') === 0) { image.addEventListener('load', onImageLoaded, false); image.src = url; return image; } image.crossOrigin = this.crossOrigin !== undefined ? this.crossOrigin : ''; request = new window.XMLHttpRequest(); request.open('GET', url, true); if (process.env.npm_lifecycle_event !== 'test') { /* istanbul ignore next */ request.onreadystatechange = function () { if (this.readyState === 4 && this.status >= 400) { onError(); } }; } request.responseType = 'arraybuffer'; request.addEventListener( 'error', onError ); request.addEventListener( 'progress', event => { if ( !event ) return; const { loaded, total, lengthComputable } = event; if ( lengthComputable ) { onProgress( { loaded, total } ); } } ); request.addEventListener( 'loadend', event => { if ( !event ) return; const { currentTarget: { response } } = event; arrayBufferView = new Uint8Array( response ); blob = new window.Blob( [ arrayBufferView ] ); image.addEventListener( 'load', onImageLoaded, false ); image.src = urlCreator.createObjectURL( blob ); } ); request.send(null); } }; /** * @module TextureLoader * @description Texture loader based on {@link https://github.com/mrdoob/three.js/blob/master/src/loaders/TextureLoader.js} */ const TextureLoader = { /** * Load image texture * @example PANOLENS.TextureLoader.load( IMAGE_URL ) * @method load * @param {string} url - An image url * @param {function} onLoad - On load callback * @param {function} onProgress - In progress callback * @param {function} onError - On error callback * @return {THREE.Texture} - Image texture */ load: function ( url, onLoad = () => {}, onProgress, onError ) { var texture = new Texture(); ImageLoader.load( url, function ( image ) { texture.image = image; // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. const isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; texture.format = isJPEG ? RGBFormat : RGBAFormat; texture.needsUpdate = true; onLoad( texture ); }, onProgress, onError ); return texture; } }; /** * @module CubeTextureLoader * @description Cube Texture Loader based on {@link https://github.com/mrdoob/three.js/blob/master/src/loaders/CubeTextureLoader.js} */ const CubeTextureLoader = { /** * Load 6 images as a cube texture * @example PANOLENS.CubeTextureLoader.load( [ 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' ] ) * @method load * @param {array} urls - array of 6 urls to images, one for each side of the CubeTexture. The urls should be specified in the following order: pos-x, neg-x, pos-y, neg-y, pos-z, neg-z * @param {function} onLoad - On load callback * @param {function} onProgress - In progress callback * @param {function} onError - On error callback * @return {THREE.CubeTexture} - Cube texture */ load: function ( urls, onLoad = () => {}, onProgress = () => {}, onError ) { var texture, loaded, progress, all, loadings; texture = new CubeTexture( [] ); loaded = 0; progress = {}; all = {}; urls.map( function ( url, index ) { ImageLoader.load( url, function ( image ) { texture.images[ index ] = image; loaded++; if ( loaded === 6 ) { texture.needsUpdate = true; onLoad( texture ); } }, function ( event ) { progress[ index ] = { loaded: event.loaded, total: event.total }; all.loaded = 0; all.total = 0; loadings = 0; for ( var i in progress ) { loadings++; all.loaded += progress[ i ].loaded; all.total += progress[ i ].total; } if ( loadings < 6 ) { all.total = all.total / loadings * 6; } onProgress( all ); }, onError ); } ); return texture; } }; /** * @classdesc User Media * @constructor * @param {object} [constraints={ video: { width: { ideal: 1920 }, height: { ideal: 1080 }, facingMode: { exact: 'environment' } }, audio: false }] */ function Media ( constraints ) { const defaultConstraints = { video: { width: { ideal: 1920 }, height: { ideal: 1080 }, facingMode: { exact: 'environment' } }, audio: false }; this.constraints = Object.assign( defaultConstraints, constraints ); this.container = null; this.scene = null; this.element = null; this.devices = []; this.stream = null; this.ratioScalar = 1; this.videoDeviceIndex = 0; } Media.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { setContainer: function ( container ) { this.container = container; }, setScene: function ( scene ) { this.scene = scene; }, /** * Enumerate devices * @memberOf Media * @instance * @returns {Promise} */ enumerateDevices: function () { const devices = this.devices; const resolvedPromise = new Promise( resolve => { resolve( devices ); } ); return devices.length > 0 ? resolvedPromise : window.navigator.mediaDevices.enumerateDevices(); }, /** * Switch to next available video device * @memberOf Media * @instance */ switchNextVideoDevice: function () { const stop = this.stop.bind( this ); const start = this.start.bind( this ); const setVideDeviceIndex = this.setVideDeviceIndex.bind( this ); let index = this.videoDeviceIndex; this.getDevices( 'video' ) .then( devices => { stop(); index++; if ( index >= devices.length ) { setVideDeviceIndex( 0 ); index--; } else { setVideDeviceIndex( index ); } start( devices[ index ] ); } ); }, /** * Get devices * @param {string} type - type keyword to match device.kind * @memberOf Media * @instance */ getDevices: function ( type = 'video' ) { const devices = this.devices; const validate = _devices => { return _devices.map( device => { if ( !devices.includes( device ) ) { devices.push( device ); } return device; } ); }; const filter = _devices => { const reg = new RegExp( type, 'i' ); return _devices.filter( device => reg.test( device.kind ) ); }; return this.enumerateDevices() .then( validate ) .then( filter ); }, /** * Get user media * @param {MediaStreamConstraints} constraints * @memberOf Media * @instance */ getUserMedia: function ( constraints ) { const setMediaStream = this.setMediaStream.bind( this ); const playVideo = this.playVideo.bind( this ); const onCatchError = error => { console.warn( `PANOLENS.Media: ${error}` ); }; return window.navigator.mediaDevices.getUserMedia( constraints ) .then( setMediaStream ) .then( playVideo ) .catch( onCatchError ); }, /** * Set video device index * @param {number} index * @memberOf Media * @instance */ setVideDeviceIndex: function ( index ) { this.videoDeviceIndex = index; }, /** * Start streaming * @param {MediaDeviceInfo} [targetDevice] * @memberOf Media * @instance */ start: function( targetDevice ) { const constraints = this.constraints; const getUserMedia = this.getUserMedia.bind( this ); const onVideoDevices = devices => { if ( !devices || devices.length === 0 ) { throw Error( 'no video device found' ); } const device = targetDevice || devices[ 0 ]; constraints.video.deviceId = device.deviceId; return getUserMedia( constraints ); }; this.element = this.createVideoElement(); return this.getDevices().then( onVideoDevices ); }, /** * Stop streaming * @memberOf Media * @instance */ stop: function () { const stream = this.stream; if ( stream && stream.active ) { const track = stream.getTracks()[ 0 ]; track.stop(); window.removeEventListener( 'resize', this.onWindowResize.bind( this ) ); this.element = null; this.stream = null; } }, /** * Set media stream * @param {MediaStream} stream * @memberOf Media * @instance */ setMediaStream: function ( stream ) { this.stream = stream; this.element.srcObject = stream; if ( this.scene ) { this.scene.background = this.createVideoTexture(); } window.addEventListener( 'resize', this.onWindowResize.bind( this ) ); }, /** * Play video element * @memberOf Media * @instance */ playVideo: function () { const { element } = this; if ( element ) { element.play(); this.dispatchEvent( { type: 'play' } ); } }, /** * Pause video element * @memberOf Media * @instance */ pauseVideo: function () { const { element } = this; if ( element ) { element.pause(); this.dispatchEvent( { type: 'pause' } ); } }, /** * Create video texture * @memberOf Media * @instance * @returns {THREE.VideoTexture} */ createVideoTexture: function () { const video = this.element; const texture = new VideoTexture( video ); texture.generateMipmaps = false; texture.minFilter = LinearFilter; texture.magFilter = LinearFilter; texture.format = RGBFormat; texture.center.set( 0.5, 0.5 ); video.addEventListener( 'canplay', this.onWindowResize.bind( this ) ); return texture; }, /** * Create video element * @memberOf Media * @instance * @returns {HTMLVideoElement} * @fires Media#canplay */ createVideoElement: function() { const dispatchEvent = this.dispatchEvent.bind( this ); const video = document.createElement( 'video' ); /** * Video can play event * @type {object} * @event Media#canplay */ const canPlay = () => dispatchEvent( { type: 'canplay' } ); video.setAttribute( 'autoplay', '' ); video.setAttribute( 'muted', '' ); video.setAttribute( 'playsinline', '' ); video.style.position = 'absolute'; video.style.top = '0'; video.style.left = '0'; video.style.width = '100%'; video.style.height = '100%'; video.style.objectPosition = 'center'; video.style.objectFit = 'cover'; video.style.display = this.scene ? 'none' : ''; video.addEventListener( 'canplay', canPlay ); return video; }, /** * On window resize event * @param {Event} event * @memberOf Media * @instance */ onWindowResize: function () { if ( this.element && this.element.videoWidth && this.element.videoHeight && this.scene ) { const { clientWidth: width, clientHeight: height } = this.container; const texture = this.scene.background; const { videoWidth, videoHeight } = this.element; const cameraRatio = videoHeight / videoWidth; const viewportRatio = this.container ? width / height : 1.0; const ratio = cameraRatio * viewportRatio * this.ratioScalar; if ( width > height ) { texture.repeat.set( ratio, 1 ); } else { texture.repeat.set( 1, 1 / ratio ); } } } } ); /** * @classdesc Reticle 3D Sprite * @constructor * @param {THREE.Color} [color=0xffffff] - Color of the reticle sprite * @param {boolean} [autoSelect=true] - Auto selection * @param {number} [dwellTime=1500] - Duration for dwelling sequence to complete */ function Reticle ( color = 0xffffff, autoSelect = true, dwellTime = 1500 ) { this.dpr = window.devicePixelRatio; const { canvas, context } = this.createCanvas(); const material = new SpriteMaterial( { color, map: this.createCanvasTexture( canvas ) } ); Sprite.call( this, material ); this.canvasWidth = canvas.width; this.canvasHeight = canvas.height; this.context = context; this.color = color instanceof Color ? color : new Color( color ); this.autoSelect = autoSelect; this.dwellTime = dwellTime; this.rippleDuration = 500; this.position.z = -10; this.center.set( 0.5, 0.5 ); this.scale.set( 0.5, 0.5, 1 ); this.startTimestamp = null; this.timerId = null; this.callback = null; this.frustumCulled = false; this.updateCanvasArcByProgress( 0 ); } Reticle.prototype = Object.assign( Object.create( Sprite.prototype ), { constructor: Reticle, /** * Set material color * @param {THREE.Color} color * @memberOf Reticle * @instance */ setColor: function ( color ) { this.material.color.copy( color instanceof Color ? color : new Color( color ) ); }, /** * Create canvas texture * @param {HTMLCanvasElement} canvas * @memberOf Reticle * @instance * @returns {THREE.CanvasTexture} */ createCanvasTexture: function ( canvas ) { const texture = new CanvasTexture( canvas ); texture.minFilter = LinearFilter; texture.magFilter = LinearFilter; texture.generateMipmaps = false; return texture; }, /** * Create canvas element * @memberOf Reticle * @instance * @returns {object} object * @returns {HTMLCanvasElement} object.canvas * @returns {CanvasRenderingContext2D} object.context */ createCanvas: function () { const width = 32; const height = 32; const canvas = document.createElement( 'canvas' ); const context = canvas.getContext( '2d' ); const dpr = this.dpr; canvas.width = width * dpr; canvas.height = height * dpr; context.scale( dpr, dpr ); context.shadowBlur = 5; context.shadowColor = 'rgba(200,200,200,0.9)'; return { canvas, context }; }, /** * Update canvas arc by progress * @param {number} progress * @memberOf Reticle * @instance */ updateCanvasArcByProgress: function ( progress ) { const context = this.context; const { canvasWidth, canvasHeight, material } = this; const dpr = this.dpr; const degree = progress * Math.PI * 2; const color = this.color.getStyle(); const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; const lineWidth = 3; context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); if ( progress === 0 ) { context.arc( x, y, canvasWidth / 16, 0, 2 * Math.PI ); context.fillStyle = color; context.fill(); } else { context.arc( x, y, canvasWidth / 4 - lineWidth, -Math.PI / 2, -Math.PI / 2 + degree ); context.strokeStyle = color; context.lineWidth = lineWidth; context.stroke(); } context.closePath(); material.map.needsUpdate = true; }, /** * Ripple effect * @memberOf Reticle * @instance * @fires Reticle#reticle-ripple-start * @fires Reticle#reticle-ripple-end */ ripple: function () { const context = this.context; const { canvasWidth, canvasHeight, material } = this; const duration = this.rippleDuration; const timestamp = performance.now(); const color = this.color; const dpr = this.dpr; const x = canvasWidth * 0.5 / dpr; const y = canvasHeight * 0.5 / dpr; const update = () => { const timerId = window.requestAnimationFrame( update ); const elapsed = performance.now() - timestamp; const progress = elapsed / duration; const opacity = 1.0 - progress > 0 ? 1.0 - progress : 0; const radius = progress * canvasWidth * 0.5 / dpr; context.clearRect( 0, 0, canvasWidth, canvasHeight ); context.beginPath(); context.arc( x, y, radius, 0, Math.PI * 2 ); context.fillStyle = `rgba(${color.r * 255}, ${color.g * 255}, ${color.b * 255}, ${opacity})`; context.fill(); context.closePath(); if ( progress >= 1.0 ) { window.cancelAnimationFrame( timerId ); this.updateCanvasArcByProgress( 0 ); /** * Reticle ripple end event * @type {object} * @event Reticle#reticle-ripple-end */ this.dispatchEvent( { type: 'reticle-ripple-end' } ); } material.map.needsUpdate = true; }; /** * Reticle ripple start event * @type {object} * @event Reticle#reticle-ripple-start */ this.dispatchEvent( { type: 'reticle-ripple-start' } ); update(); }, /** * Make reticle visible * @memberOf Reticle * @instance */ show: function () { this.visible = true; }, /** * Make reticle invisible * @memberOf Reticle * @instance */ hide: function () { this.visible = false; }, /** * Start dwelling * @param {function} callback * @memberOf Reticle * @instance * @fires Reticle#reticle-start */ start: function ( callback ) { if ( !this.autoSelect ) { return; } /** * Reticle start event * @type {object} * @event Reticle#reticle-start */ this.dispatchEvent( { type: 'reticle-start' } ); this.startTimestamp = performance.now(); this.callback = callback; this.update(); }, /** * End dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-end */ end: function(){ if ( !this.startTimestamp ) { return; } window.cancelAnimationFrame( this.timerId ); this.updateCanvasArcByProgress( 0 ); this.callback = null; this.timerId = null; this.startTimestamp = null; /** * Reticle end event * @type {object} * @event Reticle#reticle-end */ this.dispatchEvent( { type: 'reticle-end' } ); }, /** * Update dwelling * @memberOf Reticle * @instance * @fires Reticle#reticle-update */ update: function () { this.timerId = window.requestAnimationFrame( this.update.bind( this ) ); const elapsed = performance.now() - this.startTimestamp; const progress = elapsed / this.dwellTime; this.updateCanvasArcByProgress( progress ); /** * Reticle update event * @type {object} * @event Reticle#reticle-update */ this.dispatchEvent( { type: 'reticle-update', progress } ); if ( progress >= 1.0 ) { window.cancelAnimationFrame( this.timerId ); if ( this.callback ) { this.callback(); } this.end(); this.ripple(); } } } ); function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var Tween = createCommonjsModule(function (module, exports) { /** * Tween.js - Licensed under the MIT license * https://github.com/tweenjs/tween.js * ---------------------------------------------- * * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. * Thank you all, you're awesome! */ var _Group = function () { this._tweens = {}; this._tweensAddedDuringUpdate = {}; }; _Group.prototype = { getAll: function () { return Object.keys(this._tweens).map(function (tweenId) { return this._tweens[tweenId]; }.bind(this)); }, removeAll: function () { this._tweens = {}; }, add: function (tween) { this._tweens[tween.getId()] = tween; this._tweensAddedDuringUpdate[tween.getId()] = tween; }, remove: function (tween) { delete this._tweens[tween.getId()]; delete this._tweensAddedDuringUpdate[tween.getId()]; }, update: function (time, preserve) { var tweenIds = Object.keys(this._tweens); if (tweenIds.length === 0) { return false; } time = time !== undefined ? time : TWEEN.now(); // Tweens are updated in "batches". If you add a new tween during an update, then the // new tween will be updated in the next batch. // If you remove a tween during an update, it may or may not be updated. However, // if the removed tween was added during the current batch, then it will not be updated. while (tweenIds.length > 0) { this._tweensAddedDuringUpdate = {}; for (var i = 0; i < tweenIds.length; i++) { var tween = this._tweens[tweenIds[i]]; if (tween && tween.update(time) === false) { tween._isPlaying = false; if (!preserve) { delete this._tweens[tweenIds[i]]; } } } tweenIds = Object.keys(this._tweensAddedDuringUpdate); } return true; } }; var TWEEN = new _Group(); TWEEN.Group = _Group; TWEEN._nextId = 0; TWEEN.nextId = function () { return TWEEN._nextId++; }; // Include a performance.now polyfill. // In node.js, use process.hrtime. if (typeof (self) === 'undefined' && typeof (process) !== 'undefined' && process.hrtime) { TWEEN.now = function () { var time = process.hrtime(); // Convert [seconds, nanoseconds] to milliseconds. return time[0] * 1000 + time[1] / 1000000; }; } // In a browser, use self.performance.now if it is available. else if (typeof (self) !== 'undefined' && self.performance !== undefined && self.performance.now !== undefined) { // This must be bound, because directly assigning this function // leads to an invocation exception in Chrome. TWEEN.now = self.performance.now.bind(self.performance); } // Use Date.now if it is available. else if (Date.now !== undefined) { TWEEN.now = Date.now; } // Otherwise, use 'new Date().getTime()'. else { TWEEN.now = function () { return new Date().getTime(); }; } TWEEN.Tween = function (object, group) { this._object = object; this._valuesStart = {}; this._valuesEnd = {}; this._valuesStartRepeat = {}; this._duration = 1000; this._repeat = 0; this._repeatDelayTime = undefined; this._yoyo = false; this._isPlaying = false; this._reversed = false; this._delayTime = 0; this._startTime = null; this._easingFunction = TWEEN.Easing.Linear.None; this._interpolationFunction = TWEEN.Interpolation.Linear; this._chainedTweens = []; this._onStartCallback = null; this._onStartCallbackFired = false; this._onUpdateCallback = null; this._onRepeatCallback = null; this._onCompleteCallback = null; this._onStopCallback = null; this._group = group || TWEEN; this._id = TWEEN.nextId(); }; TWEEN.Tween.prototype = { getId: function () { return this._id; }, isPlaying: function () { return this._isPlaying; }, to: function (properties, duration) { this._valuesEnd = Object.create(properties); if (duration !== undefined) { this._duration = duration; } return this; }, duration: function duration(d) { this._duration = d; return this; }, start: function (time) { this._group.add(this); this._isPlaying = true; this._onStartCallbackFired = false; this._startTime = time !== undefined ? typeof time === 'string' ? TWEEN.now() + parseFloat(time) : time : TWEEN.now(); this._startTime += this._delayTime; for (var property in this._valuesEnd) { // Check if an Array was provided as property value if (this._valuesEnd[property] instanceof Array) { if (this._valuesEnd[property].length === 0) { continue; } // Create a local copy of the Array with the start value at the front this._valuesEnd[property] = [this._object[property]].concat(this._valuesEnd[property]); } // If `to()` specifies a property that doesn't exist in the source object, // we should not set that property in the object if (this._object[property] === undefined) { continue; } // Save the starting value. this._valuesStart[property] = this._object[property]; if ((this._valuesStart[property] instanceof Array) === false) { this._valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings } this._valuesStartRepeat[property] = this._valuesStart[property] || 0; } return this; }, stop: function () { if (!this._isPlaying) { return this; } this._group.remove(this); this._isPlaying = false; if (this._onStopCallback !== null) { this._onStopCallback(this._object); } this.stopChainedTweens(); return this; }, end: function () { this.update(Infinity); return this; }, stopChainedTweens: function () { for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { this._chainedTweens[i].stop(); } }, group: function (group) { this._group = group; return this; }, delay: function (amount) { this._delayTime = amount; return this; }, repeat: function (times) { this._repeat = times; return this; }, repeatDelay: function (amount) { this._repeatDelayTime = amount; return this; }, yoyo: function (yoyo) { this._yoyo = yoyo; return this; }, easing: function (easingFunction) { this._easingFunction = easingFunction; return this; }, interpolation: function (interpolationFunction) { this._interpolationFunction = interpolationFunction; return this; }, chain: function () { this._chainedTweens = arguments; return this; }, onStart: function (callback) { this._onStartCallback = callback; return this; }, onUpdate: function (callback) { this._onUpdateCallback = callback; return this; }, onRepeat: function onRepeat(callback) { this._onRepeatCallback = callback; return this; }, onComplete: function (callback) { this._onCompleteCallback = callback; return this; }, onStop: function (callback) { this._onStopCallback = callback; return this; }, update: function (time) { var property; var elapsed; var value; if (time < this._startTime) { return true; } if (this._onStartCallbackFired === false) { if (this._onStartCallback !== null) { this._onStartCallback(this._object); } this._onStartCallbackFired = true; } elapsed = (time - this._startTime) / this._duration; elapsed = (this._duration === 0 || elapsed > 1) ? 1 : elapsed; value = this._easingFunction(elapsed); for (property in this._valuesEnd) { // Don't update properties that do not exist in the source object if (this._valuesStart[property] === undefined) { continue; } var start = this._valuesStart[property] || 0; var end = this._valuesEnd[property]; if (end instanceof Array) { this._object[property] = this._interpolationFunction(end, value); } else { // Parses relative end values with start as base (e.g.: +10, -3) if (typeof (end) === 'string') { if (end.charAt(0) === '+' || end.charAt(0) === '-') { end = start + parseFloat(end); } else { end = parseFloat(end); } } // Protect against non numeric properties. if (typeof (end) === 'number') { this._object[property] = start + (end - start) * value; } } } if (this._onUpdateCallback !== null) { this._onUpdateCallback(this._object, elapsed); } if (elapsed === 1) { if (this._repeat > 0) { if (isFinite(this._repeat)) { this._repeat--; } // Reassign starting values, restart by making startTime = now for (property in this._valuesStartRepeat) { if (typeof (this._valuesEnd[property]) === 'string') { this._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]); } if (this._yoyo) { var tmp = this._valuesStartRepeat[property]; this._valuesStartRepeat[property] = this._valuesEnd[property]; this._valuesEnd[property] = tmp; } this._valuesStart[property] = this._valuesStartRepeat[property]; } if (this._yoyo) { this._reversed = !this._reversed; } if (this._repeatDelayTime !== undefined) { this._startTime = time + this._repeatDelayTime; } else { this._startTime = time + this._delayTime; } if (this._onRepeatCallback !== null) { this._onRepeatCallback(this._object); } return true; } else { if (this._onCompleteCallback !== null) { this._onCompleteCallback(this._object); } for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { // Make the chained tweens start exactly at the time they should, // even if the `update()` method was called way past the duration of the tween this._chainedTweens[i].start(this._startTime + this._duration); } return false; } } return true; } }; TWEEN.Easing = { Linear: { None: function (k) { return k; } }, Quadratic: { In: function (k) { return k * k; }, Out: function (k) { return k * (2 - k); }, InOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k; } return - 0.5 * (--k * (k - 2) - 1); } }, Cubic: { In: function (k) { return k * k * k; }, Out: function (k) { return --k * k * k + 1; }, InOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k; } return 0.5 * ((k -= 2) * k * k + 2); } }, Quartic: { In: function (k) { return k * k * k * k; }, Out: function (k) { return 1 - (--k * k * k * k); }, InOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k; } return - 0.5 * ((k -= 2) * k * k * k - 2); } }, Quintic: { In: function (k) { return k * k * k * k * k; }, Out: function (k) { return --k * k * k * k * k + 1; }, InOut: function (k) { if ((k *= 2) < 1) { return 0.5 * k * k * k * k * k; } return 0.5 * ((k -= 2) * k * k * k * k + 2); } }, Sinusoidal: { In: function (k) { return 1 - Math.cos(k * Math.PI / 2); }, Out: function (k) { return Math.sin(k * Math.PI / 2); }, InOut: function (k) { return 0.5 * (1 - Math.cos(Math.PI * k)); } }, Exponential: { In: function (k) { return k === 0 ? 0 : Math.pow(1024, k - 1); }, Out: function (k) { return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k); }, InOut: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } if ((k *= 2) < 1) { return 0.5 * Math.pow(1024, k - 1); } return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2); } }, Circular: { In: function (k) { return 1 - Math.sqrt(1 - k * k); }, Out: function (k) { return Math.sqrt(1 - (--k * k)); }, InOut: function (k) { if ((k *= 2) < 1) { return - 0.5 * (Math.sqrt(1 - k * k) - 1); } return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); } }, Elastic: { In: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } return -Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI); }, Out: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } return Math.pow(2, -10 * k) * Math.sin((k - 0.1) * 5 * Math.PI) + 1; }, InOut: function (k) { if (k === 0) { return 0; } if (k === 1) { return 1; } k *= 2; if (k < 1) { return -0.5 * Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI); } return 0.5 * Math.pow(2, -10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI) + 1; } }, Back: { In: function (k) { var s = 1.70158; return k * k * ((s + 1) * k - s); }, Out: function (k) { var s = 1.70158; return --k * k * ((s + 1) * k + s) + 1; }, InOut: function (k) { var s = 1.70158 * 1.525; if ((k *= 2) < 1) { return 0.5 * (k * k * ((s + 1) * k - s)); } return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); } }, Bounce: { In: function (k) { return 1 - TWEEN.Easing.Bounce.Out(1 - k); }, Out: function (k) { if (k < (1 / 2.75)) { return 7.5625 * k * k; } else if (k < (2 / 2.75)) { return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; } else if (k < (2.5 / 2.75)) { return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } }, InOut: function (k) { if (k < 0.5) { return TWEEN.Easing.Bounce.In(k * 2) * 0.5; } return TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5; } } }; TWEEN.Interpolation = { Linear: function (v, k) { var m = v.length - 1; var f = m * k; var i = Math.floor(f); var fn = TWEEN.Interpolation.Utils.Linear; if (k < 0) { return fn(v[0], v[1], f); } if (k > 1) { return fn(v[m], v[m - 1], m - f); } return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); }, Bezier: function (v, k) { var b = 0; var n = v.length - 1; var pw = Math.pow; var bn = TWEEN.Interpolation.Utils.Bernstein; for (var i = 0; i <= n; i++) { b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); } return b; }, CatmullRom: function (v, k) { var m = v.length - 1; var f = m * k; var i = Math.floor(f); var fn = TWEEN.Interpolation.Utils.CatmullRom; if (v[0] === v[m]) { if (k < 0) { i = Math.floor(f = m * (1 + k)); } return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); } else { if (k < 0) { return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); } if (k > 1) { return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); } return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); } }, Utils: { Linear: function (p0, p1, t) { return (p1 - p0) * t + p0; }, Bernstein: function (n, i) { var fc = TWEEN.Interpolation.Utils.Factorial; return fc(n) / fc(i) / fc(n - i); }, Factorial: (function () { var a = [1]; return function (n) { var s = 1; if (a[n]) { return a[n]; } for (var i = n; i > 1; i--) { s *= i; } a[n] = s; return s; }; })(