ohif-viewer/extensions/dicom-microscopy/src/index.tsx
Dan Rukas 9a2691a71f
fix(colors): Replaces legacy colors with ui-next colors (#5351)
* Update playwright screenshots and fix broken tests.

---------

Co-authored-by: Joe Boccanfuso <joe.boccanfuso@radicalimaging.com>
2026-02-12 08:48:05 -05:00

173 lines
5.3 KiB
TypeScript

import { id } from './id';
import React, { Suspense, useCallback, useMemo } from 'react';
import getPanelModule from './getPanelModule';
import getCommandsModule from './getCommandsModule';
import getCustomizationModule from './getCustomizationModule';
import { Types } from '@ohif/core';
import { useViewportGrid } from '@ohif/ui-next';
import getDicomMicroscopySRSopClassHandler from './DicomMicroscopySRSopClassHandler';
import getDicomMicroscopyANNSopClassHandler from './DicomMicroscopyANNSopClassHandler';
import MicroscopyService from './services/MicroscopyService';
import { useResizeDetector } from 'react-resize-detector';
import debounce from 'lodash.debounce';
const Component = React.lazy(() => {
return import('./DicomMicroscopyViewport');
});
const MicroscopyViewport = props => {
return (
<Suspense fallback={<div>Loading...</div>}>
<Component {...props} />
</Suspense>
);
};
/**
* You can remove any of the following modules if you don't need them.
*/
const extension: Types.Extensions.Extension = {
/**
* Only required property. Should be a unique value across all extensions.
* You ID can be anything you want, but it should be unique.
*/
id,
async preRegistration({ servicesManager }) {
servicesManager.registerService(MicroscopyService.REGISTRATION(servicesManager));
},
/**
* ViewportModule should provide a list of viewports that will be available in OHIF
* for Modes to consume and use in the viewports. Each viewport is defined by
* {name, component} object. Example of a viewport module is the CornerstoneViewport
* that is provided by the Cornerstone extension in OHIF.
*/
getViewportModule({ servicesManager }) {
/**
*
* @param props {*}
* @param props.displaySets
* @param props.viewportId
* @param props.viewportLabel
* @param props.dataSource
* @param props.viewportOptions
* @param props.displaySetOptions
* @returns
*/
const ExtendedMicroscopyViewport = props => {
const { viewportOptions } = props;
const [viewportGrid, viewportGridService] = useViewportGrid();
const { activeViewportId } = viewportGrid;
const displaySetsKey = useMemo(() => {
return props.displaySets.map(ds => ds.displaySetInstanceUID).join('-');
}, [props.displaySets]);
const onResize = debounce(() => {
const { microscopyService } = servicesManager.services;
const managedViewer = microscopyService.getAllManagedViewers();
if (managedViewer && managedViewer.length > 0) {
managedViewer[0].viewer.resize();
}
}, 100);
const { ref: resizeRef } = useResizeDetector({
onResize,
handleHeight: true,
handleWidth: true,
});
const setViewportActive = useCallback(
(viewportId: string) => {
viewportGridService.setActiveViewportId(viewportId);
},
[viewportGridService]
);
return (
<MicroscopyViewport
key={displaySetsKey}
activeViewportId={activeViewportId}
setViewportActive={setViewportActive}
viewportData={viewportOptions}
resizeRef={resizeRef}
{...props}
/>
);
};
return [
{
name: 'microscopy-dicom',
component: ExtendedMicroscopyViewport,
},
];
},
getToolbarModule({ servicesManager }) {
return [
{
name: 'evaluate.microscopyTool',
evaluate: ({ button }) => {
const { microscopyService } = servicesManager.services;
const activeInteractions = microscopyService.getActiveInteractions();
if (!activeInteractions) {
return false;
}
const isPrimaryActive = activeInteractions.find(interactions => {
const sameMouseButton = interactions[1].bindings.mouseButtons.includes('left');
if (!sameMouseButton) {
return false;
}
const notDraw = interactions[0] !== 'draw';
// there seems to be a custom logic for draw tool for some reason
return notDraw
? interactions[0] === button.id
: interactions[1].geometryType === button.id;
});
return {
disabled: false,
className: isPrimaryActive
? '!text-black bg-highlight'
: '!text-foreground/80 hover:!bg-muted hover:!text-highlight',
// Todo: isActive right now is used for nested buttons where the primary
// button needs to be fully rounded (vs partial rounded) when active
// otherwise it does not have any other use
isActive: isPrimaryActive,
};
},
},
];
},
/**
* SopClassHandlerModule should provide a list of sop class handlers that will be
* available in OHIF for Modes to consume and use to create displaySets from Series.
* Each sop class handler is defined by a { name, sopClassUids, getDisplaySetsFromSeries}.
* Examples include the default sop class handler provided by the default extension
*/
getSopClassHandlerModule(params) {
return [
getDicomMicroscopySRSopClassHandler(params),
getDicomMicroscopyANNSopClassHandler(params),
];
},
getPanelModule,
getCommandsModule,
getCustomizationModule,
};
export default extension;