fix: Set VTK viewport as active by interaction (#1139)

* fix: Set VTK viewport as active by interaction

* feat: listen for vtkscrollevent in wrapper component

* fix: definitions can skip empty storeContexts key

* hoc to set/pass in commandsManager

* Bump minimum react-vtkjs-viewport version to leverage new event

* Simplify to use onScroll event instead of passing down commandsManager to base component

* fix: make sure we include @JamesAPetts bug fix

Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
Rodrigo Antinarelli 2020-01-30 15:26:06 -03:00 committed by GitHub
parent c22756051b
commit 686d12da5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 133 additions and 22 deletions

View File

@ -49,7 +49,7 @@
"dependencies": {
"@babel/runtime": "^7.5.5",
"lodash.throttle": "^4.1.1",
"react-vtkjs-viewport": "^0.3.9"
"react-vtkjs-viewport": "^0.8.3"
},
"devDependencies": {
"@ohif/core": "^2.3.6",

View File

@ -1,6 +1,6 @@
import OHIF from '@ohif/core';
import { View2D } from 'react-vtkjs-viewport';
import { connect } from 'react-redux';
import VTKViewport from './VTKViewport';
const { setViewportActive, setViewportSpecificData } = OHIF.redux.actions;
@ -18,6 +18,7 @@ const mapStateToProps = (state, ownProps) => {
const pluginDetails = viewportLayout.vtk || {};
return {
activeViewportIndex: state.viewports.activeViewportIndex,
layout: state.viewports.layout,
isActive,
...pluginDetails,
@ -75,6 +76,6 @@ const ConnectedVTKViewport = connect(
mapStateToProps,
mapDispatchToProps,
mergeProps
)(View2D);
)(VTKViewport);
export default ConnectedVTKViewport;

View File

@ -77,6 +77,11 @@ class OHIFVTKViewport extends Component {
}),
viewportIndex: PropTypes.number,
children: PropTypes.node,
onScroll: PropTypes.func,
};
static defaultProps = {
onScroll: () => {},
};
static id = 'OHIFVTKViewport';
@ -386,6 +391,7 @@ class OHIFVTKViewport extends Component {
this.state.paintFilterBackgroundImageData
}
viewportIndex={this.props.viewportIndex}
onScroll={this.props.onScroll}
/>
)}
</div>

View File

@ -0,0 +1,3 @@
.vtk-viewport-handler svg {
pointer-events: none;
}

View File

@ -0,0 +1,58 @@
import React, { useEffect, useCallback } from 'react';
import { View2D } from 'react-vtkjs-viewport';
import PropTypes from 'prop-types';
import './VTKViewport.css';
const VTKViewport = props => {
const style = { width: '100%', height: '100%', position: 'relative' };
const setViewportActiveHandler = useCallback(() => {
const { setViewportActive, viewportIndex, activeViewportIndex } = props;
if (viewportIndex !== activeViewportIndex) {
// set in Connected
setViewportActive();
}
});
useEffect(() => {
const handleScrollEvent = evt => {
const vtkViewportApiReference = props.onScroll(props.viewportIndex) || {};
const viewportUid = vtkViewportApiReference.uid;
const viewportWasScrolled = viewportUid === evt.detail.uid;
if (viewportWasScrolled) {
setViewportActiveHandler();
}
};
window.addEventListener('vtkscrollevent', handleScrollEvent);
return () =>
window.removeEventListener('vtkscrollevent', handleScrollEvent);
}, [props, props.onScroll, props.viewportIndex, setViewportActiveHandler]);
return (
<div
className="vtk-viewport-handler"
style={style}
onClick={setViewportActiveHandler}
>
<View2D {...props} />
</div>
);
};
VTKViewport.propTypes = {
setViewportActive: PropTypes.func.isRequired,
viewportIndex: PropTypes.number.isRequired,
activeViewportIndex: PropTypes.number.isRequired,
/* Receives viewportIndex */
onScroll: PropTypes.func,
};
VTKViewport.defaultProps = {
onScroll: () => {},
};
export default VTKViewport;

View File

@ -103,6 +103,9 @@ const commandsModule = ({ commandsManager }) => {
}
const actions = {
getVtkApis: ({ index }) => {
return apis[index];
},
axial: async ({ viewports }) => {
const api = await _getActiveViewportVTKApi(viewports);
@ -266,11 +269,12 @@ const commandsModule = ({ commandsManager }) => {
'crosshairsWidget'
);
const uid = api.uid;
const istyle = vtkInteractorStyleMPRCrosshairs.newInstance();
api.setInteractorStyle({
istyle,
configuration: { apis, apiIndex },
configuration: { apis, apiIndex, uid },
});
});
},
@ -296,55 +300,45 @@ const commandsModule = ({ commandsManager }) => {
},
enableRotateTool: {
commandFn: actions.enableRotateTool,
storeContexts: [],
options: {},
},
enableCrosshairsTool: {
commandFn: actions.enableCrosshairsTool,
storeContexts: [],
options: {},
},
enableLevelTool: {
commandFn: actions.enableLevelTool,
storeContexts: [],
options: {},
},
setBlendModeToComposite: {
commandFn: actions.setBlendModeToComposite,
storeContexts: [],
options: { blendMode: BlendMode.COMPOSITE_BLEND },
},
setBlendModeToMaximumIntensity: {
commandFn: actions.setBlendModeToMaximumIntensity,
storeContexts: [],
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
},
setBlendModeToMinimumIntensity: {
commandFn: actions.setBlendMode,
storeContexts: [],
options: { blendMode: BlendMode.MINIMUM_INTENSITY_BLEND },
},
setBlendModeToAverageIntensity: {
commandFn: actions.setBlendMode,
storeContexts: [],
options: { blendMode: BlendMode.AVERAGE_INTENSITY_BLEND },
},
setSlabThickness: {
// TODO: How do we pass in a function argument?
commandFn: actions.setSlabThickness,
storeContexts: [],
options: {},
},
increaseSlabThickness: {
commandFn: actions.changeSlabThickness,
storeContexts: [],
options: {
change: 3,
},
},
decreaseSlabThickness: {
commandFn: actions.changeSlabThickness,
storeContexts: [],
options: {
change: -3,
},
@ -355,6 +349,10 @@ const commandsModule = ({ commandsManager }) => {
options: {},
context: 'VIEWER',
},
getVtkApiForViewportIndex: {
commandFn: actions.getVtkApis,
context: 'VIEWER',
},
};
return {

View File

@ -1,6 +1,7 @@
import asyncComponent from './asyncComponent.js';
import commandsModule from './commandsModule.js';
import toolbarModule from './toolbarModule.js';
import withCommandsManager from './withCommandsManager.js';
// This feels weird
// import loadLocales from './loadLocales';
@ -14,8 +15,8 @@ const vtkExtension = {
*/
id: 'vtk',
getViewportModule() {
return OHIFVTKViewport;
getViewportModule({ commandsManager }) {
return withCommandsManager(OHIFVTKViewport, commandsManager);
},
getToolbarModule() {
return toolbarModule;

View File

@ -0,0 +1,18 @@
import React from 'react';
export default function withCommandsManager(Component, commandsManager = {}) {
return class WithCommandsManager extends React.Component {
render() {
return (
<Component
{...this.props}
onScroll={viewportIndex =>
commandsManager.runCommand('getVtkApiForViewportIndex', {
index: viewportIndex,
})
}
/>
);
}
};
}

View File

@ -161,7 +161,7 @@ export class CommandsManager {
return;
}
const { commandFn, storeContexts } = definition;
const { commandFn, storeContexts = [] } = definition;
const definitionOptions = definition.options;
let commandParams = {};

View File

@ -1100,13 +1100,34 @@
pirates "^4.0.0"
source-map-support "^0.5.9"
"@babel/runtime@7.1.2", "@babel/runtime@7.5.5", "@babel/runtime@7.6.0", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.3":
"@babel/runtime@7.1.2":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.2.tgz#81c89935f4647706fc54541145e6b4ecfef4b8e3"
integrity sha512-Y3SCjmhSupzFB6wcv1KmmFucH6gDVnI30WjOcicV10ju0cZjak3Jcs67YLIXBrmZYw1xCrVeJPbycFwrqNyxpg==
dependencies:
regenerator-runtime "^0.12.0"
"@babel/runtime@7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205"
integrity sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/runtime@^7.6.0", "@babel/runtime@^7.6.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1"
integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==
dependencies:
regenerator-runtime "^0.13.2"
"@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6"
@ -15660,10 +15681,10 @@ react-transition-group@^4.1.1:
loose-envify "^1.4.0"
prop-types "^15.6.2"
react-vtkjs-viewport@^0.3.9:
version "0.3.9"
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.3.9.tgz#dc3dd5323c4cbaf5978cd64af2794b6b4ed61642"
integrity sha512-Sc3dRRz8tRSdUrdgL8tuYwVEl0CTjaZfDLqP5ufMXH2KjwBt3T5bjpk4xvzFyPc9CG6ywEX5MSa6eQ+NNjaUkw==
react-vtkjs-viewport@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.8.2.tgz#cdccf156cb089d32b935ebc3dc5f31213ba17bef"
integrity sha512-2OPbU5y4ay+E6qfZw4sW19uqfBnNw9kAF1PaZ/Sk5XMEEKnebplEof9ZZtE6nhPImFqMCfu4TXzYVHIAPmwFYA==
dependencies:
date-fns "^2.2.1"
gl-matrix "^3.1.0"
@ -16038,6 +16059,11 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==
regenerator-runtime@^0.13.1, regenerator-runtime@^0.13.2:
version "0.13.3"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5"