fix: Measurement Tracking: Various UI and functionality improvements (#4481)

This commit is contained in:
Alireza authored and GitHub committed 2024-11-12 13:14:47 -05:00
1 parent 4a125236dd
commit 62b2748847
25 files changed
+117 -126

No files matched your search

@@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.2.1",
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/adapters": "^2.2.3",
"@cornerstonejs/core": "^2.2.3",
"@kitware/vtk.js": "32.1.0",
"react-color": "^2.19.3"
}
@@ -46,8 +46,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.2.1",
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/adapters": "^2.2.3",
"@cornerstonejs/core": "^2.2.3",
"@kitware/vtk.js": "32.1.0",
"react-color": "^2.19.3"
}
+3 -3
View File
@@ -46,9 +46,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.2.1",
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/tools": "^2.2.1",
"@cornerstonejs/adapters": "^2.2.3",
"@cornerstonejs/core": "^2.2.3",
"@cornerstonejs/tools": "^2.2.3",
"classnames": "^2.3.2"
}
}
@@ -42,8 +42,8 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/tools": "^2.2.1",
"@cornerstonejs/core": "^2.2.3",
"@cornerstonejs/tools": "^2.2.3",
"classnames": "^2.3.2"
}
}
+4 -4
View File
@@ -38,7 +38,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.4",
"@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^2.2.1",
"@cornerstonejs/dicom-image-loader": "^2.2.3",
"@icr/polyseg-wasm": "^0.4.0",
"@ohif/core": "3.9.0-beta.110",
"@ohif/ui": "3.9.0-beta.110",
@@ -55,9 +55,9 @@
},
"dependencies": {
"@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^2.2.1",
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/tools": "^2.2.1",
"@cornerstonejs/adapters": "^2.2.3",
"@cornerstonejs/core": "^2.2.3",
"@cornerstonejs/tools": "^2.2.3",
"@icr/polyseg-wasm": "^0.4.0",
"@kitware/vtk.js": "32.1.0",
"html2canvas": "^1.4.1",
@@ -3,6 +3,7 @@ import React from 'react';
import { Toolbox } from '@ohif/ui-next';
import PanelSegmentation from './panels/PanelSegmentation';
import ActiveViewportWindowLevel from './components/ActiveViewportWindowLevel';
import PanelMeasurementTable from './panels/PanelMeasurement';
const getPanelModule = ({ commandsManager, servicesManager, extensionManager }: withAppTypes) => {
const wrappedPanelSegmentation = ({ configuration }) => {
@@ -56,6 +57,19 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
);
};
const wrappedPanelMeasurement = ({ configuration }) => {
return (
<PanelMeasurementTable
commandsManager={commandsManager}
servicesManager={servicesManager}
extensionManager={extensionManager}
configuration={{
...configuration,
}}
/>
);
};
return [
{
name: 'activeViewportWindowLevel',
@@ -63,6 +77,13 @@ const getPanelModule = ({ commandsManager, servicesManager, extensionManager }:
return <ActiveViewportWindowLevel servicesManager={servicesManager} />;
},
},
{
name: 'panelMeasurement',
iconName: 'tab-linear',
iconLabel: 'Measure',
label: 'Measurement',
component: wrappedPanelMeasurement,
},
{
name: 'panelSegmentation',
iconName: 'tab-segmentation',
@@ -330,6 +330,9 @@ const connectMeasurementServiceToTools = (measurementService, cornerstoneViewpor
}
removeAnnotation(uid);
}
// trigger a render
cornerstoneViewportService.getRenderingEngine().render();
});
measurementService.subscribe(
@@ -148,6 +148,11 @@ export default class SyncGroupService {
const { type, target = true, source = true, options = {}, id = type } = syncGroupObj;
const synchronizer = this._getOrCreateSynchronizer(type, id, options);
if (!synchronizer) {
return;
}
synchronizer.setOptions(viewportId, options);
const viewportInfo = { viewportId, renderingEngineId };
@@ -763,9 +763,11 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
});
}
if (!volumesNotLoaded.length) {
return;
}
// It's crucial not to return here because the volume may be loaded,
// but the viewport also needs to set the volume.
// if (!volumesNotLoaded.length) {
// return;
// }
// This returns the async continuation only
return this.setVolumesForViewport(viewport, volumeInputArray, presentations);
@@ -19,7 +19,18 @@ function PanelStudyBrowserHeader({
<div className="bg-muted flex h-[40px] select-none rounded-t p-2">
<div className={'flex h-[24px] w-full select-none justify-center self-center text-[14px]'}>
<div className="flex w-full items-center gap-[10px]">
<div className="flex h-full items-center justify-center">
<div className="flex items-center justify-center">
<div className="text-primary-active flex items-center space-x-1">
{actionIcons.map((icon: actionIcon, index) =>
React.createElement(Icons[icon.iconName] || Icons.MissingIcon, {
key: index,
onClick: () => updateActionIconValue(icon),
className: `cursor-pointer`,
})
)}
</div>
</div>
<div className="ml-auto flex h-full items-center justify-center">
<ToggleGroup
type="single"
value={viewPresets.filter(preset => preset.selected)[0].id}
@@ -40,18 +51,6 @@ function PanelStudyBrowserHeader({
))}
</ToggleGroup>
</div>
<div className="flex items-center justify-center">
<div className="text-primary-active flex items-center space-x-1">
{actionIcons.map((icon: actionIcon, index) =>
React.createElement(Icons[icon.iconName] || Icons.MissingIcon, {
key: index,
onClick: () => updateActionIconValue(icon),
className: `cursor-pointer`,
})
)}
</div>
</div>
</div>
</div>
</div>
+2
View File
@@ -35,6 +35,7 @@ import colorPickerDialog from './utils/colorPickerDialog';
import promptSaveReport from './utils/promptSaveReport';
import promptLabelAnnotation from './utils/promptLabelAnnotation';
import usePatientInfo from './hooks/usePatientInfo';
import { PanelStudyBrowserHeader } from './Panels/StudyBrowser/PanelStudyBrowserHeader';
import * as utils from './utils';
const defaultExtension: Types.Extensions.Extension = {
@@ -99,5 +100,6 @@ export {
promptLabelAnnotation,
colorPickerDialog,
usePatientInfo,
PanelStudyBrowserHeader,
utils,
};
+2 -2
View File
@@ -32,8 +32,8 @@
"start": "yarn run dev"
},
"peerDependencies": {
"@cornerstonejs/core": "^2.2.1",
"@cornerstonejs/tools": "^2.2.1",
"@cornerstonejs/core": "^2.2.3",
"@cornerstonejs/tools": "^2.2.3",
"@ohif/core": "3.9.0-beta.110",
"@ohif/extension-cornerstone-dicom-sr": "3.9.0-beta.110",
"@ohif/extension-default": "3.9.0-beta.110",
@@ -30,12 +30,7 @@ function TrackedMeasurementsContextProvider(
const [viewportGrid, viewportGridService] = useViewportGrid();
const { activeViewportId, viewports } = viewportGrid;
const {
measurementService,
displaySetService,
customizationService,
cornerstoneViewportService,
} = servicesManager.services;
const { measurementService, displaySetService, customizationService } = servicesManager.services;
const machineOptions = Object.assign({}, defaultOptions);
machineOptions.actions = Object.assign({}, machineOptions.actions, {
@@ -118,7 +118,7 @@ function PanelMeasurementTableTracking({
downloadCSVReport(trackedMeasurements);
}}
>
<Icons.Download />
<Icons.Download className="h-5 w-5" />
<span className="pl-1">CSV</span>
</Button>
<Button
@@ -133,7 +133,18 @@ function PanelMeasurementTableTracking({
}}
>
<Icons.Add />
Create DICOM SR
Create SR
</Button>
<Button
size="sm"
variant="ghost"
className="pl-0.5"
onClick={() => {
measurementService.clearMeasurements();
}}
>
<Icons.Delete />
Delete All
</Button>
</div>
</div>
@@ -8,7 +8,7 @@ import { StudyBrowser } from '@ohif/ui-next';
import { useTrackedMeasurements } from '../../getContextModule';
import { Separator } from '@ohif/ui-next';
import { PanelStudyBrowserTrackingHeader } from './PanelStudyBrowserTrackingHeader';
import { PanelStudyBrowserHeader } from '@ohif/extension-default';
import { defaultActionIcons, defaultViewPresets } from './constants';
const { formatDate, createStudyBrowserTabs } = utils;
@@ -482,7 +482,7 @@ function PanelStudyBrowserTracking({
return (
<>
<>
<PanelStudyBrowserTrackingHeader
<PanelStudyBrowserHeader
viewPresets={viewPresets}
updateViewPresetValue={updateViewPresetValue}
actionIcons={actionIcons}
@@ -1,61 +0,0 @@
import React from 'react';
import { ToggleGroup, ToggleGroupItem } from '@ohif/ui-next';
import { Icons } from '@ohif/ui-next';
import { actionIcon, viewPreset } from './types';
function PanelStudyBrowserTrackingHeader({
viewPresets,
updateViewPresetValue,
actionIcons,
updateActionIconValue,
}: {
viewPresets: viewPreset[];
updateViewPresetValue: (viewPreset: viewPreset) => void;
actionIcons: actionIcon[];
updateActionIconValue: (actionIcon: actionIcon) => void;
}) {
return (
<>
<div className="bg-muted flex h-[40px] select-none rounded-t p-2">
<div className={'flex h-[24px] w-full select-none justify-center self-center text-[14px]'}>
<div className="flex w-full items-center gap-[10px]">
<div className="flex h-full items-center justify-center">
<ToggleGroup
type="single"
value={viewPresets.filter(preset => preset.selected)[0].id}
onValueChange={value => {
const selectedViewPreset = viewPresets.find(preset => preset.id === value);
updateViewPresetValue(selectedViewPreset);
}}
>
{viewPresets.map((viewPreset: viewPreset, index) => (
<ToggleGroupItem
key={index}
aria-label={viewPreset.id}
value={viewPreset.id}
className="text-actions-primary"
>
{React.createElement(Icons[viewPreset.iconName] || Icons.MissingIcon)}
</ToggleGroupItem>
))}
</ToggleGroup>
</div>
<div className="flex items-center justify-center">
<div className="text-primary-active flex items-center space-x-1">
{actionIcons.map((icon: actionIcon, index) =>
React.createElement(Icons[icon.iconName] || Icons.MissingIcon, {
key: index,
onClick: () => updateActionIconValue(icon),
className: `cursor-pointer`,
})
)}
</div>
</div>
</div>
</div>
</div>
</>
);
}
export { PanelStudyBrowserTrackingHeader };