You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.9 KiB
JavaScript
118 lines
3.9 KiB
JavaScript
/* Copyright (C) 2024 Sebastián Santisi <ssantisi@fi.uba.ar>, CSC-CONICET */
|
|
import * as THREE from 'three';
|
|
|
|
class Screen {
|
|
static isMobile = 'ontouchstart' in document.documentElement;
|
|
|
|
constructor(camera, renderer, center) {
|
|
this.camera = camera;
|
|
this.renderer = renderer;
|
|
this.center = center;
|
|
this.cbmove = null;
|
|
|
|
this.raycaster = new THREE.Raycaster();
|
|
this.pointerScreen = new THREE.Vector2();
|
|
this.pointerWorld = new THREE.Vector3();
|
|
|
|
this.radius = 26;
|
|
this.phi = -0.5;
|
|
this.theta = 0.45;
|
|
this.z = 15;
|
|
this.aspect = 1.94;
|
|
|
|
this.clicked = false;
|
|
|
|
this.camera.setFocalLength(60);
|
|
|
|
if(Screen.isMobile) {
|
|
window.addEventListener('touchstart', (event) => { this.onClick(event); });
|
|
window.addEventListener('touchend', (event) => { this.onMouseUp(event); });
|
|
window.addEventListener('touchmove', (event) => { this.onPointerMove(event); });
|
|
}
|
|
else {
|
|
window.addEventListener('mouseup', (event) => { this.onMouseUp(event); });
|
|
window.addEventListener('mousedown', (event) => { this.onClick(event); });
|
|
window.addEventListener('pointermove', (event) => { this.onPointerMove(event); });
|
|
}
|
|
window.addEventListener('resize', () => { this.onResize(); });
|
|
}
|
|
|
|
setMoveCallBack(cbmove) {
|
|
this.cbmove = cbmove;
|
|
}
|
|
|
|
updatePointers(event) {
|
|
if(Screen.isMobile) {
|
|
var touch = event.touches[0] || event.changedTouches[0];
|
|
var x = touch.pageX;
|
|
var y = touch.pageY;
|
|
}
|
|
else {
|
|
var x = event.clientX
|
|
var y = event.clientY;
|
|
}
|
|
this.pointerScreen.x = (x / window.innerWidth) * 2 - 1;
|
|
this.pointerScreen.y = -(y / window.innerHeight) * 2 + 1;
|
|
this.raycaster.setFromCamera(this.pointerScreen, this.camera);
|
|
|
|
var point = new THREE.Vector3(this.pointerScreen.x, this.pointerScreen.y, 0.5);
|
|
point.unproject(this.camera);
|
|
point.sub(this.camera.position).normalize();
|
|
var distance = -this.camera.position.z / point.z;
|
|
this.pointerWorld.copy(this.camera.position).add(point.multiplyScalar(distance));
|
|
}
|
|
|
|
onClick(event) {
|
|
this.clicked = true;
|
|
this.updatePointers(event);
|
|
}
|
|
|
|
onMouseUp(event) {
|
|
this.clicked = false;
|
|
this.updatePointers(event);
|
|
ws.move(this.pointerWorld, true);
|
|
if(this.cbmove)
|
|
this.cbmove(this.pointerWorld, true);
|
|
}
|
|
|
|
onPointerMove(event) {
|
|
this.updatePointers(event);
|
|
if(this.clicked) {
|
|
if(this.cbmove)
|
|
this.cbmove(this.pointerWorld, false);
|
|
}
|
|
}
|
|
|
|
onResize() {
|
|
this.camera.aspect = window.innerWidth / window.innerHeight;
|
|
this.camera.fov = 15;
|
|
this.camera.updateProjectionMatrix();
|
|
|
|
var r;
|
|
if(this.camera.aspect > this.aspect)
|
|
r = this.radius;
|
|
else {
|
|
r = this.radius * this.aspect / this.camera.aspect;
|
|
}
|
|
|
|
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
|
document.getElementById("container").style.height = window.innerHeight;
|
|
document.getElementById("container").style.width = window.innerWidth;
|
|
document.getElementById("rotate").style.display = this.camera.aspect > 1 ? "none" : "block";
|
|
|
|
var theta = Math.PI / 2 - this.theta;
|
|
var phi = this.phi - Math.PI / 2;
|
|
var x = r * Math.sin(theta) * Math.cos(phi) + this.center.x;
|
|
var y = r * Math.sin(theta) * Math.sin(phi) + this.center.y;
|
|
var z = r * Math.cos(theta) + this.center.z;
|
|
|
|
this.camera.position.set(x, y, z);
|
|
this.camera.up = new THREE.Vector3(0,0,1);
|
|
this.camera.lookAt(this.center);
|
|
|
|
this.raycaster.setFromCamera(this.pointerScreen, this.camera);
|
|
}
|
|
}
|
|
|
|
export { Screen };
|