/**
* Handles the canvas interaction such as zooming, panning and clicking.
* @module InteractionControls
*/
var prevMousePos = { x: 0, y: 0 };
var mouseDown = false;
var aspectRatio = window.innerWidth / window.innerHeight;
var maxWindowSize = Math.max(window.innerWidth, window.innerHeight);
var cameraSize = 5;
var cameraZPos = 5;
var cameraMovementSpeed;
var cameraZoomSpeed = 2;
var camera = new THREE.OrthographicCamera(cameraSize * aspectRatio / -2, cameraSize * aspectRatio / 2, cameraSize / 2, cameraSize / -2, 1, 10);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
/**
* sets the camera to its initial position and defines all the interaction events
*/
function setupCamera() {
cameraMovementSpeed = cameraSize;
raycaster.linePrecision = edgeDistance / 2;
camera.position.set(0, 0, cameraZPos);
camera.zoom = 1.0;
camera.updateProjectionMatrix();
canvas.onmousedown = function (evt) {
mouseDown = true;
prevMousePos.x = evt.x;
prevMousePos.y = evt.y
mouse.x = (evt.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (evt.clientY / window.innerHeight) * 2 + 1;
raycast(mouse);
}
canvas.onmouseup = function () {
mouseDown = false;
}
canvas.onmousemove = function (evt) {
if (mouseDown) {
// scale movement speed according to current zoom level
let x = (evt.x - prevMousePos.x) / maxWindowSize * cameraMovementSpeed / camera.zoom;
let y = (evt.y - prevMousePos.y) / maxWindowSize * cameraMovementSpeed / camera.zoom;
prevMousePos.x = evt.x;
prevMousePos.y = evt.y;
if (!rendering) {
camera.translateX(-x);
camera.translateY(y);
renderScene();
}
}
// scale mouse pos to range [-1,1] for raycast
mouse.x = (evt.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (evt.clientY / window.innerHeight) * 2 + 1;
}
canvas.addEventListener("wheel", function (e) {
let dir = Math.sign(e.deltaY);
if (!rendering) {
if (dir < 0)
camera.zoom += camera.zoom * cameraZoomSpeed * 0.1;
else
camera.zoom -= camera.zoom * cameraZoomSpeed * 0.1;
camera.zoom = Math.max(0.5, Math.min(Math.max(30, cameraSize / 5), camera.zoom));
camera.updateProjectionMatrix();
renderScene();
}
});
window.addEventListener('resize', () => {
aspectRatio = window.innerWidth / window.innerHeight;
updateCamera(cameraSize, camera.zoom, false);
renderer.setSize(window.innerWidth, window.innerHeight);
renderScene();
});
}
/**
* updates the camera based on the specified parameters
* @param {float} size of the camera frustum
* @param {float} zoom level of the camera (1 = default)
* @param {boolean} centerOriginFlag sets the camera back to the 0 origin if true
*/
function updateCamera(size, zoom, centerOriginFlag) {
if (centerOriginFlag)
camera.position.set(0, 0, cameraZPos);
cameraSize = size;
cameraMovementSpeed = cameraSize;
cameraZoomSpeed = 2;
camera.zoom = zoom;
camera.aspect = aspectRatio;
camera.left = cameraSize * aspectRatio / -2;
camera.right = cameraSize * aspectRatio / 2;
camera.top = cameraSize / 2;
camera.bottom = cameraSize / -2;
camera.updateProjectionMatrix();
}
/**
* spawns a ray and checks for intersections
* in detailLOD: checks for intersections with nodes and edges
* in lowDetailLOD: checks for intersections with supernodes
* if an intersection occurs the further processing is forwarded to the render logic and the GUI
* @param {vec2} mousePos where the click occured, both coordinates in range [-1,1]
*/
function raycast(mousePos) {
raycaster.setFromCamera(mousePos, camera);
var intersects = raycaster.intersectObjects(nodeGroup.children);
if (intersects.length == 1) {
// node or supernode clicked
if (detailLODEnabled) {
let node = nodes[intersects[0].object.geometry.nodeId];
selectNode(node);
guiUpdateSelectedNode(node);
}
else {
let supernode = allSupernodes[intersects[0].object.geometry.supernodeId];
selectSupernode(supernode);
}
}
else if (detailLODEnabled) {
intersects = raycaster.intersectObjects(linesGroup.children);
if (intersects.length != 0) {
// edge clicked
// divide by two because one line has two points!
let lineIndex = Math.floor(intersects[0].index / 2);
selectEdge(lines[lineIndex].renderedEdge);
guiUpdateSelectedEdge(lines[lineIndex].renderedEdge.edge);
}
}
}