diff --git a/dicom-viewer/src/App.tsx b/dicom-viewer/src/App.tsx index bb44444..ec58e5f 100644 --- a/dicom-viewer/src/App.tsx +++ b/dicom-viewer/src/App.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef, useCallback, useState } from "react" -import createImageIds from "./lib/createImageIds.ts" +import { createImageIds, availableImageIds } from "./lib/createImageIds.ts" import { RenderingEngine, Enums, @@ -251,48 +251,48 @@ function App() { }; // Helper to apply all mouse tool bindings (normal or ctrl) -const applyMouseToolBindings = useCallback(() => { - // Apply to both stack and volume tool groups - const stackToolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(STACK_TOOL_GROUP_ID); - const volumeToolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(VOLUME_TOOL_GROUP_ID); + const applyMouseToolBindings = useCallback(() => { + // Apply to both stack and volume tool groups + const stackToolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(STACK_TOOL_GROUP_ID); + const volumeToolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(VOLUME_TOOL_GROUP_ID); - [stackToolGroup, volumeToolGroup].forEach(toolGroup => { - if (toolGroup) { - // Set all tools to passive first, removing all bindings - TOOL_OPTIONS.forEach(opt => { - toolGroup.setToolPassive(opt.value, { removeAllBindings: true }); - }); + [stackToolGroup, volumeToolGroup].forEach(toolGroup => { + if (toolGroup) { + // Set all tools to passive first, removing all bindings + TOOL_OPTIONS.forEach(opt => { + toolGroup.setToolPassive(opt.value, { removeAllBindings: true }); + }); - // Collect all bindings for each tool - const toolBindings: Record> = {}; + // Collect all bindings for each tool + const toolBindings: Record> = {}; - // Normal bindings - Object.entries(mouseToolBindings).forEach(([btn, tool]) => { - if (!toolBindings[tool]) toolBindings[tool] = []; - toolBindings[tool].push({ mouseButton: MouseBindings[btn] }); - }); - // Ctrl bindings - Object.entries(ctrlMouseToolBindings).forEach(([btn, tool]) => { - if (!toolBindings[tool]) toolBindings[tool] = []; - toolBindings[tool].push({ mouseButton: MouseBindings[btn], modifierKey: KeyboardBindings.Ctrl }); - }); + // Normal bindings + Object.entries(mouseToolBindings).forEach(([btn, tool]) => { + if (!toolBindings[tool]) toolBindings[tool] = []; + toolBindings[tool].push({ mouseButton: MouseBindings[btn] }); + }); + // Ctrl bindings + Object.entries(ctrlMouseToolBindings).forEach(([btn, tool]) => { + if (!toolBindings[tool]) toolBindings[tool] = []; + toolBindings[tool].push({ mouseButton: MouseBindings[btn], modifierKey: KeyboardBindings.Ctrl }); + }); - // Apply all bindings for each tool in a single call - Object.entries(toolBindings).forEach(([tool, bindings]) => { - toolGroup.setToolActive(tool, { bindings }); - }); + // Apply all bindings for each tool in a single call + Object.entries(toolBindings).forEach(([tool, bindings]) => { + toolGroup.setToolActive(tool, { bindings }); + }); - // Always re-apply the mouse wheel binding for StackScrollTool - toolGroup.setToolActive(StackScrollTool.toolName, { - bindings: [ - { - mouseButton: MouseBindings.Wheel, // Wheel Mouse - }, - ], - }); - } - }); -}, [mouseToolBindings, ctrlMouseToolBindings]); + // Always re-apply the mouse wheel binding for StackScrollTool + toolGroup.setToolActive(StackScrollTool.toolName, { + bindings: [ + { + mouseButton: MouseBindings.Wheel, // Wheel Mouse + }, + ], + }); + } + }); + }, [mouseToolBindings, ctrlMouseToolBindings]); const [sideMenuOpen, setSideMenuOpen] = useState(false); @@ -412,22 +412,6 @@ const applyMouseToolBindings = useCallback(() => { .slice(0, viewportGrid.rows * viewportGrid.cols) .filter(mode => mode === 'volume').length; - // After the viewport setup loop, outside the for-loop: - if ( - crossReferenceEnabled && - visibleVolumeViewports >= 2 - ) { - if (!volumeToolGroup.hasTool(CrosshairsTool.toolName)) { - volumeToolGroup.addTool(CrosshairsTool.toolName); - } - volumeToolGroup.setToolEnabled(CrosshairsTool.toolName); - volumeToolGroup.setToolActive(CrosshairsTool.toolName, { - bindings: [{ mouseButton: MouseBindings.Primary }], - }); - } else if (volumeToolGroup.hasTool(CrosshairsTool.toolName)) { - volumeToolGroup.setToolDisabled(CrosshairsTool.toolName); - } - // --- In your setup function, after tool group creation, enable/disable ReferenceLinesTool for each tool group --- if (referenceLinesEnabled) { if (!stackToolGroup.hasTool(ReferenceLinesTool.toolName)) { @@ -521,15 +505,13 @@ const applyMouseToolBindings = useCallback(() => { }); } - // Example: create and set a volume (you may need to adapt this for your data) - const volumeId = 'myVolumeId'; - const volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds }); + // Use a unique volumeId per viewport + const volumeId = `myVolumeId_${i}`; + const volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: sortedImageIds }); volume.load(); - //await volumeLoader.loadVolume(volumeId); viewport.setVolumes([{ volumeId }]); - // Optionally restore properties for volume viewport.render(); - return + continue } viewport.render(); @@ -586,6 +568,30 @@ const applyMouseToolBindings = useCallback(() => { updateOverlay(i, viewport); } + const activeVolumeViewports = []; + for (let i = 0; i < viewportGrid.rows * viewportGrid.cols; i++) { + const viewportId = `CT_${i}`; + const viewport = renderingEngineRef.current?.getViewport(viewportId); + if (viewport && viewportModes[i] === 'volume') { + activeVolumeViewports.push(viewport); + } + } + + if ( + crossReferenceEnabled && + activeVolumeViewports.length >= 2 + ) { + if (!volumeToolGroup.hasTool(CrosshairsTool.toolName)) { + volumeToolGroup.addTool(CrosshairsTool.toolName); + } + volumeToolGroup.setToolEnabled(CrosshairsTool.toolName); + volumeToolGroup.setToolActive(CrosshairsTool.toolName, { + bindings: [{ mouseButton: MouseBindings.Primary }], + }); + } else if (volumeToolGroup.hasTool(CrosshairsTool.toolName)) { + volumeToolGroup.setToolDisabled(CrosshairsTool.toolName); + } + // 7. Apply mouse tool bindings applyMouseToolBindings(); }; diff --git a/dicom-viewer/src/lib/createImageIds.ts b/dicom-viewer/src/lib/createImageIds.ts index c23463a..7f8c8b0 100644 --- a/dicom-viewer/src/lib/createImageIds.ts +++ b/dicom-viewer/src/lib/createImageIds.ts @@ -65,11 +65,23 @@ import { readFile } from "dicom-parser" const NUM_IMAGES = 15 // set to however many images you have -export default async function createImageIds() { +export async function createImageIds() { const imageIds = [] for (let i = 1; i <= NUM_IMAGES; i++) { const fileName = `IMG${String(i)}.dcm` imageIds.push(`wadouri:/test_images/stack2/${fileName}`) } return imageIds +} + + +export async function availableImageIds() { + // Example: two stacks, each with 10 images + const stacks = [ + Array.from({ length: 15 }, (_, i) => `wadouri:/test_images/stack2/IMG${i + 1}.dcm`), + Array.from({ length: 25 }, (_, i) => `wadouri:/test_images/stack5/IMG${i + 1}.dcm`), + Array.from({ length: 26 }, (_, i) => `wadouri:/test_images/stack3/IMG${i + 1}.dcm`), + // Add more stacks as needed + ]; + return stacks; } \ No newline at end of file