InteractorStyleManipulator

Methods

addGestureManipulator

Adds a gesture manipulator.

Argument Type Required Description
manipulator Yes the manipulator to add

Returns

Type Description
whether the manipulator has been added

addKeyboardManipulator

Adds a keyboard manipulator.

Argument Type Required Description
manipulator Yes the manipulator to add

Returns

Type Description
whether the manipulator has been added

addMouseManipulator

Adds a mouse manipulator.

Argument Type Required Description
manipulator Yes the manipulator to add

Returns

Type Description
whether the manipulator has been added

addVRManipulator

Adds a VR manipulator.

Argument Type Required Description
manipulator Yes the manipulator to add

Returns

Type Description
whether the manipulator has been added

findMouseManipulator

Finds a mouse manipulator with a given control set.

Argument Type Required Description
button Yes which button
shift Yes shift enabled
scroll Yes scroll enabled
alt Yes alt enabled

findVRManipulator

Finds a VR manipulator with a given device + input.

Argument Type Required Description
device Yes
input Yes

getCenterOfRotation

Gets the center of rotation.

Returns

Type Description
Vector3

getNumberOfGestureManipulators

Gets the number of gesture manipulators.

getNumberOfKeyboardManipulators

Gets the number of keyboard manipulators.

getNumberOfMouseManipulators

Gets the number of mouse manipulators.

getNumberOfVRManipulators

Gets the number of VR manipulators.

getRotationFactor

Gets the rotation factor.

handleButton3D

Handles a 3D button event.

Argument Type Required Description
callData Yes event data

handleEndMouseWheel

Handles the end of a wheel event.

Argument Type Required Description
callData Yes event data

handleEndPan

Handles the end of a pan gesture.

Argument Type Required Description
callData Yes event data

handleEndPinch

Handles the end of a pinch gesture.

Argument Type Required Description
callData Yes event data

handleEndRotate

Handles the end of a rotate gesture.

Argument Type Required Description
callData Yes event data

handleKeyDown

Handles a keydown event.

Argument Type Required Description
callData Yes event data

handleKeyPress

Handles a keypress.

Argument Type Required Description
callData Yes event data

handleKeyUp

Handles a keyup event.

Argument Type Required Description
callData Yes event data

handleLeftButtonPress

Handles a left button press event.

Argument Type Required Description
callData Yes event data

handleLeftButtonRelease

Handles a left button release event.

Argument Type Required Description
callData Yes event data

handleMiddleButtonPress

Handles a middle button press event.

Argument Type Required Description
callData Yes event data

handleMiddleButtonRelease

Handles a middle button release event.

Argument Type Required Description
callData Yes event data

handleMouseMove

Handles a mouse move.

Argument Type Required Description
callData Yes event data

handleMouseWheel

Handles a wheel event.

Argument Type Required Description
callData Yes event data

handleMove3D

Handles a 3D move event.

Argument Type Required Description
ed Yes event data

handlePan

Handles a pan gesture.

Argument Type Required Description
callData Yes event data

handlePinch

Handles a pinch gesture.

Argument Type Required Description
callData Yes event data

handleRightButtonPress

Handles a right button press event.

Argument Type Required Description
callData Yes event data

handleRightButtonRelease

Handles a right button release event.

Argument Type Required Description
callData Yes event data

handleRotate

Handles a rotate gesture.

Argument Type Required Description
callData Yes event data

handleStartMouseWheel

Handles the start of a wheel event.

Argument Type Required Description
callData Yes event data

handleStartPan

Handles the start of a pan gesture.

Argument Type Required Description
callData Yes event data

handleStartPinch

Handles the start of a pinch gesture.

Argument Type Required Description
callData Yes event data

handleStartRotate

Handles the start of a rotate gesture.

Argument Type Required Description
callData Yes event data

onButtonDown

Handles a button down event.

Argument Type Required Description
button Yes which button
callData Yes event data

onButtonUp

Handles a button up event.

Argument Type Required Description
button Yes which button

removeAllGestureManipulators

Remove gesture manipulators.

removeAllKeyboardManipulators

Remove keyboard manipulators.

removeAllManipulators

Remove all manipulators.

removeAllMouseManipulators

Remove mouse manipulators.

removeAllVRManipulators

Remove VR manipulators.

removeGestureManipulator

Removes a gesture manipulator.

Argument Type Required Description
manipulator Yes the manipulator to remove

removeKeyboardManipulator

Removes a keyboard manipulator.

Argument Type Required Description
manipulator Yes the manipulator to remove

