awv3
Version:
⚡ AWV3 embedded CAD
759 lines (657 loc) • 29.2 kB
JavaScript
import * as THREE from 'three';
import * as Error from '../core/error';
import * as Helpers from '../core/helpers';
import { lastCreated } from '../core/canvas';
import { exponential, elastic } from '../animation/easing';
export default class Orbit {
constructor(view = Error.log('View undefined'), options = {}) {
this.view = view;
this.canvas = view.canvas;
this.dom = view.dom;
this.camera = options.camera;
let camera = (this.camera || this.view.camera);
this.easing = exponential.out;
this.duration = 1000;
this._zoomed = false;
this._autoZoom = { start: 0, end: 0, time: 0, length: 0, ease: this.easing, duration: this.duration };
this._autoFocus = {
start: new THREE.Vector3(),
end: new THREE.Vector3(),
time: 0,
ease: this.easing,
duration: this.duration
};
this._autoTheta = { start: 0, end: 0, time: 0, ease: this.easing, duration: this.duration };
this._autoPhi = { start: 0, end: 0, time: 0, ease: this.easing, duration: this.duration };
this._autoFov = { start: 0, end: 0, time: 0, ease: this.easing, duration: this.duration };
// ...
this.enabled = options.enabled || true;
this.zoomTarget = options.zoomTarget || new THREE.Vector3();
this.dynamicDampingFactor = options.dynamicDampingFactor || 0.55;
this.dynamicDampingFactorAuto = options.dynamicDampingFactorAuto || 0.2;
this.noZoom = options.noZoom || false;
this.zoomSpeed = options.zoomSpeed || 5;
this.zoomMode = options.zoomMode || Orbit.ZoomMode.Center;
this.minDistance = options.minDistance || 0;
this.maxDistance = options.maxDistance || Infinity;
this.noRotate = options.noRotate || false;
this.rotateSpeed = options.rotateSpeed || 0.9;
this.noPan = options.noPan || false;
this.panMode = options.panMode || Orbit.PanMode.Both;
this.minPolarAngle = options.minPolarAngle || 0; // radians
this.maxPolarAngle = options.maxPolarAngle || Math.PI; // radians
this.interactionStopsAutomation = options.interactionStopsAutomation || true;
this.inMotion = false;
this.interaction = false;
this.automation = false;
this.target = new THREE.Vector3();
this.phi = 0;
this.theta = 0;
this.distance = 0;
this._rotateStart = new THREE.Vector2();
this._rotateEnd = new THREE.Vector2();
this._rotateDelta = new THREE.Vector2();
this._panStart = new THREE.Vector2();
this._panEnd = new THREE.Vector2();
this._panDelta = new THREE.Vector2();
this._panOffset = new THREE.Vector3();
this._wheelStart = new THREE.Vector2();
this._wheelEnd = new THREE.Vector2();
this._wheelDelta = new THREE.Vector2();
this._polarStart = new THREE.Vector2();
this._polarEnd = new THREE.Vector2();
this._mousePosition = new THREE.Vector2();
this._panning = new THREE.Vector3();
this._eye = new THREE.Vector3();
this._phiDelta = 0;
this._thetaDelta = 0;
this._scale = 1;
this._state = Orbit.State.none;
this._quat = new THREE.Quaternion().setFromUnitVectors(
options.up || camera.up,
new THREE.Vector3(0, 1, 0)
);
this._quatInverse = this._quat.clone().inverse();
this._touchZoomDistanceEnd;
this._touchZoomDistanceStart;
this._aDelta = new THREE.Vector2();
this._lastState = [];
this._idleCallbacks = [];
this._activeCallbacks = [];
}
clone() {
var result = new Orbit(this.view);
result.enabled = this.enabled;
result.inMotion = this.inMotion;
result.interaction = this.interaction;
result.automation = this.automation;
result.target = this.target.clone();
result.zoomTarget = this.zoomTarget.clone();
result.dynamicDampingFactor = this.dynamicDampingFactor;
result.dynamicDampingFactorAuto = this.dynamicDampingFactorAuto;
result.noZoom = this.noZoom;
result.zoomSpeed = this.zoomSpeed;
result.zoomMode = this.zoomMode;
result.minDistance = this.minDistance;
result.maxDistance = this.maxDistance;
result.noRotate = this.noRotate;
result.rotateSpeed = this.rotateSpeed;
result.noPan = this.noPan;
result.panMode = this.panMode;
result.minPolarAngle = this.minPolarAngle;
result.maxPolarAngle = this.maxPolarAngle;
result.phi = this.phi;
result.theta = this.theta;
result.distance = this.distance;
return result;
}
set up(value) {
let camera = (this.camera || this.view.camera);
camera.up.copy(value);
camera.updateProjectionMatrix();
this._quat = new THREE.Quaternion().setFromUnitVectors(camera.up, new THREE.Vector3(0, 1, 0));
this._quatInverse = this._quat.clone().inverse();
this.view.invalidate();
}
get up() {
let camera = (this.camera || this.view.camera);
return camera.up.clone();
}
easing(easing) {
this.easing = easing;
return this;
}
duration(duration) {
this.duration = duration;
return this;
}
zoom(options = { value: this.view.scene.getRadius() * 4, easing: this.easing, duration: this.duration }) {
let camera = (this.camera || this.view.camera);
if (typeof options === 'number') options = { value: options, easing: this.easing, duration: this.duration };
if (options instanceof THREE.Object3D)
options = { value: options.getRadius() * 4, easing: this.easing, duration: this.duration };
options.value = options.value || this.view.scene.getRadius() * 4;
options.duration = options.duration || this.duration;
options.easing = options.easing || this.easing;
this.automation = true;
this._wheelStart.y = 0;
this._wheelEnd.y = 0;
this._autoZoom.ease = options.easing;
this._autoZoom.duration = options.duration;
this._autoZoom.time = this.canvas.renderer.time;
this._autoZoom.length = this._eye.copy(camera.position).sub(this.target).length();
this._autoZoom.start = 1;
this._autoZoom.end = options.value / this._autoZoom.length;
return this;
}
focus(options = { value: this.view.scene.getCenter(), easing: this.easing, duration: this.duration }) {
if (options instanceof THREE.Vector3)
options = { value: options, easing: this.easing, duration: this.duration };
if (options instanceof THREE.Object3D)
options = { value: options.getCenter(), easing: this.easing, duration: this.duration };
this.automation = true;
this._autoFocus.ease = options.easing || this.easing;
this._autoFocus.duration = options.duration || this.duration;
this._autoFocus.time = this.canvas.renderer.time;
this._autoFocus.start.copy(this.target);
this._autoFocus.end.copy(options.value || this.view.scene.getCenter());
return this;
}
rotateTheta(options = { value: 0, easing: this.easing, duration: this.duration }) {
if (typeof options === 'number') options = { value: options, easing: this.easing, duration: this.duration };
let theta = options.value || 0;
let thetaNow = this.theta;
if (thetaNow < 0) thetaNow += 2 * Math.PI;
if (theta < 0) theta += 2 * Math.PI;
let thetaDist = Math.abs(theta - thetaNow);
if (2 * Math.PI - thetaDist < thetaDist) {
if (theta < thetaNow) {
theta += 2 * Math.PI;
} else {
thetaNow += 2 * Math.PI;
}
}
this.automation = true;
this._autoTheta.ease = options.easing || this.easing;
this._autoTheta.duration = options.duration || this.duration;
this._autoTheta.time = this.canvas.renderer.time;
this._autoTheta.start = thetaNow;
this._autoTheta.end = theta;
this._autoTheta.old = undefined;
return this;
}
rotatePhi(options = { value: 0, easing: this.easing, duration: this.duration }) {
if (typeof options === 'number') options = { value: options, easing: this.easing, duration: this.duration };
let phi = options.value || 0;
let phiNow = this.phi;
if (phiNow < 0) phiNow += 2 * Math.PI;
if (phi < 0) phi += 2 * Math.PI;
let phiDist = Math.abs(phi - phiNow);
if (2 * Math.PI - phiDist < phiDist) {
if (phi < phiNow) {
phi += 2 * Math.PI;
} else {
phiNow += 2 * Math.PI;
}
}
this.automation = true;
this._autoPhi.ease = options.easing || this.easing;
this._autoPhi.duration = options.duration || this.duration;
this._autoPhi.time = this.canvas.renderer.time;
this._autoPhi.start = phiNow;
this._autoPhi.end = phi;
this._autoPhi.old = undefined;
return this;
}
rotate(theta, phi) {
return this.rotateTheta(theta).rotatePhi(phi);
}
fov(options = { value: 0, easing: this.easing, duration: this.duration }) {
let camera = (this.camera || this.view.camera);
if (typeof options === 'number') options = { value: options, easing: this.easing, duration: this.duration };
options.angle = options.angle || 0;
this.automation = true;
this._autoFov.ease = options.easing || this.easing;
this._autoFov.duration = options.duration || this.duration;
this._autoFov.time = this.canvas.renderer.time;
this._autoFov.start = camera.fov;
this._autoFov.end = options.value || camera.fov;
return this;
}
_automate(time, override) {
let camera = (this.camera || this.view.camera);
let animates = false;
// Focus
if (!!this._autoFocus.time > 0) {
let elapsed = override ? 1 : Math.min(1.1, (time - this._autoFocus.time) / this._autoFocus.duration);
let value = this._autoFocus.start
.clone()
.add(
this._autoFocus.end.clone().sub(this._autoFocus.start).multiplyScalar(this._autoFocus.ease(elapsed))
);
this.target.copy(value);
if (elapsed >= 1) this._autoFocus.time = 0;
animates = true;
}
// Theta
if (!!this._autoTheta.time > 0) {
let elapsed = override ? 1 : Math.min(1.1, (time - this._autoTheta.time) / this._autoTheta.duration);
let value = this._autoTheta.start +
(this._autoTheta.end - this._autoTheta.start) * this._autoTheta.ease(elapsed);
animates = true;
if (!this._autoTheta.old) {
this._autoTheta.old = value;
this._thetaDelta = value - this._autoTheta.start;
} else {
let oldVal = this._autoTheta.old;
this._autoTheta.old = value;
this._thetaDelta = value - oldVal;
}
if (elapsed >= 1) this._autoTheta.time = 0;
}
// Phi
if (!!this._autoPhi.time > 0) {
let elapsed = override ? 1 : Math.min(1.05, (time - this._autoPhi.time) / this._autoPhi.duration);
let value = this._autoPhi.start + (this._autoPhi.end - this._autoPhi.start) * this._autoPhi.ease(elapsed);
animates = true;
if (!this._autoPhi.old) {
this._autoPhi.old = value;
this._phiDelta = value - this._autoPhi.start;
} else {
let oldVal = this._autoPhi.old;
this._autoPhi.old = value;
this._phiDelta = value - oldVal;
}
if (elapsed >= 1) this._autoPhi.time = 0;
}
// Zoom
if (!!this._autoZoom.time > 0) {
let elapsed = override ? 1 : Math.min(1.05, (time - this._autoZoom.time) / this._autoZoom.duration);
let value = this._autoZoom.start +
(this._autoZoom.end - this._autoZoom.start) * this._autoZoom.ease(elapsed);
this._scale = value;
if (elapsed >= 1) this._autoZoom.time = 0;
animates = true;
} else {
this._autoZoom.length = 0;
}
// Fov
if (!!this._autoFov.time > 0) {
let elapsed = override ? 1 : Math.min(1.05, (time - this._autoFov.time) / this._autoFov.duration);
let value = this._autoFov.start + (this._autoFov.end - this._autoFov.start) * this._autoFov.ease(elapsed);
camera.fov = value;
camera.updateProjectionMatrix();
if (elapsed >= 1) this._autoFov.time = 0;
animates = true;
}
return animates;
}
now() {
let time = this.canvas.renderer.time;
// Focus
if (!!this._autoFocus.time > 0) this._autoFocus.duration = 1;
// Theta
if (!!this._autoTheta.time > 0) this._autoTheta.duration = 1;
// Phi
if (!!this._autoPhi.time > 0) this._autoPhi.duration = 1;
// Zoom
if (!!this._autoZoom.time > 0) this._autoZoom.duration = 1;
// Fov
if (!!this._autoFov.time > 0) this._autoFov.duration = 1;
this.update(time + 1, true);
return this;
}
// pass in distance in world space to move left
panLeft(distance) {
let camera = (this.camera || this.view.camera);
if (this.panMode === Orbit.PanMode.Horizontal || this.panMode === Orbit.PanMode.Both) {
var te = camera.matrix.elements;
// get X column of matrix
this._panOffset.set(te[0], te[1], te[2]);
this._panOffset.multiplyScalar(-distance);
this._panning.add(this._panOffset);
}
}
// pass in distance in world space to move up
panUp(distance) {
let camera = (this.camera || this.view.camera);
if (this.panMode === Orbit.PanMode.Vertical || this.panMode === Orbit.PanMode.Both) {
var te = camera.matrix.elements;
// get Y column of matrix
this._panOffset.set(te[4], te[5], te[6]);
this._panOffset.multiplyScalar(distance);
this._panning.add(this._panOffset);
}
}
// pass in x,y of change desired in pixel space,
// right and down are positive
panPixels(deltaX, deltaY) {
let camera = (this.camera || this.view.camera);
var position = camera.position,
offset = position.clone().sub(this.target),
targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan(camera.fov / 2 * Math.PI / 180.0);
// we actually don't use screenWidth, since perspective camera is fixed to screen height
this.panLeft(deltaX * targetDistance / (this.view.height || 1) * 2);
this.panUp(deltaY * targetDistance / (this.view.height || 1) * 2);
}
_rotate() {
if (!this.noRotate) {
var delta = this._rotateEnd.clone().sub(this._rotateStart).multiplyScalar(this.dynamicDampingFactor);
if (delta.length() > 0.01) {
this._rotateStart.add(delta);
if (this.dynamicDampingFactor < 1.00) {
this._rotateDelta.subVectors(this._rotateEnd, this._rotateStart);
} else {
this._rotateDelta = delta;
}
// rotating across whole screen goes 360 degrees around
this._thetaDelta -= 2 * Math.PI * this._rotateDelta.x / (this.view.width || 1) * this.rotateSpeed;
// rotating up and down along whole screen attempts to go 360, but limited to 180
this._phiDelta -= 2 * Math.PI * this._rotateDelta.y / (this.view.height || 1) * this.rotateSpeed;
return true;
}
}
return false;
}
_zoom(point) {
let camera = (this.camera || this.view.camera);
if (!this.noZoom) {
// By mousewheel
var delta = this._wheelEnd.clone().sub(this._wheelStart).multiplyScalar(this.dynamicDampingFactor);
if (delta.length() > 0.00001) {
this._wheelStart.add(delta);
this._wheelDelta.subVectors(this._wheelEnd, this._wheelStart);
var factor = 1.0 + this._wheelDelta.y * this.zoomSpeed;
if (factor !== 1.0 && factor > 0.0) {
var distance = camera.zoom || camera.position.distanceTo(this.target);
if (factor > 1 && distance > this.maxDistance) return false;
if (!point) {
if (this.zoomMode === Orbit.ZoomMode.Target && !!this.zoomTarget)
point = this.zoomTarget.clone();
else if (this.zoomMode === Orbit.ZoomMode.Mouse) {
point = this._mousePosition.clone();
} else
point = new THREE.Vector2(0, 0); //ndc coords of screen center
}
// this._scale = factor;
//determine 3D position of mouse cursor (on target plane)
var ndcTarget = this.target.clone().project(camera);
var ndcPos = new THREE.Vector3(point.x, point.y, ndcTarget.z);
var worldPos = ndcPos.clone().unproject(camera);
//change eye-target distance
this.distance *= factor;
//adjust target point so that "point" stays in place
this.target.lerpVectors(worldPos, this.target, factor);
}
return true;
}
// By touch
if (this._state === Orbit.State.TouchZoomPan) {
var factor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd;
if (factor != 0 && !isNaN(factor)) {
this._touchZoomDistanceStart = this._touchZoomDistanceEnd;
this._scale = factor;
}
return true;
}
}
return false;
}
_pan() {
if (this.noPan === false) {
var delta = this._panEnd.clone().sub(this._panStart).multiplyScalar(this.dynamicDampingFactor);
if (delta.length() > 0.01) {
this._panStart.add(delta);
this._panDelta.subVectors(this._panEnd, this._panStart);
this.panPixels(this._panDelta.x, this._panDelta.y);
return true;
}
}
return false;
}
stop() {
this.automation = false;
this._autoZoom.time = 0;
this._autoZoom.length = 0;
this._autoFocus.time = 0;
this._autoTheta.time = 0;
this._autoPhi.time = 0;
this._autoFov.time = 0;
this._wheelStart.y = 0;
this._wheelEnd.y = 0;
//stgatilov: fix bug with zooming in the midst of dragging
//there is no point in setting panStart to zero here
/*this._panStart.set(0, 0);
this._panEnd.set(0, 0);*/
this.emptyIdleCallbacks();
return this;
}
store(controls) {
let camera = (this.camera || this.view.camera);
this._lastState = [
camera.fov,
this.target.clone(),
this.target.distanceTo(camera.position),
this.theta,
this.phi
];
if (!!controls)
controls.fov(lastState[0]).focus(lastState[1]).zoom(lastState[2]).rotate(lastState[3], lastState[4]).now();
return this;
}
back() {
if (this._lastState.length > 0) {
this.automation = true;
this.fov(lastState[0]).focus(lastState[1]).zoom(lastState[2]).rotate(lastState[3], lastState[4]);
}
return this;
}
polar(min, max) {
this.automation = true;
this._polarStart.set(this.minPolarAngle, this.maxPolarAngle);
this._polarEnd.set(min, max);
return this;
}
pan(x, y) {
this.automation = true;
this._panStart.set(0, 0);
this._panEnd.set(x, y);
return this;
}
waitIdle() {
return new Promise(resolve => this._idleCallbacks.push(() => resolve(this)));
}
wait() {
return this.waitIdle();
}
waitActive() {
return new Promise(resolve => this._activeCallbacks.push(() => resolve(this)));
}
emptyIdleCallbacks() {
if (this._idleCallbacks.length > 0)
for (var i = 0, l = this._idleCallbacks.length; i < l; i++)
this._idleCallbacks.shift()();
}
emptyActiveCallbacks() {
if (this._activeCallbacks.length > 0)
for (var i = 0, l = this._activeCallbacks.length; i < l; i++)
this._activeCallbacks.shift()();
}
update(time, override) {
if (this.enabled && !this.automation && !this.interaction) return;
let camera = (this.camera || this.view.camera);
let oldMotion = this.inMotion, position = camera.position;
if (!!override) {
this.view.invalidate();
}
this.inMotion = false;
this.distance = this._eye.copy(position).sub(this.target).length();
var focussed = this._automate(time, override),
rotated = this._rotate(),
zoomed = this._zoom(),
panned = this._pan();
if (rotated || zoomed || panned || focussed || override) {
this.inMotion = true;
// rotate eye to "y-axis-is-up" space
this._eye.applyQuaternion(this._quat);
// angle from z-axis around y-axis
this.theta = Math.atan2(this._eye.x, this._eye.z);
// angle from y-axis
this.phi = Math.atan2(Math.sqrt(this._eye.x * this._eye.x + this._eye.z * this._eye.z), this._eye.y);
this.theta += this._thetaDelta;
this.phi += this._phiDelta;
// restrict phi to be between desired limits
this.phi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.phi));
// restrict phi to be between EPS and PI-EPS
this.phi = Math.max(Orbit.Eps, Math.min(this.maxPolarAngle - Orbit.Eps, this.phi));
var radius = (!!this._autoZoom.length ? this._autoZoom.length : this.distance) * this._scale;
// restrict radius to be between desired limits
radius = Math.max(this.minDistance, Math.min(this.maxDistance, radius));
// move target to panned location
this.target.add(this._panning);
this._eye.x = radius * Math.sin(this.phi) * Math.sin(this.theta);
this._eye.y = radius * Math.cos(this.phi);
this._eye.z = radius * Math.sin(this.phi) * Math.cos(this.theta);
// rotate eye back to "camera-up-vector-is-up" space
this._eye.applyQuaternion(this._quatInverse);
camera.position.copy(this.target).add(this._eye);
camera.lookAt(this.target);
camera.target.copy(this.target);
this._thetaDelta = 0;
this._phiDelta = 0;
this._scale = 1;
this._panning.set(0, 0, 0);
if (oldMotion == false) {
this.emptyActiveCallbacks();
}
} else {
this.interaction = false;
this.automation = false;
this.emptyIdleCallbacks();
}
return this;
}
onMouseDown(event) {
if (this.enabled === false) return;
this.automation = this.interaction = true;
if (this.interactionStopsAutomation) this.stop();
// for convenience allow panning with MouseL if noRotate is active
if (event.button === 0 && this.noRotate || event.button === 2) {
if (this.noPan === true) return;
this._state = Orbit.State.Pan;
this._panStart.set(event.clientX, event.clientY);
this._panEnd.copy(this._panStart);
} else if (event.button === 0) {
if (this.noRotate === true) return;
this._state = Orbit.State.Rotate;
this._rotateStart.set(event.clientX, event.clientY);
this._rotateEnd.copy(this._rotateStart);
}
}
onMouseMove(event) {
if (!this.enabled) return;
this.automation = this.interaction = true;
if (this._state === Orbit.State.Rotate) {
this._rotateEnd.set(event.clientX, event.clientY);
} else if (this._state === Orbit.State.Pan) {
this._panEnd.set(event.clientX, event.clientY);
}
}
onMouseUp(event) {
this.interaction = false;
this._state = Orbit.State.None;
}
onMouseWheel(event) {
if (this.enabled === false || this.noZoom === true) return;
this.automation = this.interaction = true;
if (this.interactionStopsAutomation) this.stop();
this._autoZoom.start = this._autoZoom.end = 0;
this._wheelStart.y += event.delta * 0.01;
this._mousePosition.x = event.offsetX / this.view.width * 2 - 1;
this._mousePosition.y = (-(event.offsetY / this.view.height)) * 2 + 1;
}
onTouchStart(event) {
if (this.enabled === false) return;
this.automation = this.interaction = true;
if (this.interactionStopsAutomation) this.stop();
// for convenience allow panning mit MouseL if noRotate is active
if (event.touches.length == 1 && this.noRotate || event.touches.length == 2) {
this._state = Orbit.State.TouchZoomPan;
if (event.touches.length == 2 && this.noZoom !== true) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
this._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy);
dx = (event.touches[0].pageX + event.touches[1].pageX) / 2;
dy = (event.touches[0].pageY + event.touches[1].pageY) / 2;
this._panStart.set(dx, dy);
this._panEnd.copy(this._panStart);
} else if (event.touches.length == 1 && this.noPan !== true) {
this._touchZoomDistanceStart = this._touchZoomDistanceEnd = 0;
this._panStart.set(event.touches[0].pageX, event.touches[0].pageY);
}
this._panEnd.copy(this._panStart);
} else if (event.touches.length == 1) {
if (this.noRotate === true) return;
this._state = Orbit.State.TouchRotate;
this._rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
this._rotateEnd.copy(this._rotateStart);
} else {
this._state = Orbit.State.None;
}
}
onTouchMove(event) {
if (this.enabled === false) return;
this.automation = this.interaction = true;
// for convenience allow panning mit MouseL if noRotate is active
if (event.touches.length == 1 && this.noRotate || event.touches.length == 2) {
if (this._state != Orbit.State.TouchZoomPan) return;
if (event.touches.length == 2) {
var dx = event.touches[0].pageX - event.touches[1].pageX;
var dy = event.touches[0].pageY - event.touches[1].pageY;
this._touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy);
dx = (event.touches[0].pageX + event.touches[1].pageX) / 2;
dy = (event.touches[0].pageY + event.touches[1].pageY) / 2;
this._panEnd.set(dx, dy);
} else if (event.touches.length == 1) {
this._touchZoomDistanceStart = this._touchZoomDistanceEnd = 0;
this._panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
}
} else if (event.touches.length == 1) {
if (this._state != Orbit.State.TouchRotate) return;
this._rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
} else {
this._state = Orbit.State.None;
}
}
onTouchEnd(event) {
this.interaction = false;
if (this.enabled === false) return;
switch (event.touches.length) {
case 2:
this._touchZoomDistanceStart = this._touchZoomDistanceEnd = 0;
break;
}
this._state = Orbit.State.None;
}
}
Orbit.PanMode = {
Horizontal: 1,
Vertical: 2,
Both: 3
};
Orbit.ZoomMode = {
Center: 0,
Mouse: 1,
Target: 2
};
Orbit.Eps = 0.000001;
Orbit.State = {
None: -1,
Rotate: 0,
Zoom: 1,
Pan: 2,
TouchRotate: 3,
TouchZoomPan: 4
};