@kitware/vtk.js
Version:
Visualization Toolkit for the Web
346 lines (308 loc) • 13.1 kB
JavaScript
import { m as macro } from '../../../macros2.js';
import { k as add } from '../../../Common/Core/Math/index.js';
import { vec3 } from 'gl-matrix';
function widgetBehavior(publicAPI, model) {
model.classHierarchy.push('vtkSplineWidgetProp');
model._isDragging = false;
model.keysDown = {};
model.moveHandle = model.widgetState.getMoveHandle();
// --------------------------------------------------------------------------
// Private methods
// --------------------------------------------------------------------------
const updateHandlesSize = () => {
if (publicAPI.getHandleSizeInPixels() != null) {
const scale = publicAPI.getHandleSizeInPixels();
model.moveHandle.setScale1(scale);
model.widgetState.getHandleList().forEach(handle => {
handle.setScale1(scale);
});
}
};
// --------------------------------------------------------------------------
const addPoint = () => {
// Commit handle to location
if (!model.lastHandle || model.keysDown.Control || !model.freeHand || vec3.squaredDistance(model.moveHandle.getOrigin(), model.lastHandle.getOrigin()) > publicAPI.getFreehandMinDistance() * publicAPI.getFreehandMinDistance()) {
model.lastHandle = model.widgetState.addHandle();
model.lastHandle.setVisible(false);
model.lastHandle.setOrigin(...model.moveHandle.getOrigin());
model.lastHandle.setColor(model.moveHandle.getColor());
model.lastHandle.setScale1(model.moveHandle.getScale1());
model.lastHandle.setManipulator(model.manipulator);
if (!model.firstHandle) {
model.firstHandle = model.lastHandle;
}
model._apiSpecificRenderWindow.setCursor('grabbing');
}
};
// --------------------------------------------------------------------------
const getHoveredHandle = () => {
const handles = model.widgetState.getHandleList();
const scale = model.moveHandle.getScale1() * vec3.distance(model._apiSpecificRenderWindow.displayToWorld(0, 0, 0, model._renderer), model._apiSpecificRenderWindow.displayToWorld(1, 0, 0, model._renderer));
return handles.reduce((_ref, handle) => {
let {
closestHandle,
closestDistance
} = _ref;
if (handle !== model.moveHandle && model.moveHandle.getOrigin() && handle.getOrigin()) {
const distance = vec3.squaredDistance(model.moveHandle.getOrigin(), handle.getOrigin());
if (distance < closestDistance) {
return {
closestHandle: handle,
closestDistance: distance
};
}
}
return {
closestHandle,
closestDistance
};
}, {
closestHandle: null,
closestDistance: scale * scale
}).closestHandle;
};
// --------------------------------------------------------------------------
// Display 2D
// --------------------------------------------------------------------------
publicAPI.setDisplayCallback = callback => model.representations[0].setDisplayCallback(callback);
// --------------------------------------------------------------------------
// Public methods
// --------------------------------------------------------------------------
publicAPI.setResetAfterPointPlacement = model._factory.setResetAfterPointPlacement;
publicAPI.getResetAfterPointPlacement = model._factory.getResetAfterPointPlacement;
publicAPI.setResetAfterPointPlacement(publicAPI.getResetAfterPointPlacement());
publicAPI.setFreehandMinDistance = model._factory.setFreehandMinDistance;
publicAPI.getFreehandMinDistance = model._factory.getFreehandMinDistance;
publicAPI.setFreehandMinDistance(publicAPI.getFreehandMinDistance());
publicAPI.setAllowFreehand = model._factory.setAllowFreehand;
publicAPI.getAllowFreehand = model._factory.getAllowFreehand;
publicAPI.setAllowFreehand(publicAPI.getAllowFreehand());
publicAPI.setDefaultCursor = model._factory.setDefaultCursor;
publicAPI.getDefaultCursor = model._factory.getDefaultCursor;
publicAPI.setDefaultCursor(publicAPI.getDefaultCursor());
// --------------------------------------------------------------------------
publicAPI.setHandleSizeInPixels = size => {
model._factory.setHandleSizeInPixels(size);
updateHandlesSize();
};
publicAPI.getHandleSizeInPixels = model._factory.getHandleSizeInPixels;
publicAPI.setHandleSizeInPixels(model._factory.getHandleSizeInPixels()); // set initial value
// --------------------------------------------------------------------------
publicAPI.setResolution = resolution => {
model._factory.setResolution(resolution);
model.representations[1].setResolution(resolution);
};
publicAPI.setResolution(model._factory.getResolution()); // set initial value
// --------------------------------------------------------------------------
publicAPI.getPoints = () => model.representations[1].getOutputData().getPoints().getData();
// --------------------------------------------------------------------------
publicAPI.reset = () => {
model.widgetState.clearHandleList();
model.lastHandle = null;
model.firstHandle = null;
};
// --------------------------------------------------------------------------
// Right click: Delete handle
// --------------------------------------------------------------------------
publicAPI.handleRightButtonPress = e => {
if (!model.activeState || !model.activeState.getActive() || !model.pickable) {
return macro.VOID;
}
if (model.activeState !== model.moveHandle) {
model._interactor.requestAnimation(publicAPI);
model.activeState.deactivate();
model.widgetState.removeHandle(model.activeState);
model.activeState = null;
model._interactor.cancelAnimation(publicAPI);
} else {
const handle = getHoveredHandle();
if (handle) {
model.widgetState.removeHandle(handle);
} else if (model.lastHandle) {
model.widgetState.removeHandle(model.lastHandle);
const handles = model.widgetState.getHandleList();
model.lastHandle = handles[handles.length - 1];
}
}
publicAPI.invokeInteractionEvent();
return macro.EVENT_ABORT;
};
// --------------------------------------------------------------------------
// Left press: Add new point
// --------------------------------------------------------------------------
publicAPI.handleLeftButtonPress = e => {
const manipulator = model.activeState?.getManipulator?.() ?? model.manipulator;
if (!manipulator || !model.activeState || !model.activeState.getActive() || !model.pickable) {
return macro.VOID;
}
// update worldDelta
manipulator.handleEvent(e, model._apiSpecificRenderWindow);
if (model.activeState === model.moveHandle) {
if (model.widgetState.getHandleList().length === 0) {
addPoint();
} else {
const hoveredHandle = getHoveredHandle();
if (hoveredHandle && !model.keysDown.Control) {
model.moveHandle.deactivate();
model.moveHandle.setVisible(false);
model.activeState = hoveredHandle;
hoveredHandle.activate();
model._isDragging = true;
model.lastHandle.setVisible(true);
} else {
addPoint();
}
}
model.freeHand = publicAPI.getAllowFreehand() && !model._isDragging;
} else if (model.dragable) {
model._isDragging = true;
model._apiSpecificRenderWindow.setCursor('grabbing');
model._interactor.requestAnimation(publicAPI);
}
publicAPI.invokeStartInteractionEvent();
return macro.EVENT_ABORT;
};
// --------------------------------------------------------------------------
// Left release
// --------------------------------------------------------------------------
publicAPI.handleLeftButtonRelease = e => {
if (model._isDragging) {
if (!model.hasFocus) {
model._apiSpecificRenderWindow.setCursor(model.defaultCursor);
model.widgetState.deactivate();
model._interactor.cancelAnimation(publicAPI);
publicAPI.invokeEndInteractionEvent();
} else {
model.moveHandle.setOrigin(...model.activeState.getOrigin());
model.activeState.deactivate();
model.moveHandle.activate();
model.activeState = model.moveHandle;
if (!model.draggedPoint) {
if (vec3.squaredDistance(model.moveHandle.getOrigin(), model.lastHandle.getOrigin()) < model.moveHandle.getScale1() * model.moveHandle.getScale1() || vec3.squaredDistance(model.moveHandle.getOrigin(), model.firstHandle.getOrigin()) < model.moveHandle.getScale1() * model.moveHandle.getScale1()) {
model.lastHandle.setVisible(true);
publicAPI.invokeEndInteractionEvent();
if (publicAPI.getResetAfterPointPlacement()) {
publicAPI.reset();
} else {
publicAPI.loseFocus();
}
}
}
model._interactor.render();
}
} else if (model.activeState !== model.moveHandle) {
model.widgetState.deactivate();
}
model.freeHand = false;
model.draggedPoint = false;
model._isDragging = false;
return model.hasFocus ? macro.EVENT_ABORT : macro.VOID;
};
// --------------------------------------------------------------------------
// Mouse move: Drag selected handle / Handle follow the mouse
// --------------------------------------------------------------------------
publicAPI.handleMouseMove = callData => {
const manipulator = model.activeState?.getManipulator?.() ?? model.manipulator;
if (!manipulator || !model.activeState || !model.activeState.getActive() || !model.pickable) {
return macro.VOID;
}
const {
worldCoords,
worldDelta
} = manipulator.handleEvent(callData, model._apiSpecificRenderWindow);
const hoveredHandle = getHoveredHandle();
if (hoveredHandle) {
model.moveHandle.setVisible(false);
if (hoveredHandle !== model.firstHandle) {
model._apiSpecificRenderWindow.setCursor('grabbing');
}
} else if (!model._isDragging && model.hasFocus) {
model.moveHandle.setVisible(true);
model._apiSpecificRenderWindow.setCursor(model.defaultCursor);
}
if (model.lastHandle) {
model.lastHandle.setVisible(true);
}
const isHandleMoving = model._isDragging || model.activeState === model.moveHandle;
if (worldCoords.length && isHandleMoving) {
const curOrigin = model.activeState.getOrigin();
if (curOrigin) {
model.activeState.setOrigin(add(curOrigin, worldDelta, []));
} else {
model.activeState.setOrigin(worldCoords);
}
if (model._isDragging) {
model.draggedPoint = true;
}
if (model.freeHand && model.activeState === model.moveHandle) {
addPoint();
}
}
return model.hasFocus ? macro.EVENT_ABORT : macro.VOID;
};
// --------------------------------------------------------------------------
// Mofifier keys
// --------------------------------------------------------------------------
publicAPI.handleKeyDown = _ref2 => {
let {
key
} = _ref2;
model.keysDown[key] = true;
if (!model.hasFocus) {
return;
}
if (key === 'Enter') {
if (model.widgetState.getHandleList().length > 0) {
publicAPI.invokeEndInteractionEvent();
if (publicAPI.getResetAfterPointPlacement()) {
publicAPI.reset();
} else {
publicAPI.loseFocus();
}
}
} else if (key === 'Escape') {
publicAPI.reset();
publicAPI.loseFocus();
publicAPI.invokeEndInteractionEvent();
} else if (key === 'Delete' || key === 'Backspace') {
if (model.lastHandle) {
model.widgetState.removeHandle(model.lastHandle);
const handleList = model.widgetState.getHandleList();
model.lastHandle = handleList[handleList.length - 1];
}
}
};
// --------------------------------------------------------------------------
publicAPI.handleKeyUp = _ref3 => {
let {
key
} = _ref3;
model.keysDown[key] = false;
};
// --------------------------------------------------------------------------
// Focus API - modeHandle follow mouse when widget has focus
// --------------------------------------------------------------------------
publicAPI.grabFocus = () => {
if (!model.hasFocus) {
model.activeState = model.moveHandle;
model.activeState.activate();
model.activeState.setVisible(true);
model._interactor.requestAnimation(publicAPI);
updateHandlesSize();
}
model.hasFocus = true;
};
// --------------------------------------------------------------------------
publicAPI.loseFocus = () => {
if (model.hasFocus) {
model._interactor.cancelAnimation(publicAPI);
}
model.widgetState.deactivate();
model.moveHandle.deactivate();
model.moveHandle.setVisible(false);
model.activeState = null;
model._interactor.render();
model.hasFocus = false;
};
}
export { widgetBehavior as default };