UNPKG

threepipe

Version:

A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.

145 lines 7.06 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { Euler, EventDispatcher, MathUtils, Quaternion, Vector3 } from 'three'; import { now, serialize } from 'ts-browser-helpers'; import { uiButton, uiPanelContainer, uiSlider } from 'uiconfig.js'; // eslint-disable-next-line @typescript-eslint/naming-convention const _zee = new Vector3(0, 0, 1); // eslint-disable-next-line @typescript-eslint/naming-convention const _euler = new Euler(); // eslint-disable-next-line @typescript-eslint/naming-convention const _q0 = new Quaternion(); // eslint-disable-next-line @typescript-eslint/naming-convention const _q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis // eslint-disable-next-line @typescript-eslint/naming-convention const _q2 = new Quaternion(); // - PI/2 around the x-axis // eslint-disable-next-line @typescript-eslint/naming-convention const _changeEvent = { type: 'change' }; const EPS = 0.000001; let DeviceOrientationControls2 = class DeviceOrientationControls2 extends EventDispatcher { constructor(object) { super(); this.enabled = false; // do not serialize this as it signifies weather this is active. this.lastOrder = 'XYZ'; this.dampingFactor = 0.05; this.lastQuaternion = new Quaternion(); this.onDeviceOrientationChangeEvent = (event) => { this.deviceOrientation = event; }; this.onScreenOrientationChangeEvent = () => { this.screenOrientation = screen.orientation; }; this._initQuaternion = new Quaternion(); this._initQuaternionInvert = new Quaternion(); this._initQuaternionDest = new Quaternion(); this._lastTime = -1; if (window.isSecureContext === false) { console.error('DeviceOrientationControls2: DeviceOrientationEvent is only available in secure contexts (https)'); } this.object = object; this.lastOrder = this.object.rotation.order; this.object.rotation.reorder('YXZ'); // this.enabled = true this.connect(); } resetView() { this._initQuaternionDest.__init = false; } connect() { if (this.enabled) return; this.onScreenOrientationChangeEvent(); // run once on load // iOS 13+ if (window.DeviceOrientationEvent !== undefined && typeof window.DeviceOrientationEvent.requestPermission === 'function') { window.DeviceOrientationEvent.requestPermission().then((response) => { if (response == 'granted') { window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent); window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent); } }).catch((error) => { console.error('DeviceOrientationControls2: Unable to use DeviceOrientation API:', error); }); } else { window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent); window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent); } this.enabled = true; this._initQuaternion.copy(this.object.quaternion); this._initQuaternionInvert.copy(this.object.quaternion).invert(); } disconnect() { if (!this.enabled) return; window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent); window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent); this._initQuaternion.identity(); this._initQuaternionInvert.identity(); this._initQuaternionDest = new Quaternion(); // need to set a new instance here. this.object.rotation.reorder(this.lastOrder); this.lastOrder = 'XYZ'; this.enabled = false; } update() { if (!this.enabled) return; const device = this.deviceOrientation; if (device) { const alpha = device.alpha !== null ? MathUtils.degToRad(device.alpha) : 0; // Z const beta = device.beta !== null ? MathUtils.degToRad(device.beta) : 0; // X' const gamma = device.gamma !== null ? MathUtils.degToRad(device.gamma) : 0; // Y'' const orient = this.screenOrientation ? MathUtils.degToRad(this.screenOrientation.angle) : 0; // O this.setObjectQuaternion(alpha, beta, gamma, orient); if (8 * (1 - this.lastQuaternion.dot(this.object.quaternion)) > EPS) { this.lastQuaternion.copy(this.object.quaternion); this.dispatchEvent(_changeEvent); } } } dispose() { this.disconnect(); } // The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y'' setObjectQuaternion(alpha, beta, gamma, orient) { // if(_lastTime < 0) const time = now() / 1000; _euler.set(beta, alpha, -gamma, 'YXZ'); // 'ZXY' for the device, but 'YXZ' for us _q2.setFromEuler(_euler); // orient the device _q2.multiply(_q1); // camera looks out the back of the device, not the top _q2.multiply(_q0.setFromAxisAngle(_zee, -orient)); // adjust for screen orientation // debugger if (!this._initQuaternionDest.__init) { this._initQuaternionDest.copy(_q2).invert(); this._initQuaternionDest.__init = true; } _q2.premultiply(this._initQuaternionDest); const mTime = 1 / 60; this.object.quaternion.multiply(this._initQuaternionInvert); this.object.quaternion.slerp(_q2, this.dampingFactor / (Math.min(1, time - this._lastTime) / mTime)); this.object.quaternion.multiply(this._initQuaternion); // console.log(time - this._lastTime, mTime) this._lastTime = time; } }; __decorate([ serialize(), uiSlider('Damping', [0, 1], 0.01) ], DeviceOrientationControls2.prototype, "dampingFactor", void 0); __decorate([ uiButton('Reset View') ], DeviceOrientationControls2.prototype, "resetView", null); __decorate([ uiButton() ], DeviceOrientationControls2.prototype, "connect", null); __decorate([ uiButton() ], DeviceOrientationControls2.prototype, "disconnect", null); DeviceOrientationControls2 = __decorate([ uiPanelContainer('Device Orientation Controls') ], DeviceOrientationControls2); export { DeviceOrientationControls2 }; //# sourceMappingURL=DeviceOrientationControls2.js.map