reactjs - 如何在 React 应用中集成 cornerstone3d 示例
我正在尝试在一个 React 应用中实现 https://www.cornerstonejs.org/docs/examples#run-examples-locally 中的示例,但我不确定该做什么。
我做了什么:
- npx create-react-app my-app --template typescript
- npm 安装
- npm 安装 @cornerstonejs/core @cornerstonejs/tools @cornerstonejs/streaming-image-volume-loader
- 将 corerstone3d.beta 文件夹中的 util 和 packages 移动到项目的 src 文件夹中
- 通过本页底部的代码导入了库
- 将一些 HTML 复制到 App() { return (.......); }
- 从这里复制了一些代码:"https://www.cornerstonejs.org/live-examples/stackbasic"(在控制台查看源代码)到 App.tsx
- 通过导入缺失的库修复了一些错误
然而,我从 util 和 packages 文件夹中的函数收到了数千个错误,这些函数是我从 cornerstone3d 拿来的,如下图所示:
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { RenderingEngine, Types, Enums } from '@cornerstonejs/core';
import {
initDemo,
createImageIdsAndCacheMetaData,
setTitleAndDescription,
ctVoiRange,
} from './utils/demo/helpers';
function App() {
const { ViewportType } = Enums;
// ======== Set up page ======== //
setTitleAndDescription(
'Basic Stack',
'Displays a single DICOM image in a Stack viewport.'
);
const content = document.getElementById('content');
const element = document.createElement('div');
element.id = 'cornerstone-element';
element.style.width = '500px';
element.style.height = '500px';
// ============================= //
return (
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta
name="viewport"
content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<script defer src="stackBasic.js"></script></head>
<body>
Style the title and description components so they are the same in every demo
<div id="demo-title-container">
<h1 id="demo-title">
Insert demo title here during demo
</h1>
</div>
<div id="demo-description-container">
<p id="demo-description">
Insert demo title here during demo
</p>
</div>
<div id="demo-toolbar">
Insert buttons/dropdowns/etc here during demo
</div>
<div id="content"></div>
</body>
</html>
);
}
export default App;
(代码缺少一些部分,因为我正在尝试先修复导入)
如果在其他框架上存在任何解决方案,我也想看看它们
答案#1
如果你仍在寻找这个答案,这里是我应用的实现方法。
import React, { useEffect, useRef, useState } from "react"
import {
RenderingEngine,
Types,
Enums,
cache,
eventTarget,
getRenderingEngine,
} from "@cornerstonejs/core"
import * as cornerstoneTools from "@cornerstonejs/tools"
import createImageIdsAndCacheMetaData from "./helper/createImageIdsAndCacheMetaData"
import s from "./Cornerstone.module.scss"
import { Instance } from "../types"
import { useDispatch } from "../context"
import { wadoURL } from "./constants"
import { isSingleImageAndStack } from "../../../utils"
import "./initialization"
const {
StackScrollMouseWheelTool,
WindowLevelTool,
ZoomTool,
ToolGroupManager,
Enums: csToolsEnums,
} = cornerstoneTools
const { ViewportType, Events } = Enums
const { MouseBindings, KeyboardBindings } = csToolsEnums
cornerstoneTools.addTool(StackScrollMouseWheelTool)
cornerstoneTools.addTool(WindowLevelTool)
cornerstoneTools.addTool(ZoomTool)
const toolGroup = ToolGroupManager.createToolGroup("toolGroupId")
toolGroup?.addTool(StackScrollMouseWheelTool.toolName)
toolGroup?.addTool(WindowLevelTool.toolName)
toolGroup?.addTool(ZoomTool.toolName)
toolGroup?.setToolActive(StackScrollMouseWheelTool.toolName)
toolGroup?.setToolActive(WindowLevelTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Left Click
},
],
})
toolGroup?.setToolActive(ZoomTool.toolName, {
bindings: [
{
mouseButton: MouseBindings.Primary, // Ctrl + Left Click
modifierKey: KeyboardBindings.Ctrl,
},
],
})
interface Instance {
contentType: "dicom"
studyId: string
seriesId: string
instanceId: string
frames: number
modality: string
}
interface OwnProps {
instance: Instance
}
const renderingEngineId = "myRenderingEngine"
let renderingEngine: Types.IRenderingEngine | undefined
const Cornerstone = ({ instance }: OwnProps) => {
const [loading, setLoading] = useState(true)
const imageIdsCount = useRef<number | null>(null)
const imageIdsLoaded = useRef<number | null>(null)
const prevPropsRef = useRef<Instance | null>(null)
const viewportRef = useRef<HTMLDivElement | null>(null)
const { state } = useDispatch()
const isSingleImage = isSingleImageAndStack(instance)
useEffect(() => {
window.addEventListener("resize", handleResize)
return () => {
// renderingEngine?.destroy()
window.removeEventListener("resize", handleResize)
}
}, [])
useEffect(() => {
if (renderingEngine) {
renderingEngine?.resize(true, false)
}
}, [state.layout])
useEffect(() => {
// Compare the new props with the old props
if (instance !== prevPropsRef.current) {
const viewportInput: Types.PublicViewportInput = {
viewportId: instance.instanceId,
type: ViewportType.STACK,
element: viewportRef.current as HTMLDivElement,
defaultOptions: {
background: [0, 0, 0],
},
}
renderingEngine = getRenderingEngine(renderingEngineId)
if (!renderingEngine || renderingEngine.hasBeenDestroyed) {
// Instantiate a rendering engine
renderingEngine = new RenderingEngine(renderingEngineId)
}
if (prevPropsRef.current)
renderingEngine.disableElement(prevPropsRef.current.instanceId)
renderingEngine.enableElement(viewportInput)
const baseImageURI = `${isSingleImage ? "web" : "wadors"}:${wadoURL}/studies/${instance.studyId}/series/${instance.seriesId}/instances/${instance.instanceId}/frames/1`;
const imageURIs = [
`${baseImageURI}/rendered`,
baseImageURI
];
let isLoaded;
for (const imageURI of imageURIs) {
const cachedImage = cache.getCachedImageBasedOnImageURI(imageURI);
if (cachedImage !== undefined) {
isLoaded = cachedImage.loaded;
break; // Exit the loop if a valid loaded value is found
}
}
if (!isLoaded) setLoading(true)
else setLoading(false)
render()
}
imageIdsLoaded.current = 0
// Update the previous props ref
prevPropsRef.current = instance
// eslint-disable-next-line
}, [instance])
eventTarget?.addEventListener(Events.IMAGE_LOADED, (e: unknown) => {
imageIdsLoaded.current = (imageIdsLoaded?.current || 0) + 1
if (
imageIdsCount.current !== null &&
imageIdsLoaded.current >= imageIdsCount.current
)
setLoading(false)
})
const handleResize = () => {
if (renderingEngine) {
renderingEngine?.resize(true, false)
}
}
const render = async () => {
try {
const viewportId = instance.instanceId
let imageIds = [
`web:${wadoURL}/studies/${instance.studyId}/series/${instance.seriesId}/instances/${viewportId}/frames/1/rendered`,
]
// Get Cornerstone imageIds and fetch metadata into RAM
imageIds = await createImageIdsAndCacheMetaData({
StudyInstanceUID: instance.studyId,
SeriesInstanceUID: instance.seriesId,
SOPInstanceUID: isSingleImage ? viewportId : null,
wadoRsRoot: wadoURL,
isSingleImage,
})
imageIdsCount.current = imageIds.length
toolGroup?.addViewport(viewportId, renderingEngineId)
// get renderingEngine from cache if it exists
renderingEngine = getRenderingEngine(renderingEngineId)
let viewport = renderingEngine?.getViewport(viewportId) as
| Types.IVolumeViewport
| Types.IStackViewport
const stackViewport = viewport as Types.IStackViewport
if (!isSingleImage) {
imageIds.forEach((imageId, index) => {
stackViewport.setStack(imageIds, index)
})
}
stackViewport.setStack(imageIds)
viewport = stackViewport
// Render the image
// viewport?.render()
renderingEngine?.renderViewports([viewportId])
} catch (err) {
console.log(err)
}
}
return (
<div ref={viewportRef} style={{ width: "100%", height: "100%" }}>
{loading ? <p className={s.loading}>Loading...</p> : null}
</div>
)
}
export default Cornerstone<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>答案#2
你需要再次在 cornerstone3d 下载 cornerstone3d,然后使用 npm install 安装所有节点包
