UNPKG

three-stdlib

Version:

stand-alone library of threejs examples

503 lines (502 loc) 21.4 kB
"use strict"; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const EventDispatcher = require("./EventDispatcher.cjs"); class TrackballControls extends EventDispatcher.EventDispatcher { constructor(object, domElement) { super(); __publicField(this, "enabled", true); __publicField(this, "screen", { left: 0, top: 0, width: 0, height: 0 }); __publicField(this, "rotateSpeed", 1); __publicField(this, "zoomSpeed", 1.2); __publicField(this, "panSpeed", 0.3); __publicField(this, "noRotate", false); __publicField(this, "noZoom", false); __publicField(this, "noPan", false); __publicField(this, "staticMoving", false); __publicField(this, "dynamicDampingFactor", 0.2); __publicField(this, "minDistance", 0); __publicField(this, "maxDistance", Infinity); __publicField(this, "keys", [ "KeyA", "KeyS", "KeyD" /*D*/ ]); __publicField(this, "mouseButtons", { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN }); __publicField(this, "object"); __publicField(this, "domElement"); __publicField(this, "cursorZoom", false); __publicField(this, "target", new THREE.Vector3()); __publicField(this, "mousePosition", new THREE.Vector2()); // internals __publicField(this, "STATE", { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }); __publicField(this, "EPS", 1e-6); __publicField(this, "lastZoom", 1); __publicField(this, "lastPosition", new THREE.Vector3()); __publicField(this, "cursorVector", new THREE.Vector3()); __publicField(this, "targetVector", new THREE.Vector3()); __publicField(this, "_state", this.STATE.NONE); __publicField(this, "_keyState", this.STATE.NONE); __publicField(this, "_eye", new THREE.Vector3()); __publicField(this, "_movePrev", new THREE.Vector2()); __publicField(this, "_moveCurr", new THREE.Vector2()); __publicField(this, "_lastAxis", new THREE.Vector3()); __publicField(this, "_lastAngle", 0); __publicField(this, "_zoomStart", new THREE.Vector2()); __publicField(this, "_zoomEnd", new THREE.Vector2()); __publicField(this, "_touchZoomDistanceStart", 0); __publicField(this, "_touchZoomDistanceEnd", 0); __publicField(this, "_panStart", new THREE.Vector2()); __publicField(this, "_panEnd", new THREE.Vector2()); __publicField(this, "target0"); __publicField(this, "position0"); __publicField(this, "up0"); __publicField(this, "zoom0"); // events __publicField(this, "changeEvent", { type: "change" }); __publicField(this, "startEvent", { type: "start" }); __publicField(this, "endEvent", { type: "end" }); __publicField(this, "onScreenVector", new THREE.Vector2()); __publicField(this, "getMouseOnScreen", (pageX, pageY) => { this.onScreenVector.set( (pageX - this.screen.left) / this.screen.width, (pageY - this.screen.top) / this.screen.height ); return this.onScreenVector; }); __publicField(this, "onCircleVector", new THREE.Vector2()); __publicField(this, "getMouseOnCircle", (pageX, pageY) => { this.onCircleVector.set( (pageX - this.screen.width * 0.5 - this.screen.left) / (this.screen.width * 0.5), (this.screen.height + 2 * (this.screen.top - pageY)) / this.screen.width // screen.width intentional ); return this.onCircleVector; }); __publicField(this, "axis", new THREE.Vector3()); __publicField(this, "quaternion", new THREE.Quaternion()); __publicField(this, "eyeDirection", new THREE.Vector3()); __publicField(this, "objectUpDirection", new THREE.Vector3()); __publicField(this, "objectSidewaysDirection", new THREE.Vector3()); __publicField(this, "moveDirection", new THREE.Vector3()); __publicField(this, "angle", 0); __publicField(this, "rotateCamera", () => { this.moveDirection.set(this._moveCurr.x - this._movePrev.x, this._moveCurr.y - this._movePrev.y, 0); this.angle = this.moveDirection.length(); if (this.angle) { this._eye.copy(this.object.position).sub(this.target); this.eyeDirection.copy(this._eye).normalize(); this.objectUpDirection.copy(this.object.up).normalize(); this.objectSidewaysDirection.crossVectors(this.objectUpDirection, this.eyeDirection).normalize(); this.objectUpDirection.setLength(this._moveCurr.y - this._movePrev.y); this.objectSidewaysDirection.setLength(this._moveCurr.x - this._movePrev.x); this.moveDirection.copy(this.objectUpDirection.add(this.objectSidewaysDirection)); this.axis.crossVectors(this.moveDirection, this._eye).normalize(); this.angle *= this.rotateSpeed; this.quaternion.setFromAxisAngle(this.axis, this.angle); this._eye.applyQuaternion(this.quaternion); this.object.up.applyQuaternion(this.quaternion); this._lastAxis.copy(this.axis); this._lastAngle = this.angle; } else if (!this.staticMoving && this._lastAngle) { this._lastAngle *= Math.sqrt(1 - this.dynamicDampingFactor); this._eye.copy(this.object.position).sub(this.target); this.quaternion.setFromAxisAngle(this._lastAxis, this._lastAngle); this._eye.applyQuaternion(this.quaternion); this.object.up.applyQuaternion(this.quaternion); } this._movePrev.copy(this._moveCurr); }); __publicField(this, "zoomCamera", () => { let factor; if (this._state === this.STATE.TOUCH_ZOOM_PAN) { factor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd; this._touchZoomDistanceStart = this._touchZoomDistanceEnd; if (this.object.isPerspectiveCamera) { this._eye.multiplyScalar(factor); } else if (this.object.isOrthographicCamera) { this.object.zoom /= factor; this.object.updateProjectionMatrix(); } else { console.warn("THREE.TrackballControls: Unsupported camera type"); } } else { factor = 1 + (this._zoomEnd.y - this._zoomStart.y) * this.zoomSpeed; if (Math.abs(factor - 1) > this.EPS && factor > 0) { if (this.object.isPerspectiveCamera) { if (factor > 1 && this._eye.length() >= this.maxDistance - this.EPS) { factor = 1; } this._eye.multiplyScalar(factor); } else if (this.object.isOrthographicCamera) { if (factor > 1 && this.object.zoom < this.maxDistance * this.maxDistance) { factor = 1; } this.object.zoom /= factor; } else { console.warn("THREE.TrackballControls: Unsupported camera type"); } } if (this.staticMoving) { this._zoomStart.copy(this._zoomEnd); } else { this._zoomStart.y += (this._zoomEnd.y - this._zoomStart.y) * this.dynamicDampingFactor; } if (this.cursorZoom) { this.targetVector.copy(this.target).project(this.object); let worldPos = this.cursorVector.set(this.mousePosition.x, this.mousePosition.y, this.targetVector.z).unproject(this.object); this.target.lerpVectors(worldPos, this.target, factor); } if (this.object.isOrthographicCamera) { this.object.updateProjectionMatrix(); } } }); __publicField(this, "mouseChange", new THREE.Vector2()); __publicField(this, "objectUp", new THREE.Vector3()); __publicField(this, "pan", new THREE.Vector3()); __publicField(this, "panCamera", () => { if (!this.domElement) return; this.mouseChange.copy(this._panEnd).sub(this._panStart); if (this.mouseChange.lengthSq() > this.EPS) { if (this.object.isOrthographicCamera) { const orthoObject = this.object; const scale_x = (orthoObject.right - orthoObject.left) / this.object.zoom; const scale_y = (orthoObject.top - orthoObject.bottom) / this.object.zoom; this.mouseChange.x *= scale_x; this.mouseChange.y *= scale_y; } else { this.mouseChange.multiplyScalar(this._eye.length() * this.panSpeed); } this.pan.copy(this._eye).cross(this.object.up).setLength(this.mouseChange.x); this.pan.add(this.objectUp.copy(this.object.up).setLength(this.mouseChange.y)); this.object.position.add(this.pan); this.target.add(this.pan); if (this.staticMoving) { this._panStart.copy(this._panEnd); } else { this._panStart.add( this.mouseChange.subVectors(this._panEnd, this._panStart).multiplyScalar(this.dynamicDampingFactor) ); } } }); __publicField(this, "checkDistances", () => { if (!this.noZoom || !this.noPan) { if (this._eye.lengthSq() > this.maxDistance * this.maxDistance) { this.object.position.addVectors(this.target, this._eye.setLength(this.maxDistance)); this._zoomStart.copy(this._zoomEnd); } if (this._eye.lengthSq() < this.minDistance * this.minDistance) { this.object.position.addVectors(this.target, this._eye.setLength(this.minDistance)); this._zoomStart.copy(this._zoomEnd); } } }); __publicField(this, "handleResize", () => { if (!this.domElement) return; const box = this.domElement.getBoundingClientRect(); const d = this.domElement.ownerDocument.documentElement; this.screen.left = box.left + window.pageXOffset - d.clientLeft; this.screen.top = box.top + window.pageYOffset - d.clientTop; this.screen.width = box.width; this.screen.height = box.height; }); __publicField(this, "update", () => { this._eye.subVectors(this.object.position, this.target); if (!this.noRotate) { this.rotateCamera(); } if (!this.noZoom) { this.zoomCamera(); } if (!this.noPan) { this.panCamera(); } this.object.position.addVectors(this.target, this._eye); if (this.object.isPerspectiveCamera) { this.checkDistances(); this.object.lookAt(this.target); if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS) { this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); } } else if (this.object.isOrthographicCamera) { this.object.lookAt(this.target); if (this.lastPosition.distanceToSquared(this.object.position) > this.EPS || this.lastZoom !== this.object.zoom) { this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); this.lastZoom = this.object.zoom; } } else { console.warn("THREE.TrackballControls: Unsupported camera type"); } }); __publicField(this, "reset", () => { this._state = this.STATE.NONE; this._keyState = this.STATE.NONE; this.target.copy(this.target0); this.object.position.copy(this.position0); this.object.up.copy(this.up0); this.object.zoom = this.zoom0; this.object.updateProjectionMatrix(); this._eye.subVectors(this.object.position, this.target); this.object.lookAt(this.target); this.dispatchEvent(this.changeEvent); this.lastPosition.copy(this.object.position); this.lastZoom = this.object.zoom; }); __publicField(this, "keydown", (event) => { if (this.enabled === false) return; window.removeEventListener("keydown", this.keydown); if (this._keyState !== this.STATE.NONE) { return; } else if (event.code === this.keys[this.STATE.ROTATE] && !this.noRotate) { this._keyState = this.STATE.ROTATE; } else if (event.code === this.keys[this.STATE.ZOOM] && !this.noZoom) { this._keyState = this.STATE.ZOOM; } else if (event.code === this.keys[this.STATE.PAN] && !this.noPan) { this._keyState = this.STATE.PAN; } }); __publicField(this, "onPointerDown", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseDown(event); break; } }); __publicField(this, "onPointerMove", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseMove(event); break; } }); __publicField(this, "onPointerUp", (event) => { if (this.enabled === false) return; switch (event.pointerType) { case "mouse": case "pen": this.onMouseUp(); break; } }); __publicField(this, "keyup", () => { if (this.enabled === false) return; this._keyState = this.STATE.NONE; window.addEventListener("keydown", this.keydown); }); __publicField(this, "onMouseDown", (event) => { if (!this.domElement) return; if (this._state === this.STATE.NONE) { switch (event.button) { case this.mouseButtons.LEFT: this._state = this.STATE.ROTATE; break; case this.mouseButtons.MIDDLE: this._state = this.STATE.ZOOM; break; case this.mouseButtons.RIGHT: this._state = this.STATE.PAN; break; } } const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state; if (state === this.STATE.ROTATE && !this.noRotate) { this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY)); this._movePrev.copy(this._moveCurr); } else if (state === this.STATE.ZOOM && !this.noZoom) { this._zoomStart.copy(this.getMouseOnScreen(event.pageX, event.pageY)); this._zoomEnd.copy(this._zoomStart); } else if (state === this.STATE.PAN && !this.noPan) { this._panStart.copy(this.getMouseOnScreen(event.pageX, event.pageY)); this._panEnd.copy(this._panStart); } this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp); this.dispatchEvent(this.startEvent); }); __publicField(this, "onMouseMove", (event) => { if (this.enabled === false) return; const state = this._keyState !== this.STATE.NONE ? this._keyState : this._state; if (state === this.STATE.ROTATE && !this.noRotate) { this._movePrev.copy(this._moveCurr); this._moveCurr.copy(this.getMouseOnCircle(event.pageX, event.pageY)); } else if (state === this.STATE.ZOOM && !this.noZoom) { this._zoomEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY)); } else if (state === this.STATE.PAN && !this.noPan) { this._panEnd.copy(this.getMouseOnScreen(event.pageX, event.pageY)); } }); __publicField(this, "onMouseUp", () => { if (!this.domElement) return; if (this.enabled === false) return; this._state = this.STATE.NONE; this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp); this.dispatchEvent(this.endEvent); }); __publicField(this, "mousewheel", (event) => { if (this.enabled === false) return; if (this.noZoom === true) return; event.preventDefault(); switch (event.deltaMode) { case 2: this._zoomStart.y -= event.deltaY * 0.025; break; case 1: this._zoomStart.y -= event.deltaY * 0.01; break; default: this._zoomStart.y -= event.deltaY * 25e-5; break; } this.mousePosition.x = event.offsetX / this.screen.width * 2 - 1; this.mousePosition.y = -(event.offsetY / this.screen.height) * 2 + 1; this.dispatchEvent(this.startEvent); this.dispatchEvent(this.endEvent); }); __publicField(this, "touchstart", (event) => { if (this.enabled === false) return; event.preventDefault(); switch (event.touches.length) { case 1: this._state = this.STATE.TOUCH_ROTATE; this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); this._movePrev.copy(this._moveCurr); break; default: this._state = this.STATE.TOUCH_ZOOM_PAN; const dx = event.touches[0].pageX - event.touches[1].pageX; const dy = event.touches[0].pageY - event.touches[1].pageY; this._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy); const x = (event.touches[0].pageX + event.touches[1].pageX) / 2; const y = (event.touches[0].pageY + event.touches[1].pageY) / 2; this._panStart.copy(this.getMouseOnScreen(x, y)); this._panEnd.copy(this._panStart); break; } this.dispatchEvent(this.startEvent); }); __publicField(this, "touchmove", (event) => { if (this.enabled === false) return; event.preventDefault(); switch (event.touches.length) { case 1: this._movePrev.copy(this._moveCurr); this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); break; default: const dx = event.touches[0].pageX - event.touches[1].pageX; const dy = event.touches[0].pageY - event.touches[1].pageY; this._touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy); const x = (event.touches[0].pageX + event.touches[1].pageX) / 2; const y = (event.touches[0].pageY + event.touches[1].pageY) / 2; this._panEnd.copy(this.getMouseOnScreen(x, y)); break; } }); __publicField(this, "touchend", (event) => { if (this.enabled === false) return; switch (event.touches.length) { case 0: this._state = this.STATE.NONE; break; case 1: this._state = this.STATE.TOUCH_ROTATE; this._moveCurr.copy(this.getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); this._movePrev.copy(this._moveCurr); break; } this.dispatchEvent(this.endEvent); }); __publicField(this, "contextmenu", (event) => { if (this.enabled === false) return; event.preventDefault(); }); // https://github.com/mrdoob/three.js/issues/20575 __publicField(this, "connect", (domElement) => { if (domElement === document) { console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); } this.domElement = domElement; this.domElement.addEventListener("contextmenu", this.contextmenu); this.domElement.addEventListener("pointerdown", this.onPointerDown); this.domElement.addEventListener("wheel", this.mousewheel); this.domElement.addEventListener("touchstart", this.touchstart); this.domElement.addEventListener("touchend", this.touchend); this.domElement.addEventListener("touchmove", this.touchmove); this.domElement.ownerDocument.addEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.addEventListener("pointerup", this.onPointerUp); window.addEventListener("keydown", this.keydown); window.addEventListener("keyup", this.keyup); this.handleResize(); }); __publicField(this, "dispose", () => { if (!this.domElement) return; this.domElement.removeEventListener("contextmenu", this.contextmenu); this.domElement.removeEventListener("pointerdown", this.onPointerDown); this.domElement.removeEventListener("wheel", this.mousewheel); this.domElement.removeEventListener("touchstart", this.touchstart); this.domElement.removeEventListener("touchend", this.touchend); this.domElement.removeEventListener("touchmove", this.touchmove); this.domElement.ownerDocument.removeEventListener("pointermove", this.onPointerMove); this.domElement.ownerDocument.removeEventListener("pointerup", this.onPointerUp); window.removeEventListener("keydown", this.keydown); window.removeEventListener("keyup", this.keyup); }); this.object = object; this.target0 = this.target.clone(); this.position0 = this.object.position.clone(); this.up0 = this.object.up.clone(); this.zoom0 = this.object.zoom; if (domElement !== void 0) this.connect(domElement); this.update(); } } exports.TrackballControls = TrackballControls; //# sourceMappingURL=TrackballControls.cjs.map