|
|
@@ -1181,7 +1181,272 @@ class DicomOverlayTool {
|
|
|
|
|
|
---
|
|
|
|
|
|
-**文档版本**: 1.0.0
|
|
|
+---
|
|
|
+
|
|
|
+## 🏊 13. 启用/停用工具流程图(泳道图)
|
|
|
+
|
|
|
+### 13.1 启用流程
|
|
|
+
|
|
|
+```mermaid
|
|
|
+sequenceDiagram
|
|
|
+ participant User as 👤 用户
|
|
|
+ participant MP as MorePanel
|
|
|
+ participant Redux as Redux Store
|
|
|
+ participant SV as StackViewer
|
|
|
+ participant TG as ToolGroup
|
|
|
+ participant Tool as DicomOverlayTool
|
|
|
+ participant CM as ConfigManager
|
|
|
+ participant CS as Cornerstone3D
|
|
|
+
|
|
|
+ User->>MP: 点击"tag信息"按钮
|
|
|
+ Note over MP: handleTagInfo()
|
|
|
+ MP->>Redux: dispatch(toggleOverlay())
|
|
|
+ Note over Redux: enabled: false → true
|
|
|
+
|
|
|
+ Redux-->>SV: 状态变化通知
|
|
|
+ Note over SV: useEffect监听overlayEnabled
|
|
|
+
|
|
|
+ SV->>TG: getToolGroup(viewportId)
|
|
|
+ TG-->>SV: 返回toolGroup实例
|
|
|
+
|
|
|
+ SV->>TG: setToolEnabled(DicomOverlayTool.toolName)
|
|
|
+ Note over TG: 工具状态: Passive → Enabled
|
|
|
+
|
|
|
+ TG->>Tool: onSetToolEnabled()
|
|
|
+ Note over Tool: 工具被激活
|
|
|
+
|
|
|
+ Tool->>CM: getConfig()
|
|
|
+ Note over CM: 尝试加载配置
|
|
|
+
|
|
|
+ alt 远程配置可用
|
|
|
+ CM->>CM: RemoteAdapter.fetch()
|
|
|
+ CM-->>Tool: 返回远程配置
|
|
|
+ else 远程配置失败
|
|
|
+ CM->>CM: LocalAdapter.getConfig()
|
|
|
+ CM-->>Tool: 返回本地配置
|
|
|
+ end
|
|
|
+
|
|
|
+ Note over Tool: 配置加载完成
|
|
|
+ Tool->>CS: 触发viewport.render()
|
|
|
+
|
|
|
+ CS->>Tool: renderAnnotation(enabledElement, svgHelper)
|
|
|
+ Note over Tool: Cornerstone自动调用渲染
|
|
|
+
|
|
|
+ Tool->>Tool: extractMetadata(imageId)
|
|
|
+ Tool->>Tool: prepareTextLines()
|
|
|
+ Tool->>Tool: renderToSVG()
|
|
|
+
|
|
|
+ Tool->>CS: 创建SVG文本元素
|
|
|
+ Note over CS: SVG layer
|
|
|
+ CS-->>User: 显示四角信息 ✅
|
|
|
+```
|
|
|
+
|
|
|
+### 13.2 停用流程
|
|
|
+
|
|
|
+```mermaid
|
|
|
+sequenceDiagram
|
|
|
+ participant User as 👤 用户
|
|
|
+ participant MP as MorePanel
|
|
|
+ participant Redux as Redux Store
|
|
|
+ participant SV as StackViewer
|
|
|
+ participant TG as ToolGroup
|
|
|
+ participant Tool as DicomOverlayTool
|
|
|
+ participant CS as Cornerstone3D
|
|
|
+
|
|
|
+ User->>MP: 再次点击"tag信息"按钮
|
|
|
+ Note over MP: handleTagInfo()
|
|
|
+ MP->>Redux: dispatch(toggleOverlay())
|
|
|
+ Note over Redux: enabled: true → false
|
|
|
+
|
|
|
+ Redux-->>SV: 状态变化通知
|
|
|
+ Note over SV: useEffect监听overlayEnabled
|
|
|
+
|
|
|
+ SV->>TG: getToolGroup(viewportId)
|
|
|
+ TG-->>SV: 返回toolGroup实例
|
|
|
+
|
|
|
+ SV->>TG: setToolDisabled(DicomOverlayTool.toolName)
|
|
|
+ Note over TG: 工具状态: Enabled → Disabled
|
|
|
+
|
|
|
+ TG->>Tool: onSetToolDisabled()
|
|
|
+ Note over Tool: 工具被停用
|
|
|
+
|
|
|
+ Tool->>CS: 触发viewport.render()
|
|
|
+ Note over CS: 重新渲染viewport
|
|
|
+
|
|
|
+ CS->>Tool: renderAnnotation(enabledElement, svgHelper)
|
|
|
+ Note over Tool: 由于工具disabled,<br/>Cornerstone不再调用渲染
|
|
|
+
|
|
|
+ Note over CS: SVG元素被清除
|
|
|
+ CS-->>User: 四角信息消失 ✅
|
|
|
+```
|
|
|
+
|
|
|
+### 13.3 参与者说明
|
|
|
+
|
|
|
+#### 🎨 UI层
|
|
|
+1. **User (用户)**
|
|
|
+ - 角色: 触发操作的人
|
|
|
+ - 操作: 点击"tag信息"按钮
|
|
|
+
|
|
|
+2. **MorePanel** (`src/pages/view/components/MorePanel.tsx`)
|
|
|
+ - 角色: UI控制面板
|
|
|
+ - 关键方法:
|
|
|
+ - `handleTagInfo()`: 处理按钮点击
|
|
|
+ - 职责: 触发Redux action
|
|
|
+
|
|
|
+#### 📦 状态管理层
|
|
|
+3. **Redux Store** (`src/states/view/dicomOverlaySlice.ts`)
|
|
|
+ - 角色: 全局状态管理
|
|
|
+ - 关键状态:
|
|
|
+ - `enabled: boolean`: overlay开关状态
|
|
|
+ - 关键Action:
|
|
|
+ - `toggleOverlay()`: 切换enabled状态
|
|
|
+ - 职责: 存储和通知状态变化
|
|
|
+
|
|
|
+#### 🖼️ 视图层
|
|
|
+4. **StackViewer** (`src/pages/view/components/viewers/stack.image.viewer.tsx`)
|
|
|
+ - 角色: 图像查看器组件
|
|
|
+ - 关键Hook:
|
|
|
+ - `useSelector(selectOverlayEnabled)`: 监听状态
|
|
|
+ - `useEffect([overlayEnabled])`: 响应状态变化
|
|
|
+ - 关键逻辑:
|
|
|
+ ```typescript
|
|
|
+ useEffect(() => {
|
|
|
+ const toolGroup = ToolGroupManager.getToolGroup(`STACK_TOOL_GROUP_ID_${viewportId}`);
|
|
|
+ if (overlayEnabled) {
|
|
|
+ toolGroup.setToolEnabled(DicomOverlayTool.toolName);
|
|
|
+ } else {
|
|
|
+ toolGroup.setToolDisabled(DicomOverlayTool.toolName);
|
|
|
+ }
|
|
|
+ }, [overlayEnabled, viewportId]);
|
|
|
+ ```
|
|
|
+ - 职责: 连接Redux状态和Cornerstone工具
|
|
|
+
|
|
|
+#### 🛠️ 工具管理层
|
|
|
+5. **ToolGroup** (Cornerstone3D提供)
|
|
|
+ - 角色: 工具集合管理器
|
|
|
+ - 关键方法:
|
|
|
+ - `setToolEnabled(toolName)`: 启用工具
|
|
|
+ - `setToolDisabled(toolName)`: 停用工具
|
|
|
+ - 职责: 管理工具生命周期,触发工具回调
|
|
|
+
|
|
|
+#### 🎯 核心工具层
|
|
|
+6. **DicomOverlayTool** (`src/components/overlay/DicomOverlayTool.ts`)
|
|
|
+ - 角色: DICOM信息显示工具(继承AnnotationTool)
|
|
|
+ - 关键生命周期方法:
|
|
|
+ - `onSetToolEnabled()`: 工具启用回调
|
|
|
+ ```typescript
|
|
|
+ onSetToolEnabled(): void {
|
|
|
+ console.log('[DicomOverlayTool] Tool enabled');
|
|
|
+ this.loadConfig(); // 异步加载配置
|
|
|
+ }
|
|
|
+ ```
|
|
|
+ - `onSetToolDisabled()`: 工具停用回调
|
|
|
+ ```typescript
|
|
|
+ onSetToolDisabled(): void {
|
|
|
+ console.log('[DicomOverlayTool] Tool disabled');
|
|
|
+ // Cornerstone会自动停止调用renderAnnotation
|
|
|
+ }
|
|
|
+ ```
|
|
|
+ - `renderAnnotation(enabledElement, svgHelper)`: 渲染回调
|
|
|
+ ```typescript
|
|
|
+ renderAnnotation(enabledElement, svgHelper): boolean {
|
|
|
+ if (!this.config) return false;
|
|
|
+ // 提取metadata
|
|
|
+ const metadata = this.extractMetadata(imageId);
|
|
|
+ // 渲染到SVG
|
|
|
+ this.renderer.renderToSVG(svgHelper, viewport, metadata, ...);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ ```
|
|
|
+ - 职责: 管理配置、提取数据、触发渲染
|
|
|
+
|
|
|
+#### ⚙️ 配置管理层
|
|
|
+7. **ConfigManager** (`src/config/overlayConfig/OverlayConfigManager.ts`)
|
|
|
+ - 角色: 配置提供者
|
|
|
+ - 关键方法:
|
|
|
+ - `getConfig()`: 获取配置
|
|
|
+ ```typescript
|
|
|
+ async getConfig(): Promise<OverlayConfig> {
|
|
|
+ // 优先远程,失败降级本地
|
|
|
+ try {
|
|
|
+ return await this.remoteAdapter.getOverlayConfig();
|
|
|
+ } catch {
|
|
|
+ return await this.localAdapter.getOverlayConfig();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ```
|
|
|
+ - 职责: 统一配置访问,处理降级
|
|
|
+
|
|
|
+#### 🎨 渲染引擎层
|
|
|
+8. **Cornerstone3D**
|
|
|
+ - 角色: 医学图像渲染引擎
|
|
|
+ - 关键职责:
|
|
|
+ - 在渲染循环中自动调用`renderAnnotation()`
|
|
|
+ - 管理SVG图层
|
|
|
+ - 响应工具状态变化
|
|
|
+ - 工作机制:
|
|
|
+ - 工具Enabled时: 渲染循环包含该工具
|
|
|
+ - 工具Disabled时: 渲染循环跳过该工具
|
|
|
+
|
|
|
+### 13.4 关键流程说明
|
|
|
+
|
|
|
+#### 启用时的关键步骤
|
|
|
+
|
|
|
+1. **状态更新** (MorePanel → Redux)
|
|
|
+ - 用户点击触发`toggleOverlay()`
|
|
|
+ - Redux将`enabled`从`false`改为`true`
|
|
|
+
|
|
|
+2. **状态监听** (Redux → StackViewer)
|
|
|
+ - `useSelector`检测到状态变化
|
|
|
+ - `useEffect`被触发
|
|
|
+
|
|
|
+3. **工具激活** (StackViewer → ToolGroup)
|
|
|
+ - 调用`toolGroup.setToolEnabled()`
|
|
|
+ - ToolGroup触发工具的`onSetToolEnabled()`
|
|
|
+
|
|
|
+4. **配置加载** (Tool → ConfigManager)
|
|
|
+ - 异步加载配置
|
|
|
+ - 加载完成后触发`viewport.render()`
|
|
|
+
|
|
|
+5. **自动渲染** (Cornerstone → Tool)
|
|
|
+ - Cornerstone在渲染循环中调用`renderAnnotation()`
|
|
|
+ - 工具创建SVG元素显示信息
|
|
|
+
|
|
|
+#### 停用时的关键步骤
|
|
|
+
|
|
|
+1. **状态更新** (MorePanel → Redux)
|
|
|
+ - 用户再次点击触发`toggleOverlay()`
|
|
|
+ - Redux将`enabled`从`true`改为`false`
|
|
|
+
|
|
|
+2. **状态监听** (Redux → StackViewer)
|
|
|
+ - `useSelector`检测到状态变化
|
|
|
+ - `useEffect`被触发
|
|
|
+
|
|
|
+3. **工具停用** (StackViewer → ToolGroup)
|
|
|
+ - 调用`toolGroup.setToolDisabled()`
|
|
|
+ - ToolGroup触发工具的`onSetToolDisabled()`
|
|
|
+
|
|
|
+4. **停止渲染** (Cornerstone自动处理)
|
|
|
+ - Cornerstone不再调用该工具的`renderAnnotation()`
|
|
|
+ - SVG元素被清除
|
|
|
+ - 四角信息消失
|
|
|
+
|
|
|
+### 13.5 核心优势
|
|
|
+
|
|
|
+✅ **自动化渲染**: Cornerstone3D自动管理渲染循环,工具无需手动监听事件
|
|
|
+
|
|
|
+✅ **声明式状态**: 使用Redux管理状态,React自动响应变化
|
|
|
+
|
|
|
+✅ **清晰的职责分离**:
|
|
|
+- UI层只负责触发action
|
|
|
+- 工具层只负责渲染逻辑
|
|
|
+- Cornerstone负责渲染调度
|
|
|
+
|
|
|
+✅ **SVG渲染**: 不会被Canvas覆盖,永久显示
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+**文档版本**: 1.1.0
|
|
|
**创建日期**: 2025-01-25
|
|
|
**最后更新**: 2025-01-25
|
|
|
**作者**: Cline (AI Assistant)
|