diff --git a/Sources/Widgets/Widgets3D/AngleWidget/behavior.js b/Sources/Widgets/Widgets3D/AngleWidget/behavior.js deleted file mode 100644 index af93575f5cb..00000000000 --- a/Sources/Widgets/Widgets3D/AngleWidget/behavior.js +++ /dev/null @@ -1,164 +0,0 @@ -import macro from 'vtk.js/Sources/macros'; -import vtkPointPicker from 'vtk.js/Sources/Rendering/Core/PointPicker'; - -const MAX_POINTS = 3; - -export default function widgetBehavior(publicAPI, model) { - model.classHierarchy.push('vtkAngleWidgetProp'); - let isDragging = null; - - const picker = vtkPointPicker.newInstance(); - picker.setPickFromList(1); - - // -------------------------------------------------------------------------- - // Display 2D - // -------------------------------------------------------------------------- - - publicAPI.setDisplayCallback = (callback) => - model.representations[0].setDisplayCallback(callback); - - // -------------------------------------------------------------------------- - // Interactor events - // -------------------------------------------------------------------------- - - function ignoreKey(e) { - return e.altKey || e.controlKey || e.shiftKey; - } - - // -------------------------------------------------------------------------- - // Left press: Select handle to drag - // -------------------------------------------------------------------------- - - publicAPI.handleLeftButtonPress = (e) => { - if ( - !model.activeState || - !model.activeState.getActive() || - !model.pickable || - ignoreKey(e) - ) { - return macro.VOID; - } - - picker.initializePickList(); - picker.setPickList(publicAPI.getNestedProps()); - - if ( - model.activeState === model.widgetState.getMoveHandle() && - model.widgetState.getHandleList().length < MAX_POINTS - ) { - // Commit handle to location - const moveHandle = model.widgetState.getMoveHandle(); - const newHandle = model.widgetState.addHandle(); - newHandle.setOrigin(...moveHandle.getOrigin()); - newHandle.setColor(moveHandle.getColor()); - newHandle.setScale1(moveHandle.getScale1()); - } else { - isDragging = true; - model._apiSpecificRenderWindow.setCursor('grabbing'); - model._interactor.requestAnimation(publicAPI); - } - - publicAPI.invokeStartInteractionEvent(); - return macro.EVENT_ABORT; - }; - - // -------------------------------------------------------------------------- - // Mouse move: Drag selected handle / Handle follow the mouse - // -------------------------------------------------------------------------- - - publicAPI.handleMouseMove = (callData) => { - if ( - model.pickable && - model.dragable && - model.manipulator && - model.activeState && - model.activeState.getActive() && - !ignoreKey(callData) - ) { - model.manipulator.setOrigin(model.activeState.getOrigin()); - model.manipulator.setNormal(model._camera.getDirectionOfProjection()); - const worldCoords = model.manipulator.handleEvent( - callData, - model._apiSpecificRenderWindow - ); - - if ( - worldCoords.length && - (model.activeState === model.widgetState.getMoveHandle() || isDragging) - ) { - model.activeState.setOrigin(worldCoords); - publicAPI.invokeInteractionEvent(); - return macro.EVENT_ABORT; - } - } - if (model.hasFocus) { - model._widgetManager.disablePicking(); - } - return macro.VOID; - }; - - // -------------------------------------------------------------------------- - // Left release: Finish drag / Create new handle - // -------------------------------------------------------------------------- - - publicAPI.handleLeftButtonRelease = () => { - if (isDragging && model.pickable) { - model._apiSpecificRenderWindow.setCursor('pointer'); - model.widgetState.deactivate(); - model._interactor.cancelAnimation(publicAPI); - publicAPI.invokeEndInteractionEvent(); - } else if (model.activeState !== model.widgetState.getMoveHandle()) { - model.widgetState.deactivate(); - } - - if ( - (model.hasFocus && !model.activeState) || - (model.activeState && !model.activeState.getActive()) - ) { - publicAPI.invokeEndInteractionEvent(); - model._widgetManager.enablePicking(); - model._interactor.render(); - } - - // Don't make any more points - if (model.widgetState.getHandleList().length === MAX_POINTS) { - publicAPI.loseFocus(); - } - - isDragging = false; - }; - - // -------------------------------------------------------------------------- - // Focus API - modeHandle follow mouse when widget has focus - // -------------------------------------------------------------------------- - - publicAPI.grabFocus = () => { - if ( - !model.hasFocus && - model.widgetState.getHandleList().length < MAX_POINTS - ) { - model.activeState = model.widgetState.getMoveHandle(); - model.activeState.activate(); - model.activeState.setVisible(true); - model._interactor.requestAnimation(publicAPI); - publicAPI.invokeStartInteractionEvent(); - } - model.hasFocus = true; - }; - - // -------------------------------------------------------------------------- - - publicAPI.loseFocus = () => { - if (model.hasFocus) { - model._interactor.cancelAnimation(publicAPI); - publicAPI.invokeEndInteractionEvent(); - } - model.widgetState.deactivate(); - model.widgetState.getMoveHandle().deactivate(); - model.widgetState.getMoveHandle().setVisible(false); - model.activeState = null; - model.hasFocus = false; - model._widgetManager.enablePicking(); - model._interactor.render(); - }; -} diff --git a/Sources/Widgets/Widgets3D/AngleWidget/index.js b/Sources/Widgets/Widgets3D/AngleWidget/index.js index bda7fcde0f5..4d6ad9a507d 100644 --- a/Sources/Widgets/Widgets3D/AngleWidget/index.js +++ b/Sources/Widgets/Widgets3D/AngleWidget/index.js @@ -1,14 +1,7 @@ import macro from 'vtk.js/Sources/macros'; -import vtkAbstractWidgetFactory from 'vtk.js/Sources/Widgets/Core/AbstractWidgetFactory'; -import vtkPlanePointManipulator from 'vtk.js/Sources/Widgets/Manipulators/PlaneManipulator'; -import vtkPolyLineRepresentation from 'vtk.js/Sources/Widgets/Representations/PolyLineRepresentation'; -import vtkSphereHandleRepresentation from 'vtk.js/Sources/Widgets/Representations/SphereHandleRepresentation'; import * as vtkMath from 'vtk.js/Sources/Common/Core/Math'; -import widgetBehavior from 'vtk.js/Sources/Widgets/Widgets3D/AngleWidget/behavior'; -import stateGenerator from 'vtk.js/Sources/Widgets/Widgets3D/AngleWidget/state'; - -import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; +import vtkPolyLineWidget from 'vtk.js/Sources/Widgets/Widgets3D/PolyLineWidget'; // ---------------------------------------------------------------------------- // Factory @@ -17,36 +10,6 @@ import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; function vtkAngleWidget(publicAPI, model) { model.classHierarchy.push('vtkAngleWidget'); - // --- Widget Requirement --------------------------------------------------- - - model.methodsToLink = [ - 'activeScaleFactor', - 'activeColor', - 'useActiveColor', - 'glyphResolution', - 'defaultScale', - ]; - model.behavior = widgetBehavior; - model.widgetState = stateGenerator(); - - publicAPI.getRepresentationsForViewType = (viewType) => { - switch (viewType) { - case ViewTypes.DEFAULT: - case ViewTypes.GEOMETRY: - case ViewTypes.SLICE: - case ViewTypes.VOLUME: - default: - return [ - { builder: vtkSphereHandleRepresentation, labels: ['handles'] }, - { builder: vtkSphereHandleRepresentation, labels: ['moveHandle'] }, - { - builder: vtkPolyLineRepresentation, - labels: ['handles', 'moveHandle'], - }, - ]; - } - }; - // --- Public methods ------------------------------------------------------- // Returns angle in radians @@ -68,37 +31,21 @@ function vtkAngleWidget(publicAPI, model) { vtkMath.subtract(handles[2].getOrigin(), handles[1].getOrigin(), vec2); return vtkMath.angleBetweenVectors(vec1, vec2); }; - - // -------------------------------------------------------------------------- - // initialization - // -------------------------------------------------------------------------- - - model.widgetState.onBoundsChange((bounds) => { - const center = [ - (bounds[0] + bounds[1]) * 0.5, - (bounds[2] + bounds[3]) * 0.5, - (bounds[4] + bounds[5]) * 0.5, - ]; - model.widgetState.getMoveHandle().setOrigin(center); - }); - - // Default manipulator - model.manipulator = vtkPlanePointManipulator.newInstance(); } // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { - // manipulator: null, -}; +function defaultValues(initialValues) { + return { + maxPoints: 3, + ...initialValues, + }; +} // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); - - vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues); - macro.setGet(publicAPI, model, ['manipulator']); + vtkPolyLineWidget.extend(publicAPI, model, defaultValues(initialValues)); vtkAngleWidget(publicAPI, model); } diff --git a/Sources/Widgets/Widgets3D/AngleWidget/state.js b/Sources/Widgets/Widgets3D/AngleWidget/state.js deleted file mode 100644 index f3a70e87347..00000000000 --- a/Sources/Widgets/Widgets3D/AngleWidget/state.js +++ /dev/null @@ -1,24 +0,0 @@ -import vtkStateBuilder from 'vtk.js/Sources/Widgets/Core/StateBuilder'; - -export default function generateState() { - return vtkStateBuilder - .createBuilder() - .addStateFromMixin({ - labels: ['moveHandle'], - mixins: ['origin', 'color', 'scale1', 'visible'], - name: 'moveHandle', - initialValues: { - scale1: 0.1, - visible: false, - }, - }) - .addDynamicMixinState({ - labels: ['handles'], - mixins: ['origin', 'color', 'scale1', 'visible'], - name: 'handle', - initialValues: { - scale1: 0.1, - }, - }) - .build(); -} diff --git a/Sources/Widgets/Widgets3D/DistanceWidget/behavior.js b/Sources/Widgets/Widgets3D/DistanceWidget/behavior.js deleted file mode 100644 index f7db830928c..00000000000 --- a/Sources/Widgets/Widgets3D/DistanceWidget/behavior.js +++ /dev/null @@ -1,156 +0,0 @@ -import macro from 'vtk.js/Sources/macros'; - -const MAX_POINTS = 2; - -export default function widgetBehavior(publicAPI, model) { - model.classHierarchy.push('vtkDistanceWidgetProp'); - let isDragging = null; - - // -------------------------------------------------------------------------- - // Display 2D - // -------------------------------------------------------------------------- - - publicAPI.setDisplayCallback = (callback) => - model.representations[0].setDisplayCallback(callback); - - // -------------------------------------------------------------------------- - // Interactor events - // -------------------------------------------------------------------------- - - function ignoreKey(e) { - return e.altKey || e.controlKey || e.shiftKey; - } - - // -------------------------------------------------------------------------- - // Left press: Select handle to drag - // -------------------------------------------------------------------------- - - publicAPI.handleLeftButtonPress = (e) => { - if ( - !model.activeState || - !model.activeState.getActive() || - !model.pickable || - ignoreKey(e) - ) { - return macro.VOID; - } - - if ( - model.activeState === model.widgetState.getMoveHandle() && - model.widgetState.getHandleList().length < MAX_POINTS - ) { - // Commit handle to location - const moveHandle = model.widgetState.getMoveHandle(); - const newHandle = model.widgetState.addHandle(); - newHandle.setOrigin(...moveHandle.getOrigin()); - newHandle.setColor(moveHandle.getColor()); - newHandle.setScale1(moveHandle.getScale1()); - } else { - isDragging = true; - model._apiSpecificRenderWindow.setCursor('grabbing'); - model._interactor.requestAnimation(publicAPI); - } - - publicAPI.invokeStartInteractionEvent(); - return macro.EVENT_ABORT; - }; - - // -------------------------------------------------------------------------- - // Mouse move: Drag selected handle / Handle follow the mouse - // -------------------------------------------------------------------------- - - publicAPI.handleMouseMove = (callData) => { - if ( - model.hasFocus && - model.widgetState.getHandleList().length === MAX_POINTS - ) { - publicAPI.loseFocus(); - return macro.VOID; - } - - if ( - model.pickable && - model.dragable && - model.manipulator && - model.activeState && - model.activeState.getActive() && - !ignoreKey(callData) - ) { - const worldCoords = model.manipulator.handleEvent( - callData, - model._apiSpecificRenderWindow - ); - - if ( - worldCoords.length && - (model.activeState === model.widgetState.getMoveHandle() || isDragging) - ) { - model.activeState.setOrigin(worldCoords); - publicAPI.invokeInteractionEvent(); - return macro.EVENT_ABORT; - } - } - - return macro.VOID; - }; - - // -------------------------------------------------------------------------- - // Left release: Finish drag / Create new handle - // -------------------------------------------------------------------------- - - publicAPI.handleLeftButtonRelease = () => { - if (isDragging && model.pickable) { - model._apiSpecificRenderWindow.setCursor('pointer'); - model.widgetState.deactivate(); - model._interactor.cancelAnimation(publicAPI); - publicAPI.invokeEndInteractionEvent(); - } else if (model.activeState !== model.widgetState.getMoveHandle()) { - model.widgetState.deactivate(); - } - - if ( - (model.hasFocus && !model.activeState) || - (model.activeState && !model.activeState.getActive()) - ) { - publicAPI.invokeEndInteractionEvent(); - model._widgetManager.enablePicking(); - model._interactor.render(); - } - - isDragging = false; - }; - - // -------------------------------------------------------------------------- - // Focus API - modeHandle follow mouse when widget has focus - // -------------------------------------------------------------------------- - - publicAPI.grabFocus = () => { - if ( - !model.hasFocus && - model.widgetState.getHandleList().length < MAX_POINTS - ) { - model.activeState = model.widgetState.getMoveHandle(); - model.activeState.activate(); - model.activeState.setVisible(true); - model._interactor.requestAnimation(publicAPI); - publicAPI.invokeStartInteractionEvent(); - } - model.hasFocus = true; - }; - - // -------------------------------------------------------------------------- - - publicAPI.loseFocus = () => { - if (model.hasFocus) { - model._interactor.cancelAnimation(publicAPI); - publicAPI.invokeEndInteractionEvent(); - } - model.widgetState.deactivate(); - model.widgetState.getMoveHandle().deactivate(); - model.widgetState.getMoveHandle().setVisible(false); - model.activeState = null; - model.hasFocus = false; - model._widgetManager.enablePicking(); - model._interactor.render(); - }; -} diff --git a/Sources/Widgets/Widgets3D/DistanceWidget/example/index.js b/Sources/Widgets/Widgets3D/DistanceWidget/example/index.js index f38fb7b75d4..4010e4c811e 100644 --- a/Sources/Widgets/Widgets3D/DistanceWidget/example/index.js +++ b/Sources/Widgets/Widgets3D/DistanceWidget/example/index.js @@ -54,7 +54,6 @@ widgetManager.enablePicking(); fullScreenRenderer.addController(controlPanel); widget.getWidgetState().onModified(() => { - console.log(widget.getDistance()); document.querySelector('#distance').innerText = widget.getDistance(); }); diff --git a/Sources/Widgets/Widgets3D/DistanceWidget/index.js b/Sources/Widgets/Widgets3D/DistanceWidget/index.js index 18230fbb1ce..cabd9df3056 100644 --- a/Sources/Widgets/Widgets3D/DistanceWidget/index.js +++ b/Sources/Widgets/Widgets3D/DistanceWidget/index.js @@ -1,14 +1,7 @@ import macro from 'vtk.js/Sources/macros'; -import vtkAbstractWidgetFactory from 'vtk.js/Sources/Widgets/Core/AbstractWidgetFactory'; -import vtkPlanePointManipulator from 'vtk.js/Sources/Widgets/Manipulators/PlaneManipulator'; -import vtkPolyLineRepresentation from 'vtk.js/Sources/Widgets/Representations/PolyLineRepresentation'; -import vtkSphereHandleRepresentation from 'vtk.js/Sources/Widgets/Representations/SphereHandleRepresentation'; import { distance2BetweenPoints } from 'vtk.js/Sources/Common/Core/Math'; -import widgetBehavior from 'vtk.js/Sources/Widgets/Widgets3D/DistanceWidget/behavior'; -import stateGenerator from 'vtk.js/Sources/Widgets/Widgets3D/DistanceWidget/state'; - -import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; +import vtkPolyLineWidget from 'vtk.js/Sources/Widgets/Widgets3D/PolyLineWidget'; // ---------------------------------------------------------------------------- // Factory @@ -17,36 +10,6 @@ import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; function vtkDistanceWidget(publicAPI, model) { model.classHierarchy.push('vtkDistanceWidget'); - // --- Widget Requirement --------------------------------------------------- - - model.methodsToLink = [ - 'activeScaleFactor', - 'activeColor', - 'useActiveColor', - 'glyphResolution', - 'defaultScale', - ]; - model.behavior = widgetBehavior; - model.widgetState = stateGenerator(); - - publicAPI.getRepresentationsForViewType = (viewType) => { - switch (viewType) { - case ViewTypes.DEFAULT: - case ViewTypes.GEOMETRY: - case ViewTypes.SLICE: - case ViewTypes.VOLUME: - default: - return [ - { builder: vtkSphereHandleRepresentation, labels: ['handles'] }, - { builder: vtkSphereHandleRepresentation, labels: ['moveHandle'] }, - { - builder: vtkPolyLineRepresentation, - labels: ['handles', 'moveHandle'], - }, - ]; - } - }; - // --- Public methods ------------------------------------------------------- publicAPI.getDistance = () => { @@ -61,37 +24,21 @@ function vtkDistanceWidget(publicAPI, model) { distance2BetweenPoints(handles[0].getOrigin(), handles[1].getOrigin()) ); }; - - // -------------------------------------------------------------------------- - // initialization - // -------------------------------------------------------------------------- - - model.widgetState.onBoundsChange((bounds) => { - const center = [ - (bounds[0] + bounds[1]) * 0.5, - (bounds[2] + bounds[3]) * 0.5, - (bounds[4] + bounds[5]) * 0.5, - ]; - model.widgetState.getMoveHandle().setOrigin(center); - }); - - // Default manipulator - model.manipulator = vtkPlanePointManipulator.newInstance(); } // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { - // manipulator: null, -}; +function defaultValues(initialValues) { + return { + maxPoints: 2, + ...initialValues, + }; +} // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); - - vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues); - macro.setGet(publicAPI, model, ['manipulator']); + vtkPolyLineWidget.extend(publicAPI, model, defaultValues(initialValues)); vtkDistanceWidget(publicAPI, model); } diff --git a/Sources/Widgets/Widgets3D/DistanceWidget/state.js b/Sources/Widgets/Widgets3D/DistanceWidget/state.js deleted file mode 100644 index f3a70e87347..00000000000 --- a/Sources/Widgets/Widgets3D/DistanceWidget/state.js +++ /dev/null @@ -1,24 +0,0 @@ -import vtkStateBuilder from 'vtk.js/Sources/Widgets/Core/StateBuilder'; - -export default function generateState() { - return vtkStateBuilder - .createBuilder() - .addStateFromMixin({ - labels: ['moveHandle'], - mixins: ['origin', 'color', 'scale1', 'visible'], - name: 'moveHandle', - initialValues: { - scale1: 0.1, - visible: false, - }, - }) - .addDynamicMixinState({ - labels: ['handles'], - mixins: ['origin', 'color', 'scale1', 'visible'], - name: 'handle', - initialValues: { - scale1: 0.1, - }, - }) - .build(); -} diff --git a/Sources/Widgets/Widgets3D/PolyLineWidget/behavior.js b/Sources/Widgets/Widgets3D/PolyLineWidget/behavior.js index f98cc06228e..f2caf433d02 100644 --- a/Sources/Widgets/Widgets3D/PolyLineWidget/behavior.js +++ b/Sources/Widgets/Widgets3D/PolyLineWidget/behavior.js @@ -4,6 +4,8 @@ export default function widgetBehavior(publicAPI, model) { model.classHierarchy.push('vtkPolyLineWidgetProp'); let isDragging = null; + model.getMaxPoints = model._factory.getMaxPoints; + // -------------------------------------------------------------------------- // Display 2D // -------------------------------------------------------------------------- @@ -38,6 +40,12 @@ export default function widgetBehavior(publicAPI, model) { return macro.VOID; } + function canPlacePoints() { + return model.getMaxPoints() + ? model.widgetState.getHandleList().length < model.getMaxPoints() + : true; + } + // -------------------------------------------------------------------------- // Right click: Delete handle // -------------------------------------------------------------------------- @@ -80,7 +88,10 @@ export default function widgetBehavior(publicAPI, model) { return macro.VOID; } - if (model.activeState === model.widgetState.getMoveHandle()) { + if ( + model.activeState === model.widgetState.getMoveHandle() && + canPlacePoints() + ) { updateMoveHandle(e); // Commit handle to location const moveHandle = model.widgetState.getMoveHandle(); @@ -144,6 +155,11 @@ export default function widgetBehavior(publicAPI, model) { model._interactor.render(); } + // Don't make any more points + if (!canPlacePoints()) { + publicAPI.loseFocus(); + } + isDragging = false; }; @@ -162,7 +178,7 @@ export default function widgetBehavior(publicAPI, model) { // -------------------------------------------------------------------------- publicAPI.grabFocus = () => { - if (!model.hasFocus) { + if (!model.hasFocus && canPlacePoints()) { model.activeState = model.widgetState.getMoveHandle(); model.activeState.activate(); model.activeState.setVisible(true); diff --git a/Sources/Widgets/Widgets3D/PolyLineWidget/example/controlPanel.html b/Sources/Widgets/Widgets3D/PolyLineWidget/example/controlPanel.html index 4ed460c0d4f..64933d55134 100644 --- a/Sources/Widgets/Widgets3D/PolyLineWidget/example/controlPanel.html +++ b/Sources/Widgets/Widgets3D/PolyLineWidget/example/controlPanel.html @@ -1,2 +1,2 @@ -Show SVG layer +Show SVG layer diff --git a/Sources/Widgets/Widgets3D/PolyLineWidget/index.js b/Sources/Widgets/Widgets3D/PolyLineWidget/index.js index 6dd976f0cf7..7e46272aef3 100644 --- a/Sources/Widgets/Widgets3D/PolyLineWidget/index.js +++ b/Sources/Widgets/Widgets3D/PolyLineWidget/index.js @@ -91,17 +91,20 @@ function vtkPolyLineWidget(publicAPI, model) { // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { - // manipulator: null, -}; +function defaultValues(initialValues) { + return { + // maxPoints: 0, + ...initialValues, + }; +} // ---------------------------------------------------------------------------- export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); + Object.assign(model, defaultValues(initialValues)); vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues); - macro.setGet(publicAPI, model, ['manipulator']); + macro.setGet(publicAPI, model, ['manipulator', 'maxPoints']); vtkPolyLineWidget(publicAPI, model); }