get tools working
This commit is contained in:
+228
-92
@@ -6,6 +6,7 @@ import {
|
|||||||
} from "@cornerstonejs/core"
|
} from "@cornerstonejs/core"
|
||||||
import { init as csRenderInit } from "@cornerstonejs/core"
|
import { init as csRenderInit } from "@cornerstonejs/core"
|
||||||
import { init as csToolsInit, addTool, ToolGroupManager, Enums as csToolsEnums, PanTool, WindowLevelTool, StackScrollTool, ZoomTool, PlanarRotateTool } from "@cornerstonejs/tools"
|
import { init as csToolsInit, addTool, ToolGroupManager, Enums as csToolsEnums, PanTool, WindowLevelTool, StackScrollTool, ZoomTool, PlanarRotateTool } from "@cornerstonejs/tools"
|
||||||
|
import { LengthTool, ProbeTool, ArrowAnnotateTool, RectangleROITool, EllipticalROITool } from "@cornerstonejs/tools"
|
||||||
import { init as dicomImageLoaderInit } from "@cornerstonejs/dicom-image-loader"
|
import { init as dicomImageLoaderInit } from "@cornerstonejs/dicom-image-loader"
|
||||||
import * as cornerstoneTools from '@cornerstonejs/tools';
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||||
import { StackScrollOutOfBoundsEvent } from 'core/src/types/EventTypes';
|
import { StackScrollOutOfBoundsEvent } from 'core/src/types/EventTypes';
|
||||||
@@ -16,13 +17,6 @@ const { MouseBindings } = csToolsEnums;
|
|||||||
const { IMAGE_RENDERED } = Enums.Events;
|
const { IMAGE_RENDERED } = Enums.Events;
|
||||||
|
|
||||||
const toolGroupId = 'STACK_TOOL_GROUP_ID';
|
const toolGroupId = 'STACK_TOOL_GROUP_ID';
|
||||||
const leftClickTools = [
|
|
||||||
WindowLevelTool.toolName,
|
|
||||||
PlanarRotateTool.toolName,
|
|
||||||
StackScrollTool.toolName,
|
|
||||||
];
|
|
||||||
const defaultLeftClickTool = leftClickTools[0];
|
|
||||||
let currentLeftClickTool = leftClickTools[0];
|
|
||||||
|
|
||||||
// Common CT presets (add more as needed)
|
// Common CT presets (add more as needed)
|
||||||
const WINDOW_LEVEL_PRESETS = [
|
const WINDOW_LEVEL_PRESETS = [
|
||||||
@@ -33,6 +27,26 @@ const WINDOW_LEVEL_PRESETS = [
|
|||||||
{ name: "Abdomen", center: 60, width: 400 },
|
{ name: "Abdomen", center: 60, width: 400 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// Tool options for dropdowns
|
||||||
|
const TOOL_OPTIONS = [
|
||||||
|
{ label: "Window/Level", value: WindowLevelTool.toolName },
|
||||||
|
{ label: "Pan", value: PanTool.toolName },
|
||||||
|
{ label: "Zoom", value: ZoomTool.toolName },
|
||||||
|
{ label: "Stack Scroll", value: StackScrollTool.toolName },
|
||||||
|
{ label: "Rotate", value: PlanarRotateTool.toolName },
|
||||||
|
{ label: "Length", value: LengthTool.toolName },
|
||||||
|
{ label: "Probe", value: ProbeTool.toolName },
|
||||||
|
{ label: "Arrow Annotate", value: ArrowAnnotateTool.toolName },
|
||||||
|
{ label: "Rectangle ROI", value: RectangleROITool.toolName },
|
||||||
|
{ label: "Ellipse ROI", value: EllipticalROITool.toolName },
|
||||||
|
]
|
||||||
|
|
||||||
|
// Mouse button labels
|
||||||
|
const MOUSE_BUTTONS = [
|
||||||
|
{ label: "Left", value: "Primary" },
|
||||||
|
{ label: "Middle", value: "Auxiliary" },
|
||||||
|
{ label: "Right", value: "Secondary" },
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@@ -40,6 +54,11 @@ function App() {
|
|||||||
const viewportRef = useRef<any>(null) // Store the viewport instance
|
const viewportRef = useRef<any>(null) // Store the viewport instance
|
||||||
const running = useRef(false)
|
const running = useRef(false)
|
||||||
|
|
||||||
|
// State to control preset menu open/close
|
||||||
|
const [presetsOpen, setPresetsOpen] = useState(false);
|
||||||
|
|
||||||
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||||
|
|
||||||
// State for overlay info
|
// State for overlay info
|
||||||
const [imageInfo, setImageInfo] = useState({
|
const [imageInfo, setImageInfo] = useState({
|
||||||
index: 0,
|
index: 0,
|
||||||
@@ -48,11 +67,40 @@ function App() {
|
|||||||
windowWidth: "",
|
windowWidth: "",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// State for selected tool per mouse button
|
||||||
|
const [mouseToolBindings, setMouseToolBindings] = useState({
|
||||||
|
Primary: WindowLevelTool.toolName,
|
||||||
|
Auxiliary: PanTool.toolName,
|
||||||
|
Secondary: ZoomTool.toolName,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Helper to apply all mouse tool bindings
|
||||||
|
const applyMouseToolBindings = useCallback(() => {
|
||||||
|
console.log("applyMouseToolBindings", mouseToolBindings)
|
||||||
|
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
|
if (toolGroup) {
|
||||||
|
// Set all tools to passive first
|
||||||
|
TOOL_OPTIONS.forEach(opt => {
|
||||||
|
toolGroup.setToolPassive(opt.value, { removeAllBindings: true })
|
||||||
|
})
|
||||||
|
// Re-apply all bindings for all mouse buttons (Primary, Auxiliary, Secondary)
|
||||||
|
Object.entries(mouseToolBindings).forEach(([btn, tool]) => {
|
||||||
|
console.log("button", btn, "setToolActive", tool)
|
||||||
|
toolGroup.setToolActive(tool, {
|
||||||
|
bindings: [{ mouseButton: csToolsEnums.MouseBindings[btn] }],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// Do NOT set wheel bindings here!
|
||||||
|
}
|
||||||
|
}, [mouseToolBindings])
|
||||||
|
|
||||||
|
const handleToolChange = (mouseButton: string, toolName: string) => {
|
||||||
|
setMouseToolBindings(prev => ({ ...prev, [mouseButton]: toolName }))
|
||||||
|
}
|
||||||
|
|
||||||
const updateOverlay = useCallback(() => {
|
const updateOverlay = useCallback(() => {
|
||||||
console.log("updateOverlay")
|
|
||||||
const viewport = viewportRef.current
|
const viewport = viewportRef.current
|
||||||
if (!viewport) return
|
if (!viewport) return
|
||||||
console.log(viewport)
|
|
||||||
|
|
||||||
// For StackViewport in Cornerstone3D v3:
|
// For StackViewport in Cornerstone3D v3:
|
||||||
const currentIndex = typeof viewport.getCurrentImageIdIndex === "function"
|
const currentIndex = typeof viewport.getCurrentImageIdIndex === "function"
|
||||||
@@ -94,46 +142,32 @@ const updateOverlay = useCallback(() => {
|
|||||||
dicomImageLoaderInit({ maxWebWorkers: 1 })
|
dicomImageLoaderInit({ maxWebWorkers: 1 })
|
||||||
|
|
||||||
// Add tools to Cornerstone3D
|
// Add tools to Cornerstone3D
|
||||||
cornerstoneTools.addTool(PanTool);
|
cornerstoneTools.addTool(PanTool)
|
||||||
cornerstoneTools.addTool(WindowLevelTool);
|
cornerstoneTools.addTool(WindowLevelTool)
|
||||||
cornerstoneTools.addTool(StackScrollTool);
|
cornerstoneTools.addTool(StackScrollTool)
|
||||||
cornerstoneTools.addTool(ZoomTool);
|
cornerstoneTools.addTool(ZoomTool)
|
||||||
cornerstoneTools.addTool(PlanarRotateTool);
|
cornerstoneTools.addTool(PlanarRotateTool)
|
||||||
|
cornerstoneTools.addTool(LengthTool)
|
||||||
|
cornerstoneTools.addTool(ProbeTool)
|
||||||
|
cornerstoneTools.addTool(ArrowAnnotateTool)
|
||||||
|
cornerstoneTools.addTool(RectangleROITool)
|
||||||
|
cornerstoneTools.addTool(EllipticalROITool)
|
||||||
|
|
||||||
// Define a tool group, which defines how mouse events map to tool commands for
|
// Create tool group ONCE
|
||||||
// Any viewport using the group
|
let toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
||||||
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId);
|
if (!toolGroup) {
|
||||||
|
toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
|
||||||
// Add tools to the tool group
|
toolGroup.addTool(WindowLevelTool.toolName)
|
||||||
toolGroup.addTool(WindowLevelTool.toolName);
|
toolGroup.addTool(PanTool.toolName)
|
||||||
toolGroup.addTool(PanTool.toolName);
|
toolGroup.addTool(ZoomTool.toolName)
|
||||||
toolGroup.addTool(ZoomTool.toolName);
|
toolGroup.addTool(StackScrollTool.toolName, { loop: false })
|
||||||
toolGroup.addTool(StackScrollTool.toolName, { loop: false });
|
toolGroup.addTool(PlanarRotateTool.toolName)
|
||||||
toolGroup.addTool(PlanarRotateTool.toolName);
|
toolGroup.addTool(LengthTool.toolName)
|
||||||
|
toolGroup.addTool(ProbeTool.toolName)
|
||||||
// Set the initial state of the tools, here all tools are active and bound to
|
toolGroup.addTool(ArrowAnnotateTool.toolName)
|
||||||
// Different mouse inputs
|
toolGroup.addTool(RectangleROITool.toolName)
|
||||||
toolGroup.setToolActive(defaultLeftClickTool, {
|
toolGroup.addTool(EllipticalROITool.toolName)
|
||||||
bindings: [
|
}
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Primary, // Left Click
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
toolGroup.setToolActive(PanTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Auxiliary, // Middle Click
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
toolGroup.setToolActive(ZoomTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Secondary, // Right Click
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// The Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
|
// The Stack Scroll mouse wheel is a tool using the `mouseWheelCallback`
|
||||||
// and needs to be registered against the 'Wheel' binding.
|
// and needs to be registered against the 'Wheel' binding.
|
||||||
@@ -144,22 +178,9 @@ const updateOverlay = useCallback(() => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
toolGroup.setToolActive(PlanarRotateTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Wheel, // Shift Wheel Mouse
|
|
||||||
//modifierKey: KeyboardBindings.Shift,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Wheel_Primary, // Left Click+Wheel Mouse
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const imageIds = await createImageIdsAndCacheMetaData()
|
const imageIds = await createImageIdsAndCacheMetaData()
|
||||||
console.log("imageIds", imageIds)
|
|
||||||
|
|
||||||
// Instantiate a rendering engine
|
// Instantiate a rendering engine
|
||||||
const renderingEngineId = "myRenderingEngine"
|
const renderingEngineId = "myRenderingEngine"
|
||||||
@@ -187,10 +208,6 @@ const updateOverlay = useCallback(() => {
|
|||||||
|
|
||||||
cornerstoneTools.utilities.stackPrefetch.enable(viewport.element);
|
cornerstoneTools.utilities.stackPrefetch.enable(viewport.element);
|
||||||
|
|
||||||
function test(e) {
|
|
||||||
console.log("test", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the image
|
// Render the image
|
||||||
viewport.render()
|
viewport.render()
|
||||||
viewport.element.addEventListener(Enums.Events.IMAGE_RENDERED, updateOverlay)
|
viewport.element.addEventListener(Enums.Events.IMAGE_RENDERED, updateOverlay)
|
||||||
@@ -200,6 +217,9 @@ const updateOverlay = useCallback(() => {
|
|||||||
|
|
||||||
// Initial overlay update
|
// Initial overlay update
|
||||||
updateOverlay()
|
updateOverlay()
|
||||||
|
|
||||||
|
// Apply mouse tool bindings after setup
|
||||||
|
applyMouseToolBindings()
|
||||||
}
|
}
|
||||||
|
|
||||||
setup()
|
setup()
|
||||||
@@ -235,10 +255,25 @@ const updateOverlay = useCallback(() => {
|
|||||||
viewport.render()
|
viewport.render()
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
useEffect(() => {
|
||||||
|
applyMouseToolBindings();
|
||||||
|
}, [mouseToolBindings, applyMouseToolBindings]);
|
||||||
|
|
||||||
|
// Close the menu when clicking outside
|
||||||
|
useEffect(() => {
|
||||||
|
if (!presetsOpen) return;
|
||||||
|
const handleClick = (e: MouseEvent) => {
|
||||||
|
const menu = document.querySelector(".preset-menu");
|
||||||
|
if (menu && !menu.contains(e.target as Node)) {
|
||||||
|
setPresetsOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener("mousedown", handleClick);
|
||||||
|
return () => document.removeEventListener("mousedown", handleClick);
|
||||||
|
}, [presetsOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative", width: "512px", height: "512px" }}>
|
<div style={{ position: "relative", width: "512px", height: "512px" }}>
|
||||||
{/* ...existing Reset View button and viewport div... */}
|
|
||||||
<button
|
<button
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -252,6 +287,7 @@ const updateOverlay = useCallback(() => {
|
|||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
opacity: 0.85,
|
opacity: 0.85,
|
||||||
|
userSelect: "none", // <-- Prevents text selection
|
||||||
}}
|
}}
|
||||||
onClick={handleResetView}
|
onClick={handleResetView}
|
||||||
>
|
>
|
||||||
@@ -260,6 +296,7 @@ const updateOverlay = useCallback(() => {
|
|||||||
<div
|
<div
|
||||||
ref={elementRef}
|
ref={elementRef}
|
||||||
onDoubleClick={handleDoubleClick}
|
onDoubleClick={handleDoubleClick}
|
||||||
|
onContextMenu={e => e.preventDefault()} // <-- Add this line
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
@@ -280,6 +317,7 @@ const updateOverlay = useCallback(() => {
|
|||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
minWidth: "120px",
|
minWidth: "120px",
|
||||||
|
userSelect: "none", // <-- Prevents text selection
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
@@ -289,7 +327,7 @@ const updateOverlay = useCallback(() => {
|
|||||||
WC: {imageInfo.windowCenter} WW: {imageInfo.windowWidth}
|
WC: {imageInfo.windowCenter} WW: {imageInfo.windowWidth}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Preset menu at bottom right, collapsed by default, expands on hover */}
|
{/* Preset menu at bottom right, expands on click */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -299,6 +337,7 @@ const updateOverlay = useCallback(() => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
className="preset-menu"
|
||||||
style={{
|
style={{
|
||||||
background: "rgba(0,0,0,0.7)",
|
background: "rgba(0,0,0,0.7)",
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
@@ -306,30 +345,35 @@ const updateOverlay = useCallback(() => {
|
|||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
minWidth: "120px",
|
minWidth: "120px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
transition: "height 0.2s",
|
|
||||||
height: "28px",
|
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
boxShadow: presetsOpen ? "0 2px 8px rgba(0,0,0,0.3)" : undefined,
|
||||||
}}
|
}}
|
||||||
className="preset-menu"
|
|
||||||
>
|
>
|
||||||
<div style={{ padding: "6px 12px", fontWeight: "bold" }}>
|
|
||||||
Presets
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
padding: "6px 12px",
|
||||||
left: 0,
|
fontWeight: "bold",
|
||||||
right: 0,
|
userSelect: "none",
|
||||||
bottom: 0,
|
}}
|
||||||
|
onClick={() => setPresetsOpen((open) => !open)}
|
||||||
|
>
|
||||||
|
Presets
|
||||||
|
<span style={{ float: "right", fontWeight: "normal" }}>
|
||||||
|
{presetsOpen ? "▲" : "▼"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{presetsOpen && (
|
||||||
|
<div
|
||||||
|
className="preset-menu-content"
|
||||||
|
style={{
|
||||||
background: "rgba(0,0,0,0.95)",
|
background: "rgba(0,0,0,0.95)",
|
||||||
borderRadius: "4px",
|
borderRadius: "0 0 4px 4px",
|
||||||
padding: "6px 0 6px 0",
|
padding: "6px 0 6px 0",
|
||||||
display: "none",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
zIndex: 11,
|
zIndex: 11,
|
||||||
}}
|
}}
|
||||||
className="preset-menu-content"
|
|
||||||
>
|
>
|
||||||
{WINDOW_LEVEL_PRESETS.map((preset) => (
|
{WINDOW_LEVEL_PRESETS.map((preset) => (
|
||||||
<button
|
<button
|
||||||
@@ -347,25 +391,117 @@ const updateOverlay = useCallback(() => {
|
|||||||
fontSize: "13px",
|
fontSize: "13px",
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
}}
|
}}
|
||||||
onClick={() => handleApplyPreset(preset.center, preset.width)}
|
onClick={() => {
|
||||||
|
handleApplyPreset(preset.center, preset.width);
|
||||||
|
setPresetsOpen(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{preset.name}
|
{preset.name}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* Inline CSS for hover effect */}
|
|
||||||
<style>
|
|
||||||
{`
|
|
||||||
.preset-menu:hover .preset-menu-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.preset-menu:hover {
|
|
||||||
height: auto !important;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
</style>
|
|
||||||
</div>
|
</div>
|
||||||
|
{/* Settings button at top right */}
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
zIndex: 20,
|
||||||
|
padding: "6px 12px",
|
||||||
|
background: "#222",
|
||||||
|
color: "#fff",
|
||||||
|
border: "none",
|
||||||
|
borderRadius: "4px",
|
||||||
|
cursor: "pointer",
|
||||||
|
opacity: 0.85,
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
|
onClick={() => setSettingsOpen(true)}
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Settings Modal (viewport-local, not fixed to page) */}
|
||||||
|
{settingsOpen && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
background: "rgba(0,0,0,0.4)",
|
||||||
|
zIndex: 1000,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
onClick={() => setSettingsOpen(false)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#222",
|
||||||
|
color: "#fff",
|
||||||
|
borderRadius: "8px",
|
||||||
|
minWidth: "320px",
|
||||||
|
minHeight: "180px",
|
||||||
|
padding: "24px",
|
||||||
|
boxShadow: "0 4px 24px rgba(0,0,0,0.4)",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
onClick={e => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div style={{ fontSize: "20px", marginBottom: "16px" }}>
|
||||||
|
Settings
|
||||||
|
</div>
|
||||||
|
{/* Settings content: Tool dropdowns */}
|
||||||
|
<div style={{ marginBottom: "24px" }}>
|
||||||
|
<div style={{ marginBottom: 12, fontWeight: "bold" }}>Mouse Button Tool Bindings</div>
|
||||||
|
{MOUSE_BUTTONS.map((btn) => (
|
||||||
|
<div key={btn.value} style={{ marginBottom: 10 }}>
|
||||||
|
<label style={{ marginRight: 8 }}>{btn.label} Button:</label>
|
||||||
|
<select
|
||||||
|
value={mouseToolBindings[btn.value]}
|
||||||
|
onChange={e => handleToolChange(btn.value, e.target.value)}
|
||||||
|
style={{
|
||||||
|
background: "#333",
|
||||||
|
color: "#fff",
|
||||||
|
border: "1px solid #444",
|
||||||
|
borderRadius: "4px",
|
||||||
|
padding: "4px 8px",
|
||||||
|
fontSize: "14px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{TOOL_OPTIONS.map(opt => (
|
||||||
|
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 12,
|
||||||
|
right: 12,
|
||||||
|
background: "transparent",
|
||||||
|
color: "#fff",
|
||||||
|
border: "none",
|
||||||
|
fontSize: "20px",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
onClick={() => setSettingsOpen(false)}
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* ...rest of your UI... */}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader"
|
|||||||
return imageIds
|
return imageIds
|
||||||
} */
|
} */
|
||||||
|
|
||||||
const NUM_IMAGES = 10 // set to however many images you have
|
const NUM_IMAGES = 20 // set to however many images you have
|
||||||
|
|
||||||
export default async function createImageIdsAndCacheMetaData() {
|
export default async function createImageIdsAndCacheMetaData() {
|
||||||
const imageIds = []
|
const imageIds = []
|
||||||
|
|||||||
Reference in New Issue
Block a user