further improvements
This commit is contained in:
+15
-1
@@ -7,7 +7,21 @@
|
|||||||
<title>Vite + React + TS</title>
|
<title>Vite + React + TS</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+62
-10
@@ -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 { LengthTool, ProbeTool, ArrowAnnotateTool, RectangleROITool, EllipticalROITool, PlanarFreehandROITool, PlanarFreehandContourSegmentationTool, SculptorTool, CrosshairsTool, ReferenceLinesTool, ReferenceCursors } 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 { segmentation, Enums as csEnums } from '@cornerstonejs/tools';
|
import { segmentation, Enums as csEnums } from '@cornerstonejs/tools';
|
||||||
import { voi } from "@cornerstonejs/tools/utilities"
|
import { voi } from "@cornerstonejs/tools/utilities"
|
||||||
import { readDicomElementExplicit } from "dicom-parser"
|
import { readDicomElementExplicit } from "dicom-parser"
|
||||||
@@ -18,6 +17,20 @@ import { metaData } from '@cornerstonejs/core';
|
|||||||
import * as dicomParser from "dicom-parser";
|
import * as dicomParser from "dicom-parser";
|
||||||
import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader"
|
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;
|
window.cornerstoneTools = cornerstoneTools;
|
||||||
|
|
||||||
@@ -203,7 +216,10 @@ function App() {
|
|||||||
if (url.startsWith("blob:") || url.startsWith("/")) {
|
if (url.startsWith("blob:") || url.startsWith("/")) {
|
||||||
if (cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager) {
|
if (cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager) {
|
||||||
// If load returns a promise, collect it
|
// 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") {
|
if (result && typeof result.then === "function") {
|
||||||
loadPromises.push(result);
|
loadPromises.push(result);
|
||||||
}
|
}
|
||||||
@@ -367,6 +383,21 @@ function App() {
|
|||||||
setMetaModalOpen(true);
|
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);
|
const [altPressed, setAltPressed] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -472,23 +503,38 @@ function App() {
|
|||||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
// Handler for file input change
|
// Handler for file input change
|
||||||
const handleFilesSelected = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFilesSelected = async (event: React.ChangeEvent<HTMLInputElement> | { target: { files: File[] | FileList } }) => {
|
||||||
const files = event.target.files;
|
const files = event.target.files;
|
||||||
if (!files || files.length === 0) return;
|
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)
|
// Convert FileList to Array and sort by name (optional)
|
||||||
const fileArray = Array.from(files).sort((a, b) => a.name.localeCompare(b.name));
|
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
|
// Create imageIds for each file
|
||||||
// (Assumes cornerstone-wado-image-loader is configured for file loading)
|
|
||||||
const imageIds = fileArray.map(
|
const imageIds = fileArray.map(
|
||||||
file => `wadouri:${URL.createObjectURL(file)}`
|
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);
|
setLoadedImageIdsAndCacheMeta(imageIds);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -862,6 +908,13 @@ function App() {
|
|||||||
updateActiveReferenceLineViewport(mainToolGroup)
|
updateActiveReferenceLineViewport(mainToolGroup)
|
||||||
}, [activeViewport, referenceLinesEnabled]);
|
}, [activeViewport, referenceLinesEnabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (fileInputRef.current) {
|
||||||
|
fileInputRef.current.setAttribute("webkitdirectory", "true");
|
||||||
|
fileInputRef.current.setAttribute("directory", "true");
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!orderBySliceLocation) return;
|
if (!orderBySliceLocation) return;
|
||||||
|
|
||||||
@@ -1337,7 +1390,8 @@ function App() {
|
|||||||
<div style={{
|
<div style={{
|
||||||
position: "relative",
|
position: "relative",
|
||||||
width: "99vw",
|
width: "99vw",
|
||||||
height: "99vh",
|
height: "100%", // <-- changed from 500px
|
||||||
|
maxHeight: "100%", // <-- ensures it doesn't overflow parent
|
||||||
padding: "12px", // <-- Add this line
|
padding: "12px", // <-- Add this line
|
||||||
boxSizing: "border-box", // <-- Ensure padding doesn't shrink content
|
boxSizing: "border-box", // <-- Ensure padding doesn't shrink content
|
||||||
background: "#222",
|
background: "#222",
|
||||||
@@ -1427,8 +1481,6 @@ function App() {
|
|||||||
type="file"
|
type="file"
|
||||||
style={{ display: "none" }}
|
style={{ display: "none" }}
|
||||||
multiple
|
multiple
|
||||||
webkitdirectory="true"
|
|
||||||
directory="true"
|
|
||||||
onChange={handleFilesSelected}
|
onChange={handleFilesSelected}
|
||||||
accept=".dcm,application/dicom"
|
accept=".dcm,application/dicom"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user