removeMouseManipulator

Removes a mouse manipulator.

Argument Type Required Description
manipulator Yes the manipulator to remove

removeVRManipulator

Removes a VR manipulator.

Argument Type Required Description
manipulator Yes the manipulator to remove

resetCurrentManipulator

Resets/clears the current manipulator.

setCenterOfRotation

Sets the center of rotation

Argument Type Required Description
x Number Yes
y Number Yes
z Number Yes

setRotationFactor

Sets the rotation factor.

Argument Type Required Description
factor Yes rotation factor

Source

Presets.js
import Manipulators from 'vtk.js/Sources/Interaction/Manipulators';

const MANIPULTOR_TYPES = {
slice: Manipulators.vtkMouseCameraSliceManipulator,
multiRotate: Manipulators.vtkMouseCameraTrackballMultiRotateManipulator,
pan: Manipulators.vtkMouseCameraTrackballPanManipulator,
roll: Manipulators.vtkMouseCameraTrackballRollManipulator,
rotate: Manipulators.vtkMouseCameraTrackballRotateManipulator,
axisRotate: Manipulators.vtkMouseCameraAxisRotateManipulator,
zoom: Manipulators.vtkMouseCameraTrackballZoomManipulator,
zoomToMouse: Manipulators.vtkMouseCameraTrackballZoomToMouseManipulator,
range: Manipulators.vtkMouseRangeManipulator,
vrPan: Manipulators.vtkVRButtonPanManipulator,
gestureCamera: Manipulators.vtkGestureCameraManipulator,
movement: Manipulators.vtkKeyboardCameraManipulator,
freeLook: Manipulators.vtkMouseCameraTrackballFirstPersonManipulator,
unicam: Manipulators.vtkMouseCameraUnicamManipulator,
unicamRotate: Manipulators.vtkMouseCameraUnicamRotateManipulator,
};

const STYLES = {
'3D': [
{ type: 'rotate' },
{ type: 'pan', options: { shift: true } },
{ type: 'zoom', options: { control: true } },
{ type: 'zoom', options: { alt: true } },
{ type: 'zoom', options: { dragEnabled: false, scrollEnabled: true } },
{ type: 'zoom', options: { button: 3 } },
{ type: 'roll', options: { shift: true, control: true } },
{ type: 'roll', options: { shift: true, alt: true } },
{ type: 'roll', options: { shift: true, button: 3 } },
{ type: 'vrPan' },
{ type: 'gestureCamera' },
],
'2D': [
{ type: 'pan', options: { shift: true } },
{ type: 'zoom', options: { control: true } },
{ type: 'zoom', options: { alt: true } },
{ type: 'zoom', options: { button: 3 } },
{ type: 'roll', options: { shift: true, alt: true } },
{ type: 'roll', options: { shift: true, button: 3 } },
{ type: 'roll', options: { shift: true } },
{ type: 'vrPan' },
{ type: 'gestureCamera' },
],
FirstPerson: [{ type: 'movement' }, { type: 'freeLook' }],
Unicam: [{ type: 'unicam' }],
zRotateTop: [
{ type: 'pan', options: { shift: true } },
{
type: 'axisRotate',
options: { rotationAxis: [0, 0, 1], useHalfAxis: true },
},
{ type: 'zoom', options: { control: true } },
{ type: 'zoom', options: { alt: true } },
{ type: 'zoom', options: { dragEnabled: false, scrollEnabled: true } },
{ type: 'zoom', options: { button: 3 } },
],
zRotateAll: [
{ type: 'pan', options: { shift: true } },
{
type: 'axisRotate',
options: { rotationAxis: [0, 0, 1], useHalfAxis: false },
},
{ type: 'zoom', options: { control: true } },
{ type: 'zoom', options: { alt: true } },
{ type: 'zoom', options: { dragEnabled: false, scrollEnabled: true } },
{ type: 'zoom', options: { button: 3 } },
],
};

function applyDefinitions(definitions, manipulatorStyle) {
manipulatorStyle.removeAllManipulators();
for (let idx = 0; idx < definitions.length; idx++) {
const definition = definitions[idx];
const instance = MANIPULTOR_TYPES[definition.type].newInstance(
definition.options
);
if (instance.isA('vtkCompositeVRManipulator')) {
manipulatorStyle.addVRManipulator(instance);
} else if (instance.isA('vtkCompositeGestureManipulator')) {
manipulatorStyle.addGestureManipulator(instance);
} else if (instance.isA('vtkCompositeKeyboardManipulator')) {
manipulatorStyle.addKeyboardManipulator(instance);
} else {
manipulatorStyle.addMouseManipulator(instance);
}
}

return true;
}

function applyPreset(name, manipulatorStyle) {
return applyDefinitions(STYLES[name], manipulatorStyle);
}

function registerManipulatorType(type, classDef) {
MANIPULTOR_TYPES[type] = classDef;
}

function registerStylePreset(name, definitions) {
STYLES[name] = definitions;
}

export default {
applyDefinitions,
applyPreset,
registerManipulatorType,
registerStylePreset,
};
index.d.ts
import vtkCompositeGestureManipulator from '../../Manipulators/CompositeGestureManipulator';
import vtkCompositeKeyboardManipulator from '../../Manipulators/CompositeKeyboardManipulator';
import vtkCompositeMouseManipulator from '../../Manipulators/CompositeMouseManipulator';
import vtkCompositeVRManipulator from '../../Manipulators/CompositeVRManipulator';
import vtkInteractorStyle from '../../../Rendering/Core/InteractorStyle';
import {
Device,
Input,
} from '../../../Rendering/Core/RenderWindowInteractor/Constants';
import { Nullable, Vector3 } from '../../../types';

export interface vtkInteractorStyleManipulator extends vtkInteractorStyle {
/**
* Remove all manipulators.
*/
removeAllManipulators(): void;

/**
* Remove mouse manipulators.
*/
removeAllMouseManipulators(): void;

/**
* Remove keyboard manipulators.
*/
removeAllKeyboardManipulators(): void;

/**
* Remove VR manipulators.
*/
removeAllVRManipulators(): void;

/**
* Remove gesture manipulators.
*/
removeAllGestureManipulators(): void;

/**
* Adds a mouse manipulator.
* @param manipulator the manipulator to add
* @returns whether the manipulator has been added
*/
addMouseManipulator(manipulator: vtkCompositeMouseManipulator): boolean;

/**
* Adds a keyboard manipulator.
* @param manipulator the manipulator to add
* @returns whether the manipulator has been added
*/
addKeyboardManipulator(manipulator: vtkCompositeKeyboardManipulator): boolean;

/**
* Adds a VR manipulator.
* @param manipulator the manipulator to add
* @returns whether the manipulator has been added
*/
addVRManipulator(manipulator: vtkCompositeVRManipulator): boolean;

/**
* Adds a gesture manipulator.
* @param manipulator the manipulator to add
* @returns whether the manipulator has been added
*/
addGestureManipulator(manipulator: vtkCompositeGestureManipulator): boolean;

/**
* Removes a mouse manipulator.
* @param manipulator the manipulator to remove
*/
removeMouseManipulator(manipulator: vtkCompositeMouseManipulator): void;

/**
* Removes a keyboard manipulator.
* @param manipulator the manipulator to remove
*/
removeKeyboardManipulator(manipulator: vtkCompositeKeyboardManipulator): void;

/**
* Removes a VR manipulator.
* @param manipulator the manipulator to remove
*/
removeVRManipulator(manipulator: vtkCompositeVRManipulator): void;

/**
* Removes a gesture manipulator.
* @param manipulator the manipulator to remove
*/
removeGestureManipulator(manipulator: vtkCompositeGestureManipulator): void;

/**
* Gets the number of mouse manipulators.
*/
getNumberOfMouseManipulators(): number;

/**
* Gets the number of keyboard manipulators.
*/
getNumberOfKeyboardManipulators(): number;

/**
* Gets the number of VR manipulators.
*/
getNumberOfVRManipulators(): number;

/**
* Gets the number of gesture manipulators.
*/
getNumberOfGestureManipulators(): number;

/**
* Resets/clears the current manipulator.
*/
resetCurrentManipulator(): void;

/**
* Finds a mouse manipulator with a given control set.
* @param button which button
* @param shift shift enabled
* @param scroll scroll enabled
* @param alt alt enabled
*/
findMouseManipulator(
button: number,
shift: boolean,
scroll: boolean,
alt: boolean
): Nullable<vtkCompositeMouseManipulator>;

/**
* Finds a VR manipulator with a given device + input.
* @param device
* @param input
*/
findVRManipulator(
device: Device,
input: Input
): Nullable<vtkCompositeVRManipulator>;

/**
* Handles a left button press event.
* @param callData event data
*/
handleLeftButtonPress(callData: unknown): void;

/**
* Handles a middle button press event.
* @param callData event data
*/
handleMiddleButtonPress(callData: unknown): void;

/**
* Handles a right button press event.
* @param callData event data
*/
handleRightButtonPress(callData: unknown): void;

/**
* Handles a left button release event.
* @param callData event data
*/
handleLeftButtonRelease(callData: unknown): void;

/**
* Handles a middle button release event.
* @param callData event data
*/
handleMiddleButtonRelease(callData: unknown): void;

/**
* Handles a right button release event.
* @param callData event data
*/
handleRightButtonRelease(callData: unknown): void;

/**
* Handles the start of a wheel event.
* @param callData event data
*/
handleStartMouseWheel(callData: unknown): void;

/**
* Handles a wheel event.
* @param callData event data
*/
handleMouseWheel(callData: unknown): void;

/**
* Handles the end of a wheel event.
* @param callData event data
*/
handleEndMouseWheel(callData: unknown): void;

/**
* Handles a mouse move.
* @param callData event data
*/
handleMouseMove(callData: unknown): void;

/**
* Handles a 3D button event.
* @param callData event data
*/
handleButton3D(ed: unknown): void;

/**
* Handles a 3D move event.
* @param ed event data
*/
handleMove3D(ed: unknown): void;

/**
* Handles a keypress.
* @param callData event data
*/
handleKeyPress(callData: unknown): void;

/**
* Handles a keydown event.
* @param callData event data
*/
handleKeyDown(callData: unknown): void;

/**
* Handles a keyup event.
* @param callData event data
*/
handleKeyUp(callData: unknown): void;

/**
* Handles the start of a pinch gesture.
* @param callData event data
*/
handleStartPinch(callData: unknown): void;

/**
* Handles the end of a pinch gesture.
* @param callData event data
*/
handleEndPinch(callData: unknown): void;

/**
* Handles the start of a rotate gesture.
* @param callData event data
*/
handleStartRotate(callData: unknown): void;

/**
* Handles the end of a rotate gesture.
* @param callData event data
*/
handleEndRotate(callData: unknown): void;

/**
* Handles the start of a pan gesture.
* @param callData event data
*/
handleStartPan(callData: unknown): void;

/**
* Handles the end of a pan gesture.
* @param callData event data
*/
handleEndPan(callData: unknown): void;

/**
* Handles a pinch gesture.
* @param callData event data
*/
handlePinch(callData: unknown): void;

/**
* Handles a rotate gesture.
* @param callData event data
*/
handleRotate(callData: unknown): void;

/**
* Handles a pan gesture.
* @param callData event data
*/
handlePan(callData: unknown): void;

/**
* Handles a button down event.
* @param button which button
* @param callData event data
*/
onButtonDown(button: number, callData: unknown): void;

/**
* Handles a button up event.
* @param button which button
*/
onButtonUp(button: number): void;

/**
* Sets the rotation factor.
* @param factor rotation factor
*/
setRotationFactor(factor: number): boolean;

/**
* Gets the rotation factor.
*/
getRotationFactor(): number;

getMouseManipulators(): vtkCompositeMouseManipulator[];
getMouseManipulators(): vtkCompositeMouseManipulator[];
getMouseManipulators(): vtkCompositeMouseManipulator[];
getMouseManipulators(): vtkCompositeMouseManipulator[];

/**
* Sets the center of rotation
* @param {Number} x
* @param {Number} y
* @param {Number} z
*/
setCenterOfRotation(x: number, y: number, z: number): boolean;
setCenterOfRotation(xyz: Vector3): boolean;

/**
* Gets the center of rotation.
* @returns {Vector3}
*/
getCenterOfRotation(): Vector3;
}

export interface IInteractorStyleManipulatorInitialValues {
centerOfRotation?: Vector3;
rotationFactor?: number;
}

export function newInstance(
initialValues?: IInteractorStyleManipulatorInitialValues
): vtkInteractorStyleManipulator;

export function extend(
publicAPI: object,
model: object,
initialValues?: IInteractorStyleManipulatorInitialValues
): void;

export const vtkInteractorStyleManipulator: {
newInstance: typeof newInstance;
extend: typeof extend;
};

export default vtkInteractorStyleManipulator;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkInteractorStyle from 'vtk.js/Sources/Rendering/Core/InteractorStyle';

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
// ----------------------------------------------------------------------------

export const STATIC = {
dollyToPosition,
translateCamera,
dollyByFactor,
};

// ----------------------------------------------------------------------------
// vtkInteractorStyleManipulator methods
// ----------------------------------------------------------------------------

function vtkInteractorStyleManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkInteractorStyleManipulator');

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(1, callData);
};

//-------------------------------------------------------------------------
publicAPI.handleMiddleButtonPress = (callData) => {
model.previousPosition = callData.position;
publicAPI.onButtonDown(2, callData);
};

//-------------------------------------------------------------------------
publicAPI.handleRightButtonPress = (callData) => {
model.previousPosition = callData.position;
publicAPI.onButtonDown(3, callData);
};

//-------------------------------------------------------------------------
publicAPI.handleButton3D = (ed) => {
if (!ed) {
return;
}

// Look for a matching 3D camera interactor.
model.currentManipulator = publicAPI.findVRManipulator(
ed.device,
ed.input,
ed.pressed
);
if (model.currentManipulator) {
model.currentManipulator.onButton3D(
publicAPI,
ed.pokedRenderer,
model.state,
ed.device,
ed.input,
ed.pressed
);
if (ed.pressed) {
publicAPI.startCameraPose();
} else {
publicAPI.endCameraPose();
}
} else {
vtkDebugMacro('No manipulator found');
}
};

//-------------------------------------------------------------------------
publicAPI.handleMove3D = (ed) => {
if (model.currentManipulator && model.state === States.IS_CAMERA_POSE) {
model.currentManipulator.onMove3D(
publicAPI,
ed.pokedRenderer,
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,
callData.pokedRenderer,
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(1);
};

//-------------------------------------------------------------------------
publicAPI.handleMiddleButtonRelease = () => {
publicAPI.onButtonUp(2);
};

//-------------------------------------------------------------------------
publicAPI.handleRightButtonRelease = () => {
publicAPI.onButtonUp(3);
};

//-------------------------------------------------------------------------
publicAPI.onButtonUp = (button) => {
if (!model.currentManipulator) {
return;
}
if (
model.currentManipulator.getButton &&
model.currentManipulator.getButton() === button
) {
model.currentManipulator.onButtonUp(model._interactor);
model.currentManipulator.endInteraction();
model.currentManipulator = null;
model._interactor.cancelAnimation(publicAPI.onButtonDown);
publicAPI.invokeEndInteractionEvent(END_INTERACTION_EVENT);
}
};

//-------------------------------------------------------------------------
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,
callData.pokedRenderer,
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,
callData.pokedRenderer,
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,
callData.pokedRenderer,
callData.position
);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};

//-------------------------------------------------------------------------
// Keyboard
//-------------------------------------------------------------------------
publicAPI.handleKeyPress = (callData) => {
model.keyboardManipulators
.filter((m) => m.onKeyPress)
.forEach((manipulator) => {
manipulator.onKeyPress(
model._interactor,
callData.pokedRenderer,
callData.key
);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
});
};

//-------------------------------------------------------------------------
publicAPI.handleKeyDown = (callData) => {
model.keyboardManipulators
.filter((m) => m.onKeyDown)
.forEach((manipulator) => {
manipulator.onKeyDown(
model._interactor,
callData.pokedRenderer,
callData.key
);
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
});
};

//-------------------------------------------------------------------------
publicAPI.handleKeyUp = (callData) => {
model.keyboardManipulators
.filter((m) => m.onKeyUp)
.forEach((manipulator) => {
manipulator.onKeyUp(
model._interactor,
callData.pokedRenderer,
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,
callData.pokedRenderer,
callData.scale
);
actionCount++;
}
}
if (actionCount) {
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};

//----------------------------------------------------------------------------
publicAPI.handlePan = (callData) => {
let count = model.gestureManipulators.length;
let actionCount = 0;
while (count--) {
const manipulator = model.gestureManipulators[count];
if (manipulator && manipulator.isPanEnabled()) {
manipulator.onPan(
model._interactor,
callData.pokedRenderer,
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,
callData.pokedRenderer,
callData.rotation
);
actionCount++;
}
}
if (actionCount) {
publicAPI.invokeInteractionEvent(INTERACTION_EVENT);
}
};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
cachedMousePosition: null,
currentManipulator: null,
currentWheelManipulator: null,
// mouseManipulators: null,
// keyboardManipulators: null,
// vrManipulators: null,
// gestureManipulators: null,
centerOfRotation: [0, 0, 0],
rotationFactor: 1,
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, 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);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(
extend,
'vtkInteractorStyleManipulator'
);

// ----------------------------------------------------------------------------

export default { newInstance, extend, ...STATIC };