src/controls/orbit.js
import { vec3 } from 'gl-matrix';
import { clamp } from '../utils/math';
import { getContext } from '../session';
const offset = -Math.PI * 0.5;
class OrbitControls {
constructor(camera) {
const gl = getContext();
this.camera = camera;
this.domElement = gl.canvas;
this.radius = Math.max(camera.position.x, camera.position.z);
this.rx = Math.atan2(camera.position.y, this.radius);
this.ry = Math.atan2(camera.position.z, camera.position.x) + offset;
this.ox = 0;
this.oy = 0;
this.width = global.innerWidth;
this.height = global.innerHeight;
// rotation
this.rotationSpeed = 5 * global.devicePixelRatio;
// zoom
this.zoomMin = 0.1;
this.zoomMax = Infinity;
this.zoomSpeed = 100;
this.isDown = false;
this.enable();
}
enable() {
this.domElement.addEventListener('mousedown', this.onStart, false);
this.domElement.addEventListener('mousemove', this.onMove, false);
this.domElement.addEventListener('mouseup', this.onEnd, false);
this.domElement.addEventListener('touchstart', this.onStart, false);
this.domElement.addEventListener('touchmove', this.onMove, false);
this.domElement.addEventListener('touchend', this.onEnd, false);
global.addEventListener('wheel', this.onWheel, false);
}
disable() {
this.domElement.removeEventListener('mousedown', this.onStart, false);
this.domElement.removeEventListener('mousemove', this.onMove, false);
this.domElement.removeEventListener('mouseup', this.onEnd, false);
this.domElement.removeEventListener('touchstart', this.onStart, false);
this.domElement.removeEventListener('touchmove', this.onMove, false);
this.domElement.removeEventListener('touchend', this.onEnd, false);
global.removeEventListener('wheel', this.onWheel, false);
}
onStart = (event) => {
event.preventDefault();
this.oy = this.ry;
this.ox = this.rx;
this.startY = event.pageX / this.width;
this.startX = event.pageY / this.height;
this.isDown = true;
}
onMove = (event) => {
if (this.isDown) {
const y = event.pageX / this.width;
const x = event.pageY / this.height;
this.rx = this.ox + (-(this.startX - x) * this.rotationSpeed);
this.ry = this.oy + ((this.startY - y) * this.rotationSpeed);
this.rx = clamp(this.rx, -Math.PI * 0.5, Math.PI * 0.5);
}
}
onEnd = () => {
this.isDown = false;
}
onWheel = (event) => {
event.preventDefault();
this.zoom(-event.deltaY);
}
zoom(delta) {
this.radius += (delta / 1000) * this.zoomSpeed;
this.radius = clamp(this.radius, this.zoomMin, this.zoomMax);
}
update() {
const y = this.radius * Math.sin(this.rx);
const r = this.radius * Math.cos(this.rx);
const x = Math.sin(this.ry) * r;
const z = Math.cos(this.ry) * r;
vec3.set(this.camera.position.data, x, y, z);
}
}
export default OrbitControls;