ControlsManager

This commit is contained in:
tengge1 2020-01-09 22:08:33 +08:00
parent 1ae0b7c7c2
commit f902e79cfd
4 changed files with 57 additions and 310 deletions

View File

@ -36,7 +36,7 @@ class BaseControls extends THREE.EventDispatcher {
* @param {THREE.Object3D} target 目标
*/
focus(target) {
scope.dispatchEvent(changeEvent);
}
/**

View File

@ -1,7 +1,52 @@
import BaseControls from './BaseControls';
class ControlsManager extends BaseControls {
import EditorControls from './EditorControls';
import FreeControls from './FreeControls';
const Controls = {
EditorControls,
FreeControls
};
/**
* 控制器管理器
*/
class ControlsManager extends BaseControls {
constructor(camera, domElement) {
super(camera, domElement);
this.current = new EditorControls();
}
/**
* 改变控制器模式
* @param {String} modeName 模式
*/
changeMode(modeName) {
if (!Controls[modeName]) {
console.warn(`ControlsManager: ${modeName} is not defined.`);
return;
}
this.current.disable();
this.current = Controls[modeName];
this.current.enable();
}
enable() {
this.current && this.current.enabled();
}
disable() {
this.current && this.current.disable();
}
focus(target) {
this.current && this.current.focus(target);
}
dispose() {
this.current && this.current.disable();
}
}
export default ControlsManager;

View File

@ -1,3 +1,5 @@
import BaseControls from './BaseControls';
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
@ -312,7 +314,7 @@ function EditorControls(object, domElement) {
}
EditorControls.prototype = Object.create(THREE.EventDispatcher.prototype);
EditorControls.prototype.constructor = EditorControls;
EditorControls.prototype = Object.create(BaseControls.prototype);
EditorControls.prototype.constructor = BaseControls;
export default EditorControls;

View File

@ -1,310 +1,10 @@
function FreeControls(object, domElement) {
import BaseControls from './BaseControls';
domElement = domElement !== undefined ? domElement : document;
// API
this.enabled = true;
this.center = new THREE.Vector3();
this.panSpeed = 0.002;
this.zoomSpeed = 0.1;
this.rotationSpeed = 0.005;
// internals
var scope = this;
var vector = new THREE.Vector3();
var delta = new THREE.Vector3();
var box = new THREE.Box3();
var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2 };
var state = STATE.NONE;
var center = this.center;
var normalMatrix = new THREE.Matrix3();
var pointer = new THREE.Vector2();
var pointerOld = new THREE.Vector2();
var spherical = new THREE.Spherical();
var sphere = new THREE.Sphere();
// events
var changeEvent = { type: 'change' };
this.focus = function (target) {
var distance;
box.setFromObject(target);
if (box.isEmpty() === false) {
box.getCenter(center);
distance = box.getBoundingSphere(sphere).radius;
} else {
// Focusing on an Group, AmbientLight, etc
center.setFromMatrixPosition(target.matrixWorld);
distance = 0.1;
}
delta.set(0, 0, 1);
delta.applyQuaternion(object.quaternion);
delta.multiplyScalar(distance * 4);
object.position.copy(center).add(delta);
scope.dispatchEvent(changeEvent);
};
this.pan = function (delta) {
var distance = object.position.distanceTo(center);
delta.multiplyScalar(distance * scope.panSpeed);
delta.applyMatrix3(normalMatrix.getNormalMatrix(object.matrix));
object.position.add(delta);
center.add(delta);
scope.dispatchEvent(changeEvent);
};
this.zoom = function (delta) {
var distance = object.position.distanceTo(center);
delta.multiplyScalar(distance * scope.zoomSpeed);
if (delta.length() > distance) return;
delta.applyMatrix3(normalMatrix.getNormalMatrix(object.matrix));
object.position.add(delta);
scope.dispatchEvent(changeEvent);
};
this.rotate = function (delta) {
vector.copy(object.position).sub(center);
spherical.setFromVector3(vector);
spherical.theta += delta.x * scope.rotationSpeed;
spherical.phi += delta.y * scope.rotationSpeed;
spherical.makeSafe();
vector.setFromSpherical(spherical);
object.position.copy(center).add(vector);
object.lookAt(center);
scope.dispatchEvent(changeEvent);
};
// mouse
function onMouseDown(event) {
if (scope.enabled === false) return;
if (event.button === 0) {
state = STATE.ROTATE;
} else if (event.button === 1) {
state = STATE.ZOOM;
} else if (event.button === 2) {
state = STATE.PAN;
}
pointerOld.set(event.clientX, event.clientY);
domElement.addEventListener('mousemove', onMouseMove, false);
domElement.addEventListener('mouseup', onMouseUp, false);
domElement.addEventListener('mouseout', onMouseUp, false);
domElement.addEventListener('dblclick', onMouseUp, false);
}
function onMouseMove(event) {
if (scope.enabled === false) return;
pointer.set(event.clientX, event.clientY);
var movementX = pointer.x - pointerOld.x;
var movementY = pointer.y - pointerOld.y;
if (state === STATE.ROTATE) {
scope.rotate(delta.set(- movementX, - movementY, 0));
} else if (state === STATE.ZOOM) {
scope.zoom(delta.set(0, 0, movementY));
} else if (state === STATE.PAN) {
scope.pan(delta.set(- movementX, movementY, 0));
}
pointerOld.set(event.clientX, event.clientY);
}
function onMouseUp(event) {
domElement.removeEventListener('mousemove', onMouseMove, false);
domElement.removeEventListener('mouseup', onMouseUp, false);
domElement.removeEventListener('mouseout', onMouseUp, false);
domElement.removeEventListener('dblclick', onMouseUp, false);
state = STATE.NONE;
}
function onMouseWheel(event) {
event.preventDefault();
// Normalize deltaY due to https://bugzilla.mozilla.org/show_bug.cgi?id=1392460
scope.zoom(delta.set(0, 0, event.deltaY > 0 ? 1 : - 1));
}
function contextmenu(event) {
event.preventDefault();
}
this.dispose = function () {
domElement.removeEventListener('contextmenu', contextmenu, false);
domElement.removeEventListener('mousedown', onMouseDown, false);
domElement.removeEventListener('wheel', onMouseWheel, false);
domElement.removeEventListener('mousemove', onMouseMove, false);
domElement.removeEventListener('mouseup', onMouseUp, false);
domElement.removeEventListener('mouseout', onMouseUp, false);
domElement.removeEventListener('dblclick', onMouseUp, false);
domElement.removeEventListener('touchstart', touchStart, false);
domElement.removeEventListener('touchmove', touchMove, false);
};
domElement.addEventListener('contextmenu', contextmenu, false);
domElement.addEventListener('mousedown', onMouseDown, false);
domElement.addEventListener('wheel', onMouseWheel, false);
// touch
var touches = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
var prevTouches = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
var prevDistance = null;
function touchStart(event) {
if (scope.enabled === false) return;
switch (event.touches.length) {
case 1:
touches[0].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
touches[1].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
break;
case 2:
touches[0].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
touches[1].set(event.touches[1].pageX, event.touches[1].pageY, 0).divideScalar(window.devicePixelRatio);
prevDistance = touches[0].distanceTo(touches[1]);
break;
}
prevTouches[0].copy(touches[0]);
prevTouches[1].copy(touches[1]);
}
function touchMove(event) {
if (scope.enabled === false) return;
event.preventDefault();
event.stopPropagation();
function getClosest(touch, touches) {
var closest = touches[0];
for (var i in touches) {
if (closest.distanceTo(touch) > touches[i].distanceTo(touch)) closest = touches[i];
}
return closest;
}
switch (event.touches.length) {
case 1:
touches[0].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
touches[1].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
scope.rotate(touches[0].sub(getClosest(touches[0], prevTouches)).multiplyScalar(- 1));
break;
case 2:
touches[0].set(event.touches[0].pageX, event.touches[0].pageY, 0).divideScalar(window.devicePixelRatio);
touches[1].set(event.touches[1].pageX, event.touches[1].pageY, 0).divideScalar(window.devicePixelRatio);
var distance = touches[0].distanceTo(touches[1]);
scope.zoom(delta.set(0, 0, prevDistance - distance));
prevDistance = distance;
var offset0 = touches[0].clone().sub(getClosest(touches[0], prevTouches));
var offset1 = touches[1].clone().sub(getClosest(touches[1], prevTouches));
offset0.x = - offset0.x;
offset1.x = - offset1.x;
scope.pan(offset0.add(offset1));
break;
}
prevTouches[0].copy(touches[0]);
prevTouches[1].copy(touches[1]);
}
domElement.addEventListener('touchstart', touchStart, false);
domElement.addEventListener('touchmove', touchMove, false);
/**
* 自由控制器
*/
class FreeControls extends BaseControls {
}
EditorControls.prototype = Object.create(THREE.EventDispatcher.prototype);
EditorControls.prototype.constructor = EditorControls;
export default EditorControls;
export default FreeControls;