@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
295 lines (221 loc) • 9.39 kB
JavaScript
import macro from '../../macro.js';
import vtkInteractorStyleTrackballCamera from './InteractorStyleTrackballCamera.js';
import { r as radiansFromDegrees } from '../../Common/Core/Math/index.js';
import { States } from '../../Rendering/Core/InteractorStyle/Constants.js';
// vtkInteractorStyleImage methods
// ----------------------------------------------------------------------------
function vtkInteractorStyleImage(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkInteractorStyleImage'); // Public API methods
publicAPI.superHandleMouseMove = publicAPI.handleMouseMove;
publicAPI.handleMouseMove = function (callData) {
var pos = callData.position;
var renderer = callData.pokedRenderer;
switch (model.state) {
case States.IS_WINDOW_LEVEL:
publicAPI.windowLevel(renderer, pos);
publicAPI.invokeInteractionEvent({
type: 'InteractionEvent'
});
break;
case States.IS_SLICE:
publicAPI.slice(renderer, pos);
publicAPI.invokeInteractionEvent({
type: 'InteractionEvent'
});
break;
}
publicAPI.superHandleMouseMove(callData);
}; //----------------------------------------------------------------------------
publicAPI.superHandleLeftButtonPress = publicAPI.handleLeftButtonPress;
publicAPI.handleLeftButtonPress = function (callData) {
var pos = callData.position;
if (!callData.shiftKey && !callData.controlKey) {
model.windowLevelStartPosition[0] = pos.x;
model.windowLevelStartPosition[1] = pos.y; // Get the last (the topmost) image
publicAPI.setCurrentImageNumber(model.currentImageNumber);
var property = model.currentImageProperty;
if (property) {
model.windowLevelInitial[0] = property.getColorWindow();
model.windowLevelInitial[1] = property.getColorLevel();
}
publicAPI.startWindowLevel();
} else if (model.interactionMode === 'IMAGE3D' && callData.shiftKey) {
// If shift is held down, do a rotation
publicAPI.startRotate();
} else if (model.interactionMode === 'IMAGE_SLICING' && callData.controlKey) {
// If ctrl is held down in slicing mode, slice the image
model.lastSlicePosition = pos.y;
publicAPI.startSlice();
} else {
// The rest of the button + key combinations remain the same
publicAPI.superHandleLeftButtonPress(callData);
}
}; //--------------------------------------------------------------------------
publicAPI.superHandleLeftButtonRelease = publicAPI.handleLeftButtonRelease;
publicAPI.handleLeftButtonRelease = function () {
switch (model.state) {
case States.IS_WINDOW_LEVEL:
publicAPI.endWindowLevel();
break;
case States.IS_SLICE:
publicAPI.endSlice();
break;
default:
publicAPI.superHandleLeftButtonRelease();
break;
}
}; //--------------------------------------------------------------------------
publicAPI.handleStartMouseWheel = function (callData) {
publicAPI.startSlice();
publicAPI.handleMouseWheel(callData);
}; //--------------------------------------------------------------------------
publicAPI.handleEndMouseWheel = function () {
publicAPI.endSlice();
}; //--------------------------------------------------------------------------
publicAPI.handleMouseWheel = function (callData) {
var camera = callData.pokedRenderer.getActiveCamera();
var distance = camera.getDistance();
distance += callData.spinY; // clamp the distance to the clipping range
var range = camera.getClippingRange();
if (distance < range[0]) {
distance = range[0];
}
if (distance > range[1]) {
distance = range[1];
}
camera.setDistance(distance);
}; //----------------------------------------------------------------------------
publicAPI.windowLevel = function (renderer, position) {
model.windowLevelCurrentPosition[0] = position.x;
model.windowLevelCurrentPosition[1] = position.y;
var rwi = model.interactor;
if (model.currentImageProperty) {
var size = rwi.getView().getViewportSize(renderer);
var mWindow = model.windowLevelInitial[0];
var level = model.windowLevelInitial[1]; // Compute normalized delta
var dx = (model.windowLevelCurrentPosition[0] - model.windowLevelStartPosition[0]) * 4.0 / size[0];
var dy = (model.windowLevelStartPosition[1] - model.windowLevelCurrentPosition[1]) * 4.0 / size[1]; // Scale by current values
if (Math.abs(mWindow) > 0.01) {
dx *= mWindow;
} else {
dx *= mWindow < 0 ? -0.01 : 0.01;
}
if (Math.abs(level) > 0.01) {
dy *= level;
} else {
dy *= level < 0 ? -0.01 : 0.01;
} // Abs so that direction does not flip
if (mWindow < 0.0) {
dx *= -1;
}
if (level < 0.0) {
dy *= -1;
} // Compute new mWindow level
var newWindow = dx + mWindow;
var newLevel = level - dy;
if (newWindow < 0.01) {
newWindow = 0.01;
}
model.currentImageProperty.setColorWindow(newWindow);
model.currentImageProperty.setColorLevel(newLevel);
}
}; //----------------------------------------------------------------------------
publicAPI.slice = function (renderer, position) {
var rwi = model.interactor;
var dy = position.y - model.lastSlicePosition;
var camera = renderer.getActiveCamera();
var range = camera.getClippingRange();
var distance = camera.getDistance(); // scale the interaction by the height of the viewport
var viewportHeight = 0.0;
if (camera.getParallelProjection()) {
viewportHeight = camera.getParallelScale();
} else {
var angle = radiansFromDegrees(camera.getViewAngle());
viewportHeight = 2.0 * distance * Math.tan(0.5 * angle);
}
var size = rwi.getView().getViewportSize(renderer);
var delta = dy * viewportHeight / size[1];
distance += delta; // clamp the distance to the clipping range
if (distance < range[0]) {
distance = range[0] + viewportHeight * 1e-3;
}
if (distance > range[1]) {
distance = range[1] - viewportHeight * 1e-3;
}
camera.setDistance(distance);
model.lastSlicePosition = position.y;
}; //----------------------------------------------------------------------------
// This is a way of dealing with images as if they were layers.
// It looks through the renderer's list of props and sets the
// interactor ivars from the Nth image that it finds. You can
// also use negative numbers, i.e. -1 will return the last image,
// -2 will return the second-to-last image, etc.
publicAPI.setCurrentImageNumber = function (i) {
if (i === null) {
return;
}
var renderer = model.interactor.getCurrentRenderer();
if (!renderer) {
return;
}
model.currentImageNumber = i;
function propMatch(j, prop, targetIndex) {
if (prop.isA('vtkImageSlice') && j === targetIndex && prop.getPickable()) {
return true;
}
return false;
}
var props = renderer.getViewProps();
var targetIndex = i;
if (i < 0) {
targetIndex += props.length;
}
var imageProp = null;
var foundImageProp = false;
for (var j = 0; j < props.length && !foundImageProp; j++) {
if (propMatch(j, props[j], targetIndex)) {
foundImageProp = true;
imageProp = props[j];
}
}
if (imageProp) {
publicAPI.setCurrentImageProperty(imageProp.getProperty());
}
}; //----------------------------------------------------------------------------
publicAPI.setCurrentImageProperty = function (imageProperty) {
model.currentImageProperty = imageProperty;
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
windowLevelStartPosition: [0, 0],
windowLevelCurrentPosition: [0, 0],
lastSlicePosition: 0,
windowLevelInitial: [1.0, 0.5],
currentImageProperty: 0,
currentImageNumber: -1,
interactionMode: 'IMAGE2D',
xViewRightVector: [0, 1, 0],
xViewUpVector: [0, 0, -1],
yViewRightVector: [1, 0, 0],
yViewUpVector: [0, 0, -1],
zViewRightVector: [1, 0, 0],
zViewUpVector: [0, 1, 0]
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
vtkInteractorStyleTrackballCamera.extend(publicAPI, model, initialValues); // Create get-set macros
macro.setGet(publicAPI, model, ['interactionMode']); // For more macro methods, see "Sources/macro.js"
// Object specific methods
vtkInteractorStyleImage(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend, 'vtkInteractorStyleImage'); // ----------------------------------------------------------------------------
var vtkInteractorStyleImage$1 = {
newInstance: newInstance,
extend: extend
};
export default vtkInteractorStyleImage$1;
export { extend, newInstance };