Skip to content

Commit

Permalink
fix(toolbox): Preserve user-specified tool state and streamline comma…
Browse files Browse the repository at this point in the history
…nd execution (OHIF#4063)
  • Loading branch information
sedghi authored and WillianVarela committed Apr 30, 2024
1 parent dfff1f5 commit e7d25c5
Show file tree
Hide file tree
Showing 34 changed files with 332 additions and 181 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ provided by the <a href="https://ohif.org/">Open Health Imaging Foundation (OHIF
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-volume-rendering.webp?raw=true" alt="Volume Rendering" width="350"/> | Volume Rendering | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.25403.345050719074.3824.20170125095438.5&hangingprotocolId=mprAnd3DVolumeViewport) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-pdf.webp?raw=true" alt="PDF" width="350"/> | PDF | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.317377619501274872606137091638706705333) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-rtstruct.webp?raw=true" alt="RTSTRUCT" width="350"/> | RT STRUCT | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=1.3.6.1.4.1.5962.99.1.2968617883.1314880426.1493322302363.3.0) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4D.webp?raw=true" alt="4D" width="350"/> | 4D | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-4d.webp?raw=true" alt="4D" width="350"/> | 4D | [Demo](https://viewer.ohif.org/dynamic-volume?StudyInstanceUIDs=2.25.232704420736447710317909004159492840763) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/demo-video.webp?raw=true" alt="VIDEO" width="350"/> | Video | [Demo](https://viewer.ohif.org/viewer?StudyInstanceUIDs=2.25.96975534054447904995905761963464388233) |
| <img src="https://github.com/OHIF/Viewers/blob/master/platform/docs/docs/assets/img/microscopy.webp?raw=true" alt="microscopy" width="350"/> | Slide Microscopy | [Demo](https://viewer.ohif.org/microscopy?StudyInstanceUIDs=2.25.141277760791347900862109212450152067508) |

Expand Down
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-seg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.13",
"@cornerstonejs/core": "^1.70.13",
"@kitware/vtk.js": "30.3.3",
"@cornerstonejs/adapters": "^1.70.14",
"@cornerstonejs/core": "^1.70.14",
"@kitware/vtk.js": "30.4.1",
"react-color": "^2.19.3"
}
}
30 changes: 9 additions & 21 deletions extensions/cornerstone-dicom-seg/src/getToolbarModule.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export function getToolbarModule({ commandsManager, servicesManager }) {
const { segmentationService, toolGroupService } = servicesManager.services;
export function getToolbarModule({ servicesManager }) {
const { segmentationService, toolbarService, toolGroupService } = servicesManager.services;
return [
{
name: 'evaluate.cornerstone.segmentation',
Expand All @@ -20,12 +20,16 @@ export function getToolbarModule({ commandsManager, servicesManager }) {
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);

if (!toolGroup) {
return;
return {
disabled: true,
className: '!text-common-bright ohif-disabled',
disabledText: disabledText ?? 'Not available on the current viewport',
};
}

const toolName = getToolNameForButton(button);
const toolName = toolbarService.getToolNameForButton(button);

if (!toolGroup || !toolGroup.hasTool(toolName)) {
if (!toolGroup.hasTool(toolName) && !toolNames) {
return {
disabled: true,
className: '!text-common-bright ohif-disabled',
Expand All @@ -51,19 +55,3 @@ export function getToolbarModule({ commandsManager, servicesManager }) {
},
];
}

// Todo: this is duplicate, we should move it to a shared location
function getToolNameForButton(button) {
const { props } = button;

const commands = props?.commands || button.commands;
const commandsArray = Array.isArray(commands) ? commands : [commands];
const firstCommand = commandsArray[0];

if (firstCommand?.commandOptions) {
return firstCommand.commandOptions.toolName ?? props?.id ?? button.id;
}

// use id as a fallback for toolName
return props?.id ?? button.id;
}
6 changes: 3 additions & 3 deletions extensions/cornerstone-dicom-sr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.13",
"@cornerstonejs/core": "^1.70.13",
"@cornerstonejs/tools": "^1.70.13",
"@cornerstonejs/adapters": "^1.70.14",
"@cornerstonejs/core": "^1.70.14",
"@cornerstonejs/tools": "^1.70.14",
"classnames": "^2.3.2"
}
}
6 changes: 3 additions & 3 deletions extensions/cornerstone-dynamic-volume/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^1.70.13",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.13",
"@cornerstonejs/tools": "^1.70.13",
"@cornerstonejs/core": "^1.70.14",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.14",
"@cornerstonejs/tools": "^1.70.14",
"classnames": "^2.3.2"
}
}
12 changes: 6 additions & 6 deletions extensions/cornerstone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.70.13",
"@cornerstonejs/dicom-image-loader": "^1.70.14",
"@icr/polyseg-wasm": "^0.4.0",
"@ohif/core": "3.8.0-beta.92",
"@ohif/ui": "3.8.0-beta.92",
Expand All @@ -55,12 +55,12 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.70.13",
"@cornerstonejs/core": "^1.70.13",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.13",
"@cornerstonejs/tools": "^1.70.13",
"@cornerstonejs/adapters": "^1.70.14",
"@cornerstonejs/core": "^1.70.14",
"@cornerstonejs/streaming-image-volume-loader": "^1.70.14",
"@cornerstonejs/tools": "^1.70.14",
"@icr/polyseg-wasm": "^0.4.0",
"@kitware/vtk.js": "30.3.3",
"@kitware/vtk.js": "30.4.1",
"html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8",
"lodash.merge": "^4.6.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,10 @@ function _subscribeToJumpToMeasurementEvents(
cornerstoneViewportService.getViewportIdToJump(
jumpId,
measurement.displaySetInstanceUID,
{ referencedImageId: measurement.referencedImageId }
{
referencedImageId:
measurement.referencedImageId || measurement.metadata?.referencedImageId,
}
);
}
if (cacheJumpToMeasurementEvent.cornerstoneViewport !== viewportId) {
Expand Down Expand Up @@ -594,6 +597,9 @@ function _jumpToMeasurement(
i => i.SOPInstanceUID === SOPInstanceUID
);

// the index is reversed in the volume viewport
// imageIdIndex = referencedDisplaySet.images.length - 1 - imageIdIndex;

const { viewPlaneNormal: viewportViewPlane } = viewport.getCamera();

// should compare abs for both planes since the direction can be flipped
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function CornerstoneImageScrollbar({

if (isCineEnabled) {
// on image scrollbar change, stop the CINE if it is playing
cineService.stopClip(element);
cineService.stopClip(element, { viewportId });
cineService.setCine({ id: viewportId, isPlaying: false });
}

Expand Down
12 changes: 10 additions & 2 deletions extensions/cornerstone/src/components/CinePlayer/CinePlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
}
cineService.setCine({ id: viewportId, isPlaying, frameRate });
setNewStackFrameRate(frameRate);
}, [displaySetService, viewportId, viewportGridService, cines, isCineEnabled]);
}, [displaySetService, viewportId, viewportGridService, cines, isCineEnabled, enabledVPElement]);

useEffect(() => {
isMountedRef.current = true;
Expand All @@ -78,6 +78,14 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
};
}, [isCineEnabled, newDisplaySetHandler]);

useEffect(() => {
if (!isCineEnabled) {
return;
}

cineHandler();
}, [isCineEnabled, cineHandler, enabledVPElement]);

/**
* Use effect for handling new display set
*/
Expand Down Expand Up @@ -112,7 +120,7 @@ function WrappedCinePlayer({ enabledVPElement, viewportId, servicesManager }) {
cineHandler();

return () => {
cineService.stopClip(enabledVPElement);
cineService.stopClip(enabledVPElement, { viewportId });
};
}, [cines, viewportId, cineService, enabledVPElement, cineHandler]);

Expand Down
42 changes: 19 additions & 23 deletions extensions/cornerstone/src/getToolbarModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const getToggledClassName = (isToggled: boolean) => {
export default function getToolbarModule({ commandsManager, servicesManager }) {
const {
toolGroupService,
toolbarService,
syncGroupService,
cornerstoneViewportService,
hangingProtocolService,
Expand All @@ -21,24 +22,26 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
// enabled or not
{
name: 'evaluate.cornerstoneTool',
evaluate: ({ viewportId, button, disabledText }) => {
evaluate: ({ viewportId, button, toolNames, disabledText }) => {
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);

if (!toolGroup) {
return;
}

const toolName = getToolNameForButton(button);
const toolName = toolbarService.getToolNameForButton(button);

if (!toolGroup || !toolGroup.hasTool(toolName)) {
if (!toolGroup || (!toolGroup.hasTool(toolName) && !toolNames)) {
return {
disabled: true,
className: '!text-common-bright ohif-disabled',
disabledText: disabledText ?? 'Not available on the current viewport',
};
}

const isPrimaryActive = toolGroup.getActivePrimaryMouseButtonTool() === toolName;
const isPrimaryActive = toolNames
? toolNames.includes(toolGroup.getActivePrimaryMouseButtonTool())
: toolGroup.getActivePrimaryMouseButtonTool() === toolName;

return {
disabled: false,
Expand Down Expand Up @@ -71,7 +74,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
// check if the active toolName is part of the items then we need
// to move it to the primary button
const activeToolIndex = items.findIndex(item => {
const toolName = getToolNameForButton(item);
const toolName = toolbarService.getToolNameForButton(item);
return toolName === activeToolName;
});

Expand Down Expand Up @@ -114,6 +117,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
_evaluateToggle({
viewportId,
button,
toolbarService,
disabledText,
offModes: [Enums.ToolModes.Disabled],
toolGroupService,
Expand All @@ -125,6 +129,7 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
_evaluateToggle({
viewportId,
button,
toolbarService,
disabledText,
offModes: [Enums.ToolModes.Disabled, Enums.ToolModes.Passive],
toolGroupService,
Expand Down Expand Up @@ -267,13 +272,20 @@ export default function getToolbarModule({ commandsManager, servicesManager }) {
];
}

function _evaluateToggle({ viewportId, button, disabledText, offModes, toolGroupService }) {
function _evaluateToggle({
viewportId,
toolbarService,
button,
disabledText,
offModes,
toolGroupService,
}) {
const toolGroup = toolGroupService.getToolGroupForViewport(viewportId);

if (!toolGroup) {
return;
}
const toolName = getToolNameForButton(button);
const toolName = toolbarService.getToolNameForButton(button);

if (!toolGroup.hasTool(toolName)) {
return {
Expand All @@ -289,19 +301,3 @@ function _evaluateToggle({ viewportId, button, disabledText, offModes, toolGroup
className: getToggledClassName(!isOff),
};
}

// Todo: this is duplicate, we should move it to a shared location
function getToolNameForButton(button) {
const { props } = button;

const commands = props?.commands || button.commands;
const commandsArray = Array.isArray(commands) ? commands : [commands];
const firstCommand = commandsArray[0];

if (firstCommand?.commandOptions) {
return firstCommand.commandOptions.toolName ?? props?.id ?? button.id;
}

// use id as a fallback for toolName
return props?.id ?? button.id;
}
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
cameraProps: unknown
): string {
const viewportInfo = this.getViewportInfo(activeViewportId);

if (viewportInfo.getViewportType() === csEnums.ViewportType.VOLUME_3D) {
return null;
}

const { referencedImageId } = cameraProps;
if (viewportInfo?.contains(displaySetInstanceUID, referencedImageId)) {
return activeViewportId;
Expand Down
47 changes: 40 additions & 7 deletions extensions/cornerstone/src/services/ViewportService/Viewport.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Types, Enums } from '@cornerstonejs/core';
import {
Types,
Enums,
getEnabledElementByViewportId,
VolumeViewport,
utilities,
} from '@cornerstonejs/core';
import { Types as CoreTypes } from '@ohif/core';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
Expand Down Expand Up @@ -89,13 +95,30 @@ const DEFAULT_TOOLGROUP_ID = 'default';

// Return true if the data contains the given display set UID OR the imageId
// if it is a composite object.
const dataContains = (data, displaySetUID: string, imageId?: string): boolean => {
if (data.displaySetInstanceUID === displaySetUID) {
return true;
}
const dataContains = ({ data, displaySetUID, imageId, viewport }): boolean => {
if (imageId && data.isCompositeStack && data.imageIds) {
return !!data.imageIds.find(dataId => dataId === imageId);
}

if (imageId && (data.volumeId || viewport instanceof VolumeViewport)) {
const isAcquisition = !!viewport.getCurrentImageId();

if (!isAcquisition) {
return false;
}

const imageURI = utilities.imageIdToURI(imageId);
const hasImageId = viewport.hasImageURI(imageURI);

if (hasImageId) {
return true;
}
}

if (data.displaySetInstanceUID === displaySetUID) {
return true;
}

return false;
};

Expand All @@ -122,10 +145,20 @@ class ViewportInfo {
return false;
}

const { viewport } = getEnabledElementByViewportId(this.viewportId) || {};

if (this.viewportData.data.length) {
return !!this.viewportData.data.find(data => dataContains(data, displaySetUID, imageId));
return !!this.viewportData.data.find(data =>
dataContains({ data, displaySetUID, imageId, viewport })
);
}
return dataContains(this.viewportData.data, displaySetUID, imageId);

return dataContains({
data: this.viewportData.data,
displaySetUID,
imageId,
viewport,
});
}

public destroy = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function getMappedAnnotations(annotation, DisplaySetService) {
unit: modalityUnit,
mean,
stdDev,
metadata,
max,
area,
areaUnit,
Expand Down
4 changes: 2 additions & 2 deletions extensions/measurement-tracking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^1.70.13",
"@cornerstonejs/tools": "^1.70.13",
"@cornerstonejs/core": "^1.70.14",
"@cornerstonejs/tools": "^1.70.14",
"@ohif/core": "3.8.0-beta.92",
"@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.92",
"@ohif/ui": "3.8.0-beta.92",
Expand Down
Loading

0 comments on commit e7d25c5

Please sign in to comment.