feat: 处理窗口resize

This commit is contained in:
mozzie 2024-09-19 15:00:40 +08:00
parent d09d852207
commit dff24401bf
3 changed files with 87 additions and 56 deletions

View File

@ -5,6 +5,11 @@ export type ViewportId = "CT_AXIAL" | "CT_SAGITTAL" | "CT_CORONAL";
export const viewportId1: ViewportId = "CT_AXIAL";
export const viewportId2: ViewportId = "CT_SAGITTAL";
export const viewportId3: ViewportId = "CT_CORONAL";
export const viewportIds: ViewportId[] = [
viewportId1,
viewportId2,
viewportId3,
];
export const viewportColors = {
[viewportId1]: "rgb(200, 0, 0)",
@ -34,7 +39,8 @@ export const viewportReferenceLineSlabThicknessControlsOn = [
export const volumeName = "CT_VOLUME_ID"; // Id of the volume less loader prefix
export const volumeLoaderScheme = "cornerstoneStreamingImageVolume"; // Loader id which defines which volume loader to use
export const volumeId = `${volumeLoaderScheme}:${volumeName}`; // VolumeId with loader id + volume id
export const toolGroupMprId = "toolMprNo1";
export const toolGroupMprId = "toolMpr";
export const toolGroupStackId = "toolStack";
export function getReferenceLineColor(vpId: ViewportId) {
return viewportColors[vpId];

View File

@ -26,15 +26,14 @@ import {
getReferenceLineDraggableRotatable,
getReferenceLineSlabThicknessControlsOn,
toolGroupMprId,
viewportId1,
viewportId2,
viewportId3,
toolGroupStackId,
viewportIds,
} from "./MprViewer/index.config";
import setCtTransferFunctionForVolumeActor from "./MprViewer/CornerstoneDicomLoader/setCtTransferFunctionForVolumeActor";
import { Slider } from "@/components/ui/slider";
import { stackViewportId } from "./StackViewer/index.config";
import { ToolBarMenu } from "./ToolBarMenu";
import { Model3DViewer } from "./ModelViewer";
import useMultiResizeObserver from "./useMultiResizeObserver";
const {
ToolGroupManager,
@ -69,7 +68,16 @@ export const Viewer = () => {
const [imageIds, setImageIds] = useState<string[]>();
const renderingEngineRef = useRef<RenderingEngine>();
const volumeId = SeriesInstanceUID;
const toolGroupStackId = "STACK_TOOL_GROUP:" + SeriesInstanceUID;
useMultiResizeObserver(
[
stackViewportRef,
volumeViewport1Ref,
volumeViewport2Ref,
volumeViewport3Ref,
],
() => renderingEngineRef.current?.resize()
);
useEffect(() => {
cornerstoneTools.addTool(StackScrollMouseWheelTool);
@ -90,7 +98,7 @@ export const Viewer = () => {
SeriesInstanceUID,
wadoRsRoot,
});
// 这一步会对imageIds进行排序如果不排序imageIds会错误乱,stackViewport顺序会错误
const volume = await volumeLoader.createAndCacheVolume(
SeriesInstanceUID,
@ -102,7 +110,7 @@ export const Viewer = () => {
const volumeViewportInput: PublicViewportInput[] = [
{
viewportId: viewportId1,
viewportId: viewportIds[0],
type: ViewportType.ORTHOGRAPHIC,
element: volumeViewport1Ref.current,
defaultOptions: {
@ -111,7 +119,7 @@ export const Viewer = () => {
},
},
{
viewportId: viewportId2,
viewportId: viewportIds[1],
type: ViewportType.ORTHOGRAPHIC,
element: volumeViewport2Ref.current,
defaultOptions: {
@ -120,7 +128,7 @@ export const Viewer = () => {
},
},
{
viewportId: viewportId3,
viewportId: viewportIds[2],
type: ViewportType.ORTHOGRAPHIC,
element: volumeViewport3Ref.current,
defaultOptions: {
@ -151,13 +159,11 @@ export const Viewer = () => {
const toolGroupMpr = ToolGroupManager.createToolGroup(toolGroupMprId);
if (toolGroupMpr) {
toolGroupMpr.addViewport(viewportId1, renderingEngineId);
toolGroupMpr.addViewport(viewportId2, renderingEngineId);
toolGroupMpr.addViewport(viewportId3, renderingEngineId);
viewportIds.forEach((vp) =>
toolGroupMpr.addViewport(vp, renderingEngineId)
);
toolGroupMpr.addTool(ZoomTool.toolName);
toolGroupMpr.setToolActive(ZoomTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Secondary }],
});
toolGroupMpr.addTool(WindowLevelTool.toolName);
toolGroupMpr.addTool(StackScrollMouseWheelTool.toolName);
toolGroupMpr.addTool(CrosshairsTool.toolName, {
getReferenceLineColor,
@ -165,12 +171,13 @@ export const Viewer = () => {
getReferenceLineDraggableRotatable,
getReferenceLineSlabThicknessControlsOn,
});
toolGroupMpr.setToolActive(ZoomTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Secondary }],
});
toolGroupMpr.setToolActive(CrosshairsTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Primary }],
});
toolGroupMpr.setToolActive(StackScrollMouseWheelTool.toolName);
toolGroupMpr.addTool(WindowLevelTool.toolName);
toolGroupMpr.setToolActive(WindowLevelTool.toolName, {
bindings: [{ mouseButton: MouseBindings.Auxiliary }],
});
@ -195,12 +202,8 @@ export const Viewer = () => {
await setVolumesForViewports(
renderingEngineRef.current,
[{ volumeId: SeriesInstanceUID }],
[viewportId1, viewportId2, viewportId3]
viewportIds
);
// 默认windowWidtth
// const { windowCenter, windowWidth } =
// volumeRef.current.cornerstoneImageMetaData;
};
initCornerstone(() => {
@ -208,10 +211,6 @@ export const Viewer = () => {
});
return () => {
// renderingEngineRef.current?.disableElement(stackViewportId);
// renderingEngineRef.current?.disableElement(viewportId1);
// renderingEngineRef.current?.disableElement(viewportId2);
// renderingEngineRef.current?.disableElement(viewportId3);
cache.purgeCache();
ToolGroupManager.destroy();
renderingEngineRef.current?.destroy();
@ -221,7 +220,7 @@ export const Viewer = () => {
cornerstoneTools.removeTool(WindowLevelTool);
cornerstoneTools.removeTool(ZoomTool);
};
}, [SeriesInstanceUID, StudyInstanceUID, toolGroupStackId, volumeId]);
}, [SeriesInstanceUID, StudyInstanceUID, volumeId]);
const onChangeIndex = (value: number[]) => setIndex(value[0]);
@ -253,25 +252,6 @@ export const Viewer = () => {
}
}, [index]);
useEffect(() => {
const container = stackViewportRef.current;
if (!container) return;
let resizeTimeout: NodeJS.Timeout | null = null;
const resizeObserver = new ResizeObserver(() => {
if (resizeTimeout) clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(
() => renderingEngineRef.current?.resize(),
100
);
});
resizeObserver.observe(container);
return () => {
if (resizeTimeout) clearTimeout(resizeTimeout);
resizeObserver.unobserve(container);
resizeObserver.disconnect();
};
}, []);
return (
<div className="w-full h-full flex flex-col">
<div className="flex-shrink-0 border-b border-secondary">
@ -315,15 +295,19 @@ export const Viewer = () => {
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<div
className="w-full h-1/3 border-b border-1 border-secondary"
ref={volumeViewport1Ref}
/>
<div
className="w-full h-1/3 border-b border-1 border-secondary"
ref={volumeViewport2Ref}
/>
<div className="w-full h-1/3" ref={volumeViewport3Ref} />
<ResizablePanelGroup direction="vertical" className="w-full h-full">
<ResizablePanel defaultSize={1 / 3}>
<div className="h-full" ref={volumeViewport1Ref} />
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={1 / 3}>
<div className="h-full" ref={volumeViewport2Ref} />
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={1 / 3}>
<div className="h-full" ref={volumeViewport3Ref} />
</ResizablePanel>
</ResizablePanelGroup>
</ResizablePanel>
</ResizablePanelGroup>
</div>

View File

@ -0,0 +1,41 @@
import { useEffect, RefObject } from "react";
type ResizeObserverCallback = () => void;
/**
* Hook Ref
* @param refs - Ref
* @param callback -
*/
function useMultiResizeObserver(
refs: Array<RefObject<Element>>,
callback: ResizeObserverCallback
) {
useEffect(() => {
const elements = refs
.map((ref) => ref.current)
.filter((el): el is Element => el !== null);
if (elements.length === 0) return;
let resizeTimeout: NodeJS.Timeout | null = null;
const resizeObserver = new ResizeObserver(() => {
if (resizeTimeout) clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(callback, 100);
});
elements.forEach((element) => {
resizeObserver.observe(element);
});
return () => {
if (resizeTimeout) clearTimeout(resizeTimeout);
elements.forEach((element) => {
resizeObserver.unobserve(element);
});
resizeObserver.disconnect();
};
}, [refs, callback]);
}
export default useMultiResizeObserver;