feat: react-grid尝试

This commit is contained in:
mozzie 2024-09-13 22:42:13 +08:00
parent 27f26a2af0
commit 0e7d05d9a4
6 changed files with 102 additions and 31 deletions

View File

@ -72,7 +72,9 @@
"@cornerstonejs/streaming-image-volume-loader": "1.84.4", "@cornerstonejs/streaming-image-volume-loader": "1.84.4",
"dicomweb-client": "0.10.4", "dicomweb-client": "0.10.4",
"@cornerstonejs/calculate-suv": "1.1.0", "@cornerstonejs/calculate-suv": "1.1.0",
"dcmjs": "0.34.1" "dcmjs": "0.34.1",
"react-grid-layout": "1.4.4",
"react-resizable": "3.0.5"
}, },
"devDependencies": { "devDependencies": {
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",

View File

@ -10,7 +10,7 @@ import {
export const menuItems: MenuItem[] = [ export const menuItems: MenuItem[] = [
{ to: "/", name: "自动分析", icon: <BrainCircuit /> }, { to: "/", name: "自动分析", icon: <BrainCircuit /> },
{ to: "/datasource", name: "数据列表", icon: <HardDrive /> }, { to: "/datasource", name: "数据列表", icon: <HardDrive /> },
{ to: "/viewer", name: "MPR阅片", icon: <Rotate3DIcon size={24} /> }, // { to: "/viewer", name: "MPR阅片", icon: <Rotate3DIcon size={24} /> },
{ to: "/models", name: "模型管理", icon: <Package /> }, { to: "/models", name: "模型管理", icon: <Package /> },
{ to: "/tools", name: "小工具", icon: <Wrench /> }, { to: "/tools", name: "小工具", icon: <Wrench /> },
// { to: "/setting", name: "设置", icon: <IoSettingsOutline size={24} /> }, // { to: "/setting", name: "设置", icon: <IoSettingsOutline size={24} /> },

View File

@ -15,11 +15,10 @@ export const SideBarLeft = () => {
{menuItems.map((item) => ( {menuItems.map((item) => (
<li <li
key={item.name} key={item.name}
className={`w-full flex flex-col items-center justify-center ${ className={`w-full flex flex-col items-center justify-center ${location.pathname === item.to
location.pathname === item.to ? "active text-primary bg-primary/10 rounded-r"
? "active text-primary bg-primary/10 rounded-r" : ""
: "" }`}
}`}
onClick={() => handleClick(item)} onClick={() => handleClick(item)}
> >
<Link <Link

View File

@ -1,4 +1,4 @@
import { useEffect, useRef } from "react"; import { useEffect, useRef, useState } from "react";
import * as cornerstoneTools from "@cornerstonejs/tools"; import * as cornerstoneTools from "@cornerstonejs/tools";
import { PublicViewportInput } from "@cornerstonejs/core/dist/types/types/IViewport.js"; import { PublicViewportInput } from "@cornerstonejs/core/dist/types/types/IViewport.js";
import { createImageIdsAndCacheMetaData } from "./CornerstoneDicomLoader/createImageIdsAndCacheMetaData"; import { createImageIdsAndCacheMetaData } from "./CornerstoneDicomLoader/createImageIdsAndCacheMetaData";
@ -20,6 +20,12 @@ import {
ViewportId, ViewportId,
} from "./Crosshair.config"; } from "./Crosshair.config";
import GridLayout from 'react-grid-layout';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
import { DraftingCompassIcon, MoveIcon } from "lucide-react";
import { Card } from "@/components/ui/card";
const { const {
ToolGroupManager, ToolGroupManager,
CrosshairsTool, CrosshairsTool,
@ -61,6 +67,7 @@ interface CrosshairMprProps {
} }
export const CrosshairMpr = (props: CrosshairMprProps) => { export const CrosshairMpr = (props: CrosshairMprProps) => {
const containerRef = useRef<HTMLDivElement | null>(null);
const viewportRef_AXIAL = useRef<HTMLDivElement | null>(null); const viewportRef_AXIAL = useRef<HTMLDivElement | null>(null);
const viewportRef_SAGITTAL = useRef<HTMLDivElement | null>(null); const viewportRef_SAGITTAL = useRef<HTMLDivElement | null>(null);
const viewportRef_CORONAL = useRef<HTMLDivElement | null>(null); const viewportRef_CORONAL = useRef<HTMLDivElement | null>(null);
@ -68,6 +75,7 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
const imageIds = useRef<string[]>(); const imageIds = useRef<string[]>();
const ts = "-" + Date.now(); const ts = "-" + Date.now();
useEffect(() => { useEffect(() => {
cornerstoneTools.addTool(StackScrollMouseWheelTool); cornerstoneTools.addTool(StackScrollMouseWheelTool);
cornerstoneTools.addTool(CrosshairsTool); cornerstoneTools.addTool(CrosshairsTool);
@ -219,7 +227,7 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
}, [props, ts]); }, [props, ts]);
useEffect(() => { useEffect(() => {
const resize = () => renderingEngine.current?.resize(); const resize = () => renderingEngine.current?.resize()
window.addEventListener("resize", resize); window.addEventListener("resize", resize);
return () => { return () => {
window.removeEventListener("resize", resize); window.removeEventListener("resize", resize);
@ -231,14 +239,16 @@ export const CrosshairMpr = (props: CrosshairMprProps) => {
}; };
return ( return (
<div className="h-full flex flex-col gap-y-2"> <div ref={containerRef} className="w-full h-full flex flex-col">
<div <Card className="rounded-none h-1/3">
onDoubleClick={() => onDBClickViewport(viewportRef_AXIAL)} <div className="w-full h-full" onDoubleClick={() => onDBClickViewport(viewportRef_AXIAL)} ref={viewportRef_AXIAL}></div>
className="h-1/3 border rounded-md" </Card>
ref={viewportRef_AXIAL} <Card className="rounded-none h-1/3">
></div> <div className="w-full h-full" ref={viewportRef_SAGITTAL}></div>
<div className="h-1/3 border rounded-md" ref={viewportRef_SAGITTAL}></div> </Card>
<div className="h-1/3 border rounded-md" ref={viewportRef_CORONAL}></div> <Card className="rounded-none h-1/3">
<div className="w-full h-full" ref={viewportRef_CORONAL}></div>
</Card>
</div> </div>
); );
}; };

View File

@ -3,6 +3,7 @@ import { initCornerstone } from "./MprViewer/CornerstoneDicomLoader/init";
import { CrosshairMpr } from "./MprViewer/Crosshair"; import { CrosshairMpr } from "./MprViewer/Crosshair";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
export interface CurrentDicom { export interface CurrentDicom {
SeriesInstanceUID: string | null; SeriesInstanceUID: string | null;
StudyInstanceUID: string | null; StudyInstanceUID: string | null;
@ -26,14 +27,16 @@ export const Viewer = () => {
}, [currentDicom]); }, [currentDicom]);
useEffect(() => { useEffect(() => {
console.log(window.location.href)
initCornerstone(() => { initCornerstone(() => {
setCornerstoneLoaded(true); setCornerstoneLoaded(true);
}); });
}, []); }, []);
useEffect(() => { useEffect(() => {
console.log(currentDicom, cornerstoneLoaded); console.log(cornerstoneLoaded);
}, [cornerstoneLoaded, currentDicom]); }, [cornerstoneLoaded]);
return ( return (
<div className="w-full h-full flex"> <div className="w-full h-full flex">
@ -46,10 +49,7 @@ export const Viewer = () => {
StudyInstanceUID={currentDicom.StudyInstanceUID} StudyInstanceUID={currentDicom.StudyInstanceUID}
SeriesInstanceUID={currentDicom.SeriesInstanceUID} SeriesInstanceUID={currentDicom.SeriesInstanceUID}
/> />
)} )}</div>
</div>
{Object.values(currentDicom).some((i) => !i) && "导入dicom"}
</div> </div>
); );
}; };

View File

@ -175,12 +175,18 @@ importers:
react-dropzone: react-dropzone:
specifier: 14.2.3 specifier: 14.2.3
version: 14.2.3(react@18.3.1) version: 14.2.3(react@18.3.1)
react-grid-layout:
specifier: 1.4.4
version: 1.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-hook-form: react-hook-form:
specifier: 7.53.0 specifier: 7.53.0
version: 7.53.0(react@18.3.1) version: 7.53.0(react@18.3.1)
react-icons: react-icons:
specifier: ^5.2.1 specifier: ^5.2.1
version: 5.3.0(react@18.3.1) version: 5.3.0(react@18.3.1)
react-resizable:
specifier: 3.0.5
version: 3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-resizable-panels: react-resizable-panels:
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -2740,6 +2746,10 @@ packages:
clone-response@1.0.3: clone-response@1.0.3:
resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==}
clsx@1.2.1:
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
engines: {node: '>=6'}
clsx@2.0.0: clsx@2.0.0:
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -3255,6 +3265,9 @@ packages:
fast-deep-equal@3.1.3: fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
fast-equals@4.0.3:
resolution: {integrity: sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==}
fast-fifo@1.3.2: fast-fifo@1.3.2:
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
@ -4632,12 +4645,24 @@ packages:
peerDependencies: peerDependencies:
react: ^18.3.1 react: ^18.3.1
react-draggable@4.4.6:
resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==}
peerDependencies:
react: '>= 16.3.0'
react-dom: '>= 16.3.0'
react-dropzone@14.2.3: react-dropzone@14.2.3:
resolution: {integrity: sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==} resolution: {integrity: sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==}
engines: {node: '>= 10.13'} engines: {node: '>= 10.13'}
peerDependencies: peerDependencies:
react: '>= 16.8 || 18.0.0' react: '>= 16.8 || 18.0.0'
react-grid-layout@1.4.4:
resolution: {integrity: sha512-7+Lg8E8O8HfOH5FrY80GCIR1SHTn2QnAYKh27/5spoz+OHhMmEhU/14gIkRzJOtympDPaXcVRX/nT1FjmeOUmQ==}
peerDependencies:
react: '>= 16.3.0'
react-dom: '>= 16.3.0'
react-hook-form@7.53.0: react-hook-form@7.53.0:
resolution: {integrity: sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==} resolution: {integrity: sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
@ -4695,6 +4720,11 @@ packages:
react: ^16.14.0 || ^17.0.0 || ^18.0.0 react: ^16.14.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
react-resizable@3.0.5:
resolution: {integrity: sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==}
peerDependencies:
react: '>= 16.3'
react-router-dom@6.26.1: react-router-dom@6.26.1:
resolution: {integrity: sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==} resolution: {integrity: sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -7958,7 +7988,7 @@ snapshots:
app-builder-bin@4.0.0: {} app-builder-bin@4.0.0: {}
app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): app-builder-lib@24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
dependencies: dependencies:
'@develar/schema-utils': 2.6.5 '@develar/schema-utils': 2.6.5
'@electron/notarize': 2.2.1 '@electron/notarize': 2.2.1
@ -7972,7 +8002,7 @@ snapshots:
builder-util-runtime: 9.2.4 builder-util-runtime: 9.2.4
chromium-pickle-js: 0.2.0 chromium-pickle-js: 0.2.0
debug: 4.3.6 debug: 4.3.6
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
ejs: 3.1.10 ejs: 3.1.10
electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3) electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3)
electron-publish: 24.13.1 electron-publish: 24.13.1
@ -8406,6 +8436,8 @@ snapshots:
dependencies: dependencies:
mimic-response: 1.0.1 mimic-response: 1.0.1
clsx@1.2.1: {}
clsx@2.0.0: {} clsx@2.0.0: {}
clsx@2.1.1: {} clsx@2.1.1: {}
@ -8686,9 +8718,9 @@ snapshots:
dlv@1.1.3: {} dlv@1.1.3: {}
dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3):
dependencies: dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
builder-util: 24.13.1 builder-util: 24.13.1
builder-util-runtime: 9.2.4 builder-util-runtime: 9.2.4
fs-extra: 10.1.0 fs-extra: 10.1.0
@ -8758,7 +8790,7 @@ snapshots:
electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3): electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3):
dependencies: dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
archiver: 5.3.2 archiver: 5.3.2
builder-util: 24.13.1 builder-util: 24.13.1
fs-extra: 10.1.0 fs-extra: 10.1.0
@ -8768,11 +8800,11 @@ snapshots:
electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)): electron-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)):
dependencies: dependencies:
app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) app-builder-lib: 24.13.3(dmg-builder@24.13.3(electron-builder-squirrel-windows@24.13.3))(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
builder-util: 24.13.1 builder-util: 24.13.1
builder-util-runtime: 9.2.4 builder-util-runtime: 9.2.4
chalk: 4.1.2 chalk: 4.1.2
dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3)) dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3)
fs-extra: 10.1.0 fs-extra: 10.1.0
is-ci: 3.0.1 is-ci: 3.0.1
lazy-val: 1.0.5 lazy-val: 1.0.5
@ -9019,6 +9051,8 @@ snapshots:
fast-deep-equal@3.1.3: {} fast-deep-equal@3.1.3: {}
fast-equals@4.0.3: {}
fast-fifo@1.3.2: {} fast-fifo@1.3.2: {}
fast-glob@3.3.2: fast-glob@3.3.2:
@ -10534,6 +10568,13 @@ snapshots:
react: 18.3.1 react: 18.3.1
scheduler: 0.23.2 scheduler: 0.23.2
react-draggable@4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
clsx: 1.2.1
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-dropzone@14.2.3(react@18.3.1): react-dropzone@14.2.3(react@18.3.1):
dependencies: dependencies:
attr-accept: 2.2.2 attr-accept: 2.2.2
@ -10541,6 +10582,17 @@ snapshots:
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
react-grid-layout@1.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
clsx: 2.1.1
fast-equals: 4.0.3
prop-types: 15.8.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-draggable: 4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-resizable: 3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
resize-observer-polyfill: 1.5.1
react-hook-form@7.53.0(react@18.3.1): react-hook-form@7.53.0(react@18.3.1):
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@ -10590,6 +10642,14 @@ snapshots:
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
react-resizable@3.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
prop-types: 15.8.1
react: 18.3.1
react-draggable: 4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
transitivePeerDependencies:
- react-dom
react-router-dom@6.26.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): react-router-dom@6.26.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@remix-run/router': 1.19.1 '@remix-run/router': 1.19.1