further improvements

This commit is contained in:
Ross
2025-05-31 11:24:20 +01:00
parent c90c280255
commit c7728bf1a2
2 changed files with 85 additions and 19 deletions
+15 -1
View File
@@ -7,7 +7,21 @@
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<div id="root" style="max-height:500px; height:500px; overflow:auto;"></div>
<script type="module" src="/src/main.tsx"></script>
<input type="file" id="dicomInput" multiple />
<button onclick="sendToViewer()">Send to Viewer</button>
<script>
function sendToViewer() {
const files = document.getElementById('dicomInput').files;
if (window.loadDicomStackFromFiles) {
window.loadDicomStackFromFiles(files);
} else {
alert("Viewer API not ready");
}
}
</script>
</body>
</html>
+70 -18
View File
@@ -9,7 +9,6 @@ import { init as csToolsInit, addTool, ToolGroupManager, Enums as csToolsEnums,
import { LengthTool, ProbeTool, ArrowAnnotateTool, RectangleROITool, EllipticalROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, SculptorTool, CrosshairsTool, ReferenceLinesTool, ReferenceCursors } from "@cornerstonejs/tools"
import { init as dicomImageLoaderInit } from "@cornerstonejs/dicom-image-loader"
import * as cornerstoneTools from '@cornerstonejs/tools';
import { StackScrollOutOfBoundsEvent } from 'core/src/types/EventTypes';
import { segmentation, Enums as csEnums } from '@cornerstonejs/tools';
import { voi } from "@cornerstonejs/tools/utilities"
import { readDicomElementExplicit } from "dicom-parser"
@@ -18,6 +17,20 @@ import { metaData } from '@cornerstonejs/core';
import * as dicomParser from "dicom-parser";
import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader"
// Extend the Window interface to include cornerstoneTools
declare global {
interface Window {
cornerstoneTools: typeof cornerstoneTools;
}
}
// Add this type for clarity
declare global {
interface Window {
loadDicomStackFromFiles?: (files: FileList | File[]) => void;
}
}
window.cornerstoneTools = cornerstoneTools;
@@ -203,7 +216,10 @@ function App() {
if (url.startsWith("blob:") || url.startsWith("/")) {
if (cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager) {
// If load returns a promise, collect it
const result = cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager.load(url);
// @ts-ignore
const result = cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager.load(
url,
);
if (result && typeof result.then === "function") {
loadPromises.push(result);
}
@@ -367,6 +383,21 @@ function App() {
setMetaModalOpen(true);
};
// Inside your App component:
useEffect(() => {
window.loadDicomStackFromFiles = (files: FileList | File[]) => {
// Convert FileList to array if needed
const fileArray = Array.from(files);
// Your logic to handle the files and load them as a stack
// For example, call your existing handler:
handleFilesSelected({ target: { files: fileArray } } as any);
};
// Cleanup on unmount
return () => {
window.loadDicomStackFromFiles = undefined;
};
}, []);
const [altPressed, setAltPressed] = useState(false);
useEffect(() => {
@@ -472,24 +503,39 @@ function App() {
const fileInputRef = useRef<HTMLInputElement | null>(null);
// Handler for file input change
const handleFilesSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (!files || files.length === 0) return;
const handleFilesSelected = async (event: React.ChangeEvent<HTMLInputElement> | { target: { files: File[] | FileList } }) => {
const files = event.target.files;
if (!files || files.length === 0) return;
// Reset order by slice location when new files are loaded
setOrderBySliceLocation(false);
setOrderBySliceLocation(false);
// Convert FileList to Array and sort by name (optional, for series order)
const fileArray = Array.from(files).sort((a, b) => a.name.localeCompare(b.name));
// Convert FileList to Array and sort by name (optional)
const fileArray = Array.from(files).sort((a, b) => a.name.localeCompare(b.name));
// Create imageIds for each file using the cornerstone-wado-image-loader file API
// (Assumes cornerstone-wado-image-loader is configured for file loading)
const imageIds = fileArray.map(
file => `wadouri:${URL.createObjectURL(file)}`
);
// Create imageIds for each file
const imageIds = fileArray.map(
file => `wadouri:${URL.createObjectURL(file)}`
);
// Add as a new stack
setAvailableStacks(prev => {
const next = [...prev, imageIds];
// Optionally, set the new stack as active in the first viewport:
setViewportImageIds(vpPrev => {
const vpNext = [...vpPrev];
vpNext[0] = imageIds;
return vpNext;
});
setSelectedStackIdx(selPrev => {
const selNext = [...selPrev];
selNext[0] = next.length - 1;
return selNext;
});
// Cache imageIds and load metadata for this stack
setLoadedImageIdsAndCacheMeta(imageIds);
};
return next;
});
};
const handleToolChange = (mouseButton: string, toolName: string) => {
@@ -862,6 +908,13 @@ function App() {
updateActiveReferenceLineViewport(mainToolGroup)
}, [activeViewport, referenceLinesEnabled]);
useEffect(() => {
if (fileInputRef.current) {
fileInputRef.current.setAttribute("webkitdirectory", "true");
fileInputRef.current.setAttribute("directory", "true");
}
}, []);
useEffect(() => {
if (!orderBySliceLocation) return;
@@ -1337,7 +1390,8 @@ function App() {
<div style={{
position: "relative",
width: "99vw",
height: "99vh",
height: "100%", // <-- changed from 500px
maxHeight: "100%", // <-- ensures it doesn't overflow parent
padding: "12px", // <-- Add this line
boxSizing: "border-box", // <-- Ensure padding doesn't shrink content
background: "#222",
@@ -1427,8 +1481,6 @@ function App() {
type="file"
style={{ display: "none" }}
multiple
webkitdirectory="true"
directory="true"
onChange={handleFilesSelected}
accept=".dcm,application/dicom"
/>