@kitware/vtk.js
Version:
Visualization Toolkit for the Web
640 lines (561 loc) • 25.1 kB
JavaScript
import { m as macro } from '../../macros2.js';
import { MouseButton } from '../../Rendering/Core/RenderWindowInteractor/Constants.js';
import vtkInteractorStyle from '../../Rendering/Core/InteractorStyle.js';
const {
vtkDebugMacro
} = macro;
const {
States
} = vtkInteractorStyle;
// ----------------------------------------------------------------------------
// Event Types
// ----------------------------------------------------------------------------
const START_INTERACTION_EVENT = {
type: 'StartInteractionEvent'
};
const INTERACTION_EVENT = {
type: 'InteractionEvent'
};
const END_INTERACTION_EVENT = {
type: 'EndInteractionEvent'
};
// ----------------------------------------------------------------------------
// Global methods
// ----------------------------------------------------------------------------
function translateCamera(renderer, rwi, toX, toY, fromX, fromY) {
const cam = renderer.getActiveCamera();
let viewFocus = cam.getFocalPoint();
viewFocus = rwi.getInteractorStyle().computeWorldToDisplay(renderer, viewFocus[0], viewFocus[1], viewFocus[2]);
const focalDepth = viewFocus[2];
const newPickPoint = rwi.getInteractorStyle().computeDisplayToWorld(renderer, toX, toY, focalDepth);
const oldPickPoint = rwi.getInteractorStyle().computeDisplayToWorld(renderer, fromX, fromY, focalDepth);
// camera motion is reversed
const motionVector = [oldPickPoint[0] - newPickPoint[0], oldPickPoint[1] - newPickPoint[1], oldPickPoint[2] - newPickPoint[2]];
viewFocus = cam.getFocalPoint();
const viewPoint = cam.getPosition();
cam.setFocalPoint(motionVector[0] + viewFocus[0], motionVector[1] + viewFocus[1], motionVector[2] + viewFocus[2]);
cam.setPosition(motionVector[0] + viewPoint[0], motionVector[1] + viewPoint[1], motionVector[2] + viewPoint[2]);
}
function dollyToPosition(fact, position, renderer, rwi) {
const cam = renderer.getActiveCamera();
if (cam.getParallelProjection()) {
// Zoom relatively to the cursor
const view = rwi.getView();
const aSize = view.getViewportSize(renderer);
const viewport = renderer.getViewport();
const viewSize = view.getSize();
const w = aSize[0];
const h = aSize[1];
const x0 = w / 2;
const y0 = h / 2;
const x1 = position.x - viewport[0] * viewSize[0];
const y1 = position.y - viewport[1] * viewSize[1];
translateCamera(renderer, rwi, x0, y0, x1, y1);
cam.setParallelScale(cam.getParallelScale() / fact);
translateCamera(renderer, rwi, x1, y1, x0, y0);
} else {
// Zoom relatively to the cursor position
// Move focal point to cursor position
let viewFocus = cam.getFocalPoint();
const norm = cam.getViewPlaneNormal();
viewFocus = rwi.getInteractorStyle().computeWorldToDisplay(renderer, viewFocus[0], viewFocus[1], viewFocus[2]);
const newFp = rwi.getInteractorStyle().computeDisplayToWorld(renderer, position.x, position.y, viewFocus[2]);
cam.setFocalPoint(newFp[0], newFp[1], newFp[2]);
// Move camera in/out along projection direction
cam.dolly(fact);
renderer.resetCameraClippingRange();
// Find new focal point
const newCameraPos = cam.getPosition();
viewFocus = cam.getFocalPoint();
const newPoint = [0, 0, 0];
let t = norm[0] * (viewFocus[0] - newCameraPos[0]) + norm[1] * (viewFocus[1] - newCameraPos[1]) + norm[2] * (viewFocus[2] - newCameraPos[2]);
t /= norm[0] ** 2 + norm[1] ** 2 + norm[2] ** 2;
newPoint[0] = newCameraPos[0] + norm[0] * t;
newPoint[1] = newCameraPos[1] + norm[1] * t;
newPoint[2] = newCameraPos[2] + norm[2] * t;
cam.setFocalPoint(newPoint[0], newPoint[1], newPoint[2]);
renderer.resetCameraClippingRange();
}
}
function dollyByFactor(interactor, renderer, factor) {
if (Number.isNaN(factor)) {
return;
}
const camera = renderer.getActiveCamera();
if (camera.getParallelProjection()) {
camera.setParallelScale(camera.getParallelScale() / factor);
} else {
camera.dolly(factor);
renderer.resetCameraClippingRange();
}
if (interactor.getLightFollowCamera()) {
renderer.updateLightsGeometryToFollowCamera();
}
}
// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------
const STATIC = {
dollyToPosition,
translateCamera,
dollyByFactor
};
// ----------------------------------------------------------------------------
// vtkInteractorStyleManipulator methods
// ----------------------------------------------------------------------------
function vtkInteractorStyleManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkInteractorStyleManipulator');
model.currentVRManipulators = new Map();
model.mouseManipulators = [];
model.keyboardManipulators = [];
model.vrManipulators = [];
model.gestureManipulators = [];
model.currentManipulator = null;
model.currentWheelManipulator = null;
model.centerOfRotation = [0, 0, 0];
model.rotationFactor = 1;
//-------------------------------------------------------------------------
publicAPI.removeAllManipulators = () => {
publicAPI.removeAllMouseManipulators();
publicAPI.removeAllKeyboardManipulators();
publicAPI.removeAllVRManipulators();
publicAPI.removeAllGestureManipulators();
};
//-------------------------------------------------------------------------
publicAPI.removeAllMouseManipulators = () => {
model.mouseManipulators = [];
};
//-------------------------------------------------------------------------
publicAPI.removeAllKeyboardManipulators = () => {
model.keyboardManipulators = [];
};
//-------------------------------------------------------------------------
publicAPI.removeAllVRManipulators = () => {
model.vrManipulators = [];
};
//-------------------------------------------------------------------------
publicAPI.removeAllGestureManipulators = () => {
model.gestureManipulators = [];
};
//-------------------------------------------------------------------------
const removeManipulator = (manipulator, list) => {
const index = list.indexOf(manipulator);
if (index === -1) {
return false;
}
list.splice(index, 1);
publicAPI.modified();
return true;
};
//-------------------------------------------------------------------------
publicAPI.removeMouseManipulator = manipulator => removeManipulator(manipulator, model.mouseManipulators);
//-------------------------------------------------------------------------
publicAPI.removeKeyboardManipulator = manipulator => removeManipulator(manipulator, model.keyboardManipulators);
//-------------------------------------------------------------------------
publicAPI.removeVRManipulator = manipulator => removeManipulator(manipulator, model.vrManipulators);
//-------------------------------------------------------------------------
publicAPI.removeGestureManipulator = manipulator => removeManipulator(manipulator, model.gestureManipulators);
//-------------------------------------------------------------------------
const addManipulator = (manipulator, list) => {
const index = list.indexOf(manipulator);
if (index !== -1) {
return false;
}
list.push(manipulator);
publicAPI.modified();
return true;
};
//-------------------------------------------------------------------------
publicAPI.addMouseManipulator = manipulator => addManipulator(manipulator, model.mouseManipulators);
//-------------------------------------------------------------------------
publicAPI.addKeyboardManipulator = manipulator => addManipulator(manipulator, model.keyboardManipulators);
//-------------------------------------------------------------------------
publicAPI.addVRManipulator = manipulator => addManipulator(manipulator, model.vrManipulators);
//-------------------------------------------------------------------------
publicAPI.addGestureManipulator = manipulator => addManipulator(manipulator, model.gestureManipulators);
//-------------------------------------------------------------------------
publicAPI.getNumberOfMouseManipulators = () => model.mouseManipulators.length;
//-------------------------------------------------------------------------
publicAPI.getNumberOfKeyboardManipulators = () => model.keyboardManipulators.length;
//-------------------------------------------------------------------------
publicAPI.getNumberOfVRManipulators = () => model.vrManipulators.length;
//-------------------------------------------------------------------------
publicAPI.getNumberOfGestureManipulators = () => model.gestureManipulators.length;
//-------------------------------------------------------------------------
publicAPI.resetCurrentManipulator = () => {
model.currentManipulator = null;
model.currentWheelManipulator = null;
};
//-------------------------------------------------------------------------
// Mouse
//-------------------------------------------------------------------------
publicAPI.handleLeftButtonPress = callData => {
model.previousPosition = callData.position;
publicAPI.onButtonDown(MouseButton.LeftButton, callData);
};
//-------------------------------------------------------------------------
publicAPI.handleMiddleButtonPress = callData => {
model.previousPosition = callData.position;
publicAPI.onButtonDown(MouseButton.MiddleButton, callData);
};
//-------------------------------------------------------------------------
publicAPI.handleRightButtonPress = callData => {
model.previousPosition = callData.position;
publicAPI.onButtonDown(MouseButton.RightButton, callData);
};
//-------------------------------------------------------------------------
publicAPI.handleButton3D = ed => {
if (!ed) {
return;
}
// Look for a matching 3D camera interactor.
const manipulator = publicAPI.findVRManipulator(ed.device, ed.input, ed.pressed);
if (manipulator) {
// register the manipulator for this device
model.currentVRManipulators.set(ed.device, manipulator);
manipulator.onButton3D(publicAPI, model.getRenderer(ed), model.state, ed);
if (ed.pressed) {
publicAPI.startCameraPose();
} else {
model.currentVRManipulators.delete(ed.device);
// make sure we don't end camera pose if other VR manipulators are currently interacting
if (model.currentVRManipulators.size === 0) {
publicAPI.endCameraPose();
}
}
} else {
vtkDebugMacro('No manipulator found');
}
};
//-------------------------------------------------------------------------
publicAPI.handleMove3D = ed => {
const manipulator = model.currentVRManipulators.get(ed.device);
if (manipulator && model.state === States.IS_CAMERA_POSE) {
manipulator.onMove3D(publicAPI, model.getRenderer(ed), model.state, ed);
}
};
//-------------------------------------------------------------------------
publicAPI.onButtonDown = (button, callData) => {
// Must not be processing an interaction to start another.
if (model.currentManipulator) {
return;
}
// Look for a matching camera interactor.
model.currentManipulator = publicAPI.findMouseManipulator(button, callData.shiftKey, callData.controlKey, callData.altKey);
if (model.currentManipulator) {
if (model.currentManipulator.setCenter) {
model.currentManipulator.setCenter(model.centerOfRotation);
}
if (model.currentManipulator.setRotationFactor) {
model.currentManipulator.setRotationFactor(model.rotationFactor);
}
model.currentManipulator.startInteraction();
model.currentManipulator.onButtonDown(model._interactor, model.getRenderer(callData), callData.position);
model._interactor.requestAnimation(publicAPI.onButtonDown);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
} else {
vtkDebugMacro('No manipulator found');
}
};
//-------------------------------------------------------------------------
publicAPI.findMouseManipulator = (button, shift, control, alt) => {
// Look for a matching camera manipulator
let manipulator = null;
let count = model.mouseManipulators.length;
while (count--) {
const manip = model.mouseManipulators[count];
if (manip && manip.getButton() === button && manip.getShift() === shift && manip.getControl() === control && manip.getAlt() === alt && manip.isDragEnabled()) {
manipulator = manip;
}
}
return manipulator;
};
//-------------------------------------------------------------------------
publicAPI.findVRManipulator = (device, input) => {
// Look for a matching camera manipulator
let manipulator = null;
let count = model.vrManipulators.length;
while (count--) {
const manip = model.vrManipulators[count];
if (manip && manip.getDevice() === device && manip.getInput() === input) {
manipulator = manip;
}
}
return manipulator;
};
//-------------------------------------------------------------------------
publicAPI.handleLeftButtonRelease = () => {
publicAPI.onButtonUp(MouseButton.LeftButton);
};
//-------------------------------------------------------------------------
publicAPI.handleMiddleButtonRelease = () => {
publicAPI.onButtonUp(MouseButton.MiddleButton);
};
//-------------------------------------------------------------------------
publicAPI.handleRightButtonRelease = () => {
publicAPI.onButtonUp(MouseButton.RightButton);
};
//-------------------------------------------------------------------------
publicAPI.onButtonUp = button => {
if (!model.currentManipulator) {
return;
}
if (model.currentManipulator.getButton && model.currentManipulator.getButton() === button) {
model.currentManipulator.onButtonUp(model._interactor);
model.currentManipulator.endInteraction();
if (!model._interactor.isPointerLocked()) {
model.currentManipulator = null;
}
model._interactor.cancelAnimation(publicAPI.onButtonDown);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
}
};
//-------------------------------------------------------------------------
publicAPI.handleEndPointerLock = () => {
model.currentManipulator = null;
};
//-------------------------------------------------------------------------
publicAPI.handleStartMouseWheel = callData => {
// Must not be processing a wheel interaction to start another.
if (model.currentWheelManipulator) {
return;
}
let manipulator = null;
let count = model.mouseManipulators.length;
while (count--) {
const manip = model.mouseManipulators[count];
if (manip && manip.isScrollEnabled() && manip.getShift() === callData.shiftKey && manip.getControl() === callData.controlKey && manip.getAlt() === callData.altKey) {
manipulator = manip;
}
}
if (manipulator) {
model.currentWheelManipulator = manipulator;
model.currentWheelManipulator.onStartScroll(model._interactor, model.getRenderer(callData), callData.spinY);
model.currentWheelManipulator.startInteraction();
model._interactor.requestAnimation(publicAPI.handleStartMouseWheel);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
} else {
vtkDebugMacro('No manipulator found');
}
};
//-------------------------------------------------------------------------
publicAPI.handleEndMouseWheel = () => {
if (!model.currentWheelManipulator) {
return;
}
if (model.currentWheelManipulator.onEndScroll) {
model.currentWheelManipulator.onEndScroll(model._interactor);
model.currentWheelManipulator.endInteraction();
model.currentWheelManipulator = null;
model._interactor.cancelAnimation(publicAPI.handleStartMouseWheel);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
}
};
//-------------------------------------------------------------------------
publicAPI.handleMouseWheel = callData => {
if (model.currentWheelManipulator && model.currentWheelManipulator.onScroll) {
model.currentWheelManipulator.onScroll(model._interactor, model.getRenderer(callData), callData.spinY, model.cachedMousePosition);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
//-------------------------------------------------------------------------
publicAPI.handleMouseMove = callData => {
model.cachedMousePosition = callData.position;
if (model.currentManipulator && model.currentManipulator.onMouseMove) {
model.currentManipulator.onMouseMove(model._interactor, model.getRenderer(callData), callData.position);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
//-------------------------------------------------------------------------
// Keyboard
//-------------------------------------------------------------------------
publicAPI.handleKeyPress = callData => {
model.keyboardManipulators.filter(m => m.onKeyPress).forEach(manipulator => {
manipulator.onKeyPress(model._interactor, model.getRenderer(callData), callData.key);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
});
};
//-------------------------------------------------------------------------
publicAPI.handleKeyDown = callData => {
model.keyboardManipulators.filter(m => m.onKeyDown).forEach(manipulator => {
manipulator.onKeyDown(model._interactor, model.getRenderer(callData), callData.key);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
});
};
//-------------------------------------------------------------------------
publicAPI.handleKeyUp = callData => {
model.keyboardManipulators.filter(m => m.onKeyUp).forEach(manipulator => {
manipulator.onKeyUp(model._interactor, model.getRenderer(callData), callData.key);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
});
};
//-------------------------------------------------------------------------
// Gesture
//-------------------------------------------------------------------------
publicAPI.handleStartPinch = callData => {
publicAPI.startDolly();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPinchEnabled()) {
manipulator.onStartPinch(model._interactor, callData.scale);
manipulator.startInteraction();
}
}
model._interactor.requestAnimation(publicAPI.handleStartPinch);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
};
//--------------------------------------------------------------------------
publicAPI.handleEndPinch = () => {
publicAPI.endDolly();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPinchEnabled()) {
manipulator.onEndPinch(model._interactor);
manipulator.endInteraction();
}
}
model._interactor.cancelAnimation(publicAPI.handleStartPinch);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
};
//----------------------------------------------------------------------------
publicAPI.handleStartRotate = callData => {
publicAPI.startRotate();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isRotateEnabled()) {
manipulator.onStartRotate(model._interactor, callData.rotation);
manipulator.startInteraction();
}
}
model._interactor.requestAnimation(publicAPI.handleStartRotate);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
};
//--------------------------------------------------------------------------
publicAPI.handleEndRotate = () => {
publicAPI.endRotate();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isRotateEnabled()) {
manipulator.onEndRotate(model._interactor);
manipulator.endInteraction();
}
}
model._interactor.cancelAnimation(publicAPI.handleStartRotate);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
};
//----------------------------------------------------------------------------
publicAPI.handleStartPan = callData => {
publicAPI.startPan();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPanEnabled()) {
manipulator.onStartPan(model._interactor, callData.translation);
manipulator.startInteraction();
}
}
model._interactor.requestAnimation(publicAPI.handleStartPan);
publicAPI.invokeStartInteractionEvent(START_INTERACTION_EVENT);
};
//--------------------------------------------------------------------------
publicAPI.handleEndPan = () => {
publicAPI.endPan();
let count = model.gestureManipulators.length;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPanEnabled()) {
manipulator.onEndPan(model._interactor);
manipulator.endInteraction();
}
}
model._interactor.cancelAnimation(publicAPI.handleStartPan);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
};
//----------------------------------------------------------------------------
publicAPI.handlePinch = callData => {
let count = model.gestureManipulators.length;
let actionCount = 0;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPinchEnabled()) {
manipulator.onPinch(model._interactor, model.getRenderer(callData), callData.scale);
actionCount++;
}
}
if (actionCount) {
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
//----------------------------------------------------------------------------
publicAPI.handlePan = callData => {
const renderer = model.getRenderer(callData);
let count = model.gestureManipulators.length;
let actionCount = 0;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPanEnabled()) {
manipulator.onPan(model._interactor, renderer, callData.translation);
actionCount++;
}
}
if (actionCount) {
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
//----------------------------------------------------------------------------
publicAPI.handleRotate = callData => {
let count = model.gestureManipulators.length;
let actionCount = 0;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isRotateEnabled()) {
manipulator.onRotate(model._interactor, model.getRenderer(callData), callData.rotation);
actionCount++;
}
}
if (actionCount) {
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const defaultValues = initialValues => ({
cachedMousePosition: null,
currentManipulator: null,
currentWheelManipulator: null,
// mouseManipulators: null,
// keyboardManipulators: null,
// vrManipulators: null,
// gestureManipulators: null,
centerOfRotation: [0, 0, 0],
rotationFactor: 1,
...initialValues
});
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, defaultValues(initialValues));
// Inheritance
vtkInteractorStyle.extend(publicAPI, model, initialValues);
// Create get-set macros
macro.setGet(publicAPI, model, ['rotationFactor']);
macro.get(publicAPI, model, ['mouseManipulators', 'keyboardManipulators', 'vrManipulators', 'gestureManipulators']);
macro.setGetArray(publicAPI, model, ['centerOfRotation'], 3);
// Object specific methods
vtkInteractorStyleManipulator(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkInteractorStyleManipulator');
// ----------------------------------------------------------------------------
var vtkInteractorStyleManipulator$1 = {
newInstance,
extend,
...STATIC
};
export { STATIC, vtkInteractorStyleManipulator$1 as default, extend, newInstance